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.Logger;
import org.mxchange.addressbook.application.Application;
import org.mxchange.addressbook.client.Client;
-import org.mxchange.addressbook.database.frontend.DatabaseWrapper;
+import org.mxchange.addressbook.database.frontend.DatabaseFrontend;
import org.mxchange.addressbook.manager.contact.ManageableContact;
/**
* @author Roland Haeder
*/
public class BaseFrameworkSystem implements FrameworkInterface {
+
/**
* Instance for own properties
*/
*/
private ManageableContact contactManager;
-
/**
* Name of used database table, handled over to backend
*/
private String tableName;
/**
- * DatabaseWrapper instance
+ * DatabaseFrontend instance
*/
- private DatabaseWrapper wrapper;
+ private DatabaseFrontend wrapper;
/**
* Initialize object
}
/**
- * Some "getter" for a Method instance from given method name
+ * Some "getter" for target class instance from given name.
*
- * @param instance Actual instance to call
- * @param targetClass Target class name
- * @param methodName Method name
- * @return A Method instance
+ * @param instance Instance to iterate on
+ * @param targetClass Class name to look for
+ * @return Class instance
*/
@SuppressWarnings ("unchecked")
- 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));
+ private Class<? extends FrameworkInterface> getClassFromTarget (final FrameworkInterface instance, final String targetClass) {
+ // Trace message
+ this.getLogger().debug(MessageFormat.format("instance={0},targetClass={1}", instance, targetClass));
// Instance reflaction of this class
Class<? extends FrameworkInterface> c = instance.getClass();
-
+
// Analyze class
while (!targetClass.equals(c.getSimpleName())) {
// Debug message
c = (Class<? extends FrameworkInterface>) c.getSuperclass();
}
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("c={0} - EXIT!", c));
+
+ // 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));
+
+ // Get target class instance
+ Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
+
// Init field instance
Method method = null;
}
// Assert on field
- assert(method instanceof Method) : "method is not a Method instance";
+ assert (method instanceof Method) : "method is not a Method instance";
// Trace message
this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method));
// .. and exit
System.exit(1);
-
+
}
/**
// Increment counter
count++;
}
-
+
// Trace message
this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder));
// Trace message
this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName));
- // First all lower case
- String lower = columnName.toLowerCase();
-
// Then split on "_"
- StringTokenizer tokenizer = new StringTokenizer(lower, "_");
+ StringTokenizer tokenizer = new StringTokenizer(columnName, "_");
// Resulting string
StringBuilder builder = new StringBuilder(tokenizer.countTokens());
// Add token
builder.append(token);
}
-
+
// Trace message
this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder));
// Return value
return object;
}
-
+
/**
* Getter for logger
*
}
/**
- * Getter for DatabaseWrapper instance
+ * Getter for DatabaseFrontend instance
*
- * @return DatabaseWrapper instance
+ * @return DatabaseFrontend instance
*/
- protected DatabaseWrapper getWrapper () {
+ protected DatabaseFrontend getWrapper () {
return this.wrapper;
}
/**
* Setter for wrapper instance
*
- * @param wrapper A DatabaseWrapper instance
+ * @param wrapper A DatabaseFrontend instance
*/
- protected void setWrapper (final DatabaseWrapper wrapper) {
+ protected void setWrapper (final DatabaseFrontend wrapper) {
this.wrapper = wrapper;
}
+
+ /**
+ * 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));
+
+ // 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]));
+
+ // Increment index
+ index++;
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("tokens({0})={1} - EXIT!", tokens.length, Arrays.toString(tokens)));
+
+ // Return it
+ return tokens;
+ }
+
+ /**
+ * 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));
+
+ // 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));
+
+ // Not found
+ isBool = false;
+ } catch (final SecurityException ex) {
+ // Really bad?
+ this.abortProgramWithException(ex);
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("isBool={0} - EXIT!", isBool));
+
+ // Return result
+ return isBool;
+ }
}
// Trace message
this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName));
+ // Determine if the given column is boolean
+ if (this.isBooleanField(this, "BaseContact", columnName)) {
+ // Yes, then call other method
+ return this.getBooleanField(this, "BaseContact", columnName);
+ }
+
// Convert column name to field name
- String methodName = this.convertColumnNameToGetterMethod(columnName, true);
+ String methodName = this.convertColumnNameToGetterMethod(columnName, false);
// Debug message
this.getLogger().debug(MessageFormat.format("field={0}", methodName));
*/
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
*
*
* @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);
+ public Storeable readRow (final int rowIndex) throws BadTokenException;
}
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
-import java.util.StringTokenizer;
import org.mxchange.addressbook.FrameworkInterface;
import org.mxchange.addressbook.contact.Contact;
-import org.mxchange.addressbook.contact.Gender;
-import org.mxchange.addressbook.contact.book.BookContact;
-import org.mxchange.addressbook.contact.user.UserContact;
import org.mxchange.addressbook.database.backend.BaseDatabaseBackend;
import org.mxchange.addressbook.database.backend.DatabaseBackend;
-import org.mxchange.addressbook.database.frontend.DatabaseWrapper;
+import org.mxchange.addressbook.database.frontend.DatabaseFrontend;
import org.mxchange.addressbook.database.storage.Storeable;
import org.mxchange.addressbook.database.storage.csv.StoreableCsv;
import org.mxchange.addressbook.exceptions.BadTokenException;
* @param tableName Name of "table"
* @param wrapper Wrapper instance to call back
*/
- public Base64CsvDatabaseBackend (final String tableName, final DatabaseWrapper wrapper) {
+ public Base64CsvDatabaseBackend (final String tableName, final DatabaseFrontend wrapper) {
// Trace message
this.getLogger().trace(MessageFormat.format("tableName={0},wrapper={1}", tableName, wrapper)); //NOI18N
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));
+
+ // Callback the wrapper to handle parsing
+ try {
+ Storeable storeable = this.getWrapper().parseLineToStoreable(line);
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("storeable={0}", storeable));
+
+ // 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));
+
+ // 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
*
try {
// And parse it to a Contact instance
- Contact contact = this.parseLineToContact(line);
+ Contact contact = (Contact) this.getWrapper().parseLineToStoreable(line);
// Debug message
this.getLogger().debug(MessageFormat.format("contact={0}", contact));
* Gets an iterator for contacts
*
* @return Iterator for contacts
- * @throws org.mxchange.addressbook.exceptions.BadTokenException If the underlaying method has found an invalid token
+ * @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();
}
/**
* 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) {
+ public Storeable readRow (final int rowIndex) throws BadTokenException {
// First rewind
this.rewind();
// Intialize variables
- int count = 0;
+ int count = -1;
Storeable storeable = null;
// Read all rows
- do {
+ while (!this.isEndOfFile() || (count < rowIndex)) {
// Read row
String line = this.readLine();
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("line={0}", line));
+
// Callback the wrapper to handle parsing
storeable = this.getWrapper().parseLineToStoreable(line);
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("storeable={0}", storeable));
+
// Increment counter
count++;
- } while (!this.isEndOfFile() || (count > rowIndex));
+ }
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("storeable={0} - EXIT!", storeable));
// Return found element
return storeable;
}
return isEof;
}
- /**
- * Parses given line and creates a Contact instance
- *
- * @param line Raw line to parse
- *
- * @return Contact instance
- */
- private Contact parseLineToContact (final String line) throws BadTokenException {
- // Trace message
- this.getLogger().trace(MessageFormat.format("line={0} - CALLED!", line)); //NOI18N
-
- // Init A lot variables
- Long num = null;
- Boolean bool = null;
- Gender gender = null;
- int count = 0;
- Contact contact = null;
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("line={0}", line)); //NOI18N
-
- // Then tokenize it
- // @TODO Move this into separate method
- StringTokenizer tokenizer = new StringTokenizer(line, ";"); //NOI18N
-
- // Reset variables
- count = 0;
- contact = null;
-
- // The tokens are now available, so get all
- while (tokenizer.hasMoreElements()) {
- // Reset variables
- num = null;
- bool = null;
-
- // Get next token
- String token = tokenizer.nextToken();
-
- // If char " is at pos 2 (0,1,2), then cut it of there
- if ((token.charAt(0) != '"') && (token.charAt(2) == '"')) {
- // UTF-8 writer characters found
- token = token.substring(2);
- }
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
-
- // Verify token, it must have double-quotes on each side
- if ((!token.startsWith("\"")) || (!token.endsWith("\""))) { //NOI18N
- // Something bad was read
- throw new BadTokenException(token, count); //NOI18N
- }
-
- // All fine, so remove it
- String strippedToken = token.substring(1, token.length() - 1);
-
- // Is the string's content "null"?
- if (strippedToken.equals("null")) { //NOI18N
- // Debug message
- this.getLogger().debug(MessageFormat.format("strippedToken={0} - NULL!", strippedToken)); //NOI18N
-
- // This needs to be set to null
- strippedToken = null;
- }
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("strippedToken={0}", strippedToken)); //NOI18N
-
- // Now, let's try a number check, if no null
- if (strippedToken != null) {
- // Okay, no null, maybe the string bears a decimal number?
- try {
- num = Long.valueOf(strippedToken);
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("strippedToken={0} - NUMBER!", strippedToken)); //NOI18N
- } catch (final NumberFormatException ex) {
- // No number, then set default
- num = null;
- }
- }
-
- // Now, let's try a boolean check, if no null
- if ((strippedToken != null) && (num == null) && ((strippedToken.equals("true")) || (strippedToken.equals("false")))) { //NOI18N
- // Debug message
- this.getLogger().debug(MessageFormat.format("strippedToken={0} - BOOLEAN!", strippedToken)); //NOI18N
-
- // parseBoolean() is relaxed, so no exceptions
- bool = Boolean.valueOf(strippedToken);
- }
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("strippedToken={0},num={1},bool={2}", strippedToken, num, bool)); //NOI18N
-
- // Now, let's try a gender check, if no null
- if ((strippedToken != null) && (num == null) && (bool == null) && ((strippedToken.equals("M")) || (strippedToken.equals("F")) || (strippedToken.equals("C")))) { //NOI18N
- // Get first character
- gender = Gender.fromChar(strippedToken.charAt(0));
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("strippedToken={0},gender={1}", strippedToken, gender)); //NOI18N
-
- // This instance must be there
- assert (gender instanceof Gender) : MessageFormat.format("gender is not set by Gender.fromChar({0})", strippedToken); //NOI18N
- }
-
- // Now it depends on the counter which position we need to check
- switch (count) {
- case 0: // isOwnContact
- assert ((bool instanceof Boolean));
-
- // Debug message
- this.getLogger().debug(MessageFormat.format("bool={0}", bool)); //NOI18N
-
- // Is it own contact?
- if (true == bool) {
- // Debug message
- this.getLogger().debug("Creating UserContact object ..."); //NOI18N
-
- // Own entry
- contact = new UserContact();
- } else {
- // Debug message
- this.getLogger().debug("Creating BookContact object ..."); //NOI18N
-
- // Other contact
- contact = new BookContact();
- }
- break;
-
- case 1: // Gender
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateNameData(gender, null, null, null);
- break;
-
- case 2: // Surname
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
- assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
-
- // Update data
- contact.updateNameData(gender, strippedToken, null, null);
- break;
-
- case 3: // Family name
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
- assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
-
- // Update data
- contact.updateNameData(gender, null, strippedToken, null);
- break;
-
- case 4: // Company name
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
- assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
-
- // Update data
- contact.updateNameData(gender, null, null, strippedToken);
- break;
-
- case 5: // Street number
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateAddressData(strippedToken, 0, null, null);
- break;
-
- case 6: // ZIP code
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateAddressData(null, num, null, null);
- break;
-
- case 7: // City name
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateAddressData(null, 0, strippedToken, null);
- break;
-
- case 8: // Country code
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateAddressData(null, 0, null, strippedToken);
- break;
-
- case 9: // Phone number
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateOtherData(strippedToken, null, null, null, null, null);
- break;
-
- case 10: // Fax number
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateOtherData(null, strippedToken, null, null, null, null);
- break;
-
- case 11: // Cellphone number
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateOtherData(null, null, strippedToken, null, null, null);
- break;
-
- case 12: // Email address
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateOtherData(null, null, null, strippedToken, null, null);
- break;
-
- case 13: // Birthday
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateOtherData(null, null, null, null, strippedToken, null);
- break;
-
- case 14: // Birthday
- assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
-
- // Update data
- contact.updateOtherData(null, null, null, null, null, strippedToken);
- break;
-
- default: // New data entry
- this.getLogger().warn(MessageFormat.format("Will not handle unknown data {0} at index {1}", strippedToken, count)); //NOI18N
- break;
- }
-
- // Increment counter for next round
- count++;
- }
-
- // Trace message
- this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
-
- // Return finished instance
- return contact;
- }
-
/**
* Reads a line from file base
*
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");
+ }
+
// Decode BASE-64
byte[] decoded = Base64.getDecoder().decode(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;
}
line = this.readLine();
// Parse line
- instance = (Storeable) this.parseLineToContact(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
}
}
+ /**
+ * 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
*
* @author Roland Haeder
*/
-public abstract class BaseDatabaseFrontend extends BaseFrameworkSystem implements DatabaseWrapper {
+public abstract class BaseDatabaseFrontend extends BaseFrameworkSystem implements DatabaseFrontend {
/**
* Instance for database backend
--- /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.addressbook.database.frontend;
+
+import org.mxchange.addressbook.FrameworkInterface;
+import org.mxchange.addressbook.database.storage.Storeable;
+import org.mxchange.addressbook.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.addressbook.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.addressbook.database.frontend;
-
-import org.mxchange.addressbook.FrameworkInterface;
-import org.mxchange.addressbook.database.storage.Storeable;
-
-/**
- * A generic interface for database frontends
- *
- * @author Roland Haeder
- */
-public interface DatabaseWrapper 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
- */
- public Storeable parseLineToStoreable (final String line);
-}
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.Iterator;
+import java.util.StringTokenizer;
import org.mxchange.addressbook.contact.Contact;
+import org.mxchange.addressbook.contact.Gender;
+import org.mxchange.addressbook.contact.book.BookContact;
+import org.mxchange.addressbook.contact.user.UserContact;
import org.mxchange.addressbook.database.contact.ContactDatabaseConstants;
import org.mxchange.addressbook.database.frontend.BaseDatabaseFrontend;
import org.mxchange.addressbook.database.storage.Storeable;
*
* @author Roland Haeder
*/
-public class ContactDatabaseFrontend extends BaseDatabaseFrontend implements ContactWrapper {
+public class ContactDatabaseFrontend extends BaseDatabaseFrontend implements ContactFrontend {
/**
* Constructor which accepts a contact manager
// Trace message
this.getLogger().trace("CALLED!"); //NOI18N
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ // Get row index back from backend
+ int rowIndex = this.getBackend().getRowIndexFromColumn(ContactDatabaseConstants.COLUMN_NAME_OWN_CONTACT, true);
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("rowIndex={0}", rowIndex));
+
+ // Init instance
+ Contact contact = null;
+
+ try {
+ // Now simply read the row
+ contact = (Contact) this.getBackend().readRow(rowIndex);
+ } catch (final BadTokenException ex) {
+ // Bad token found
+ this.abortProgramWithException(ex);
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact));
+
+ // Return it
+ return contact;
}
/**
* @return A Storeable instance
*/
@Override
- public Storeable parseLineToStoreable (final String line) {
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ public Storeable parseLineToStoreable (final String line) throws BadTokenException {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("line={0} - CALLED!", line)); //NOI18N
+
+ // Call inner method
+ Contact contact = this.parseLineToContact(line);
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("contact={0}", contact));
+
+ // Return it
+ return (Storeable) contact;
}
/**
*/
@Override
public Contact readSingleContact (final int rowIndex) {
- // Deligate this to backend instance
- return (Contact) this.getBackend().readRow(rowIndex);
-
+ try {
+ // Deligate this to backend instance
+ return (Contact) this.getBackend().readRow(rowIndex);
+ } catch (final BadTokenException ex) {
+ // Bad token found
+ this.abortProgramWithException(ex);
+ }
+
+ // Bad state, should not be reached
+ throw new IllegalStateException("This should not be reached");
+ }
+
+ /**
+ * Parses given line and creates a Contact instance
+ *
+ * @param line Raw line to parse
+ *
+ * @return Contact instance
+ */
+ private Contact parseLineToContact (final String line) throws BadTokenException {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("line={0} - CALLED!", line)); //NOI18N
+
+ // Init A lot variables
+ Long num = null;
+ Boolean bool = null;
+ Gender gender = null;
+ int count = 0;
+ Contact contact = null;
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("line={0}", line)); //NOI18N
+
+ // Then tokenize it
+ // @TODO Move this into separate method
+ StringTokenizer tokenizer = new StringTokenizer(line, ";"); //NOI18N
+
+ // Reset variables
+ count = 0;
+ contact = null;
+
+ // The tokens are now available, so get all
+ while (tokenizer.hasMoreElements()) {
+ // Reset variables
+ num = null;
+ bool = null;
+
+ // Get next token
+ String token = tokenizer.nextToken();
+
+ // If char " is at pos 2 (0,1,2), then cut it of there
+ if ((token.charAt(0) != '"') && (token.charAt(2) == '"')) {
+ // UTF-8 writer characters found
+ token = token.substring(2);
+ }
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
+
+ // Verify token, it must have double-quotes on each side
+ if ((!token.startsWith("\"")) || (!token.endsWith("\""))) { //NOI18N
+ // Something bad was read
+ throw new BadTokenException(token, count); //NOI18N
+ }
+
+ // All fine, so remove it
+ String strippedToken = token.substring(1, token.length() - 1);
+
+ // Is the string's content "null"?
+ if (strippedToken.equals("null")) { //NOI18N
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("strippedToken={0} - NULL!", strippedToken)); //NOI18N
+
+ // This needs to be set to null
+ strippedToken = null;
+ }
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("strippedToken={0}", strippedToken)); //NOI18N
+
+ // Now, let's try a number check, if no null
+ if (strippedToken != null) {
+ // Okay, no null, maybe the string bears a decimal number?
+ try {
+ num = Long.valueOf(strippedToken);
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("strippedToken={0} - NUMBER!", strippedToken)); //NOI18N
+ } catch (final NumberFormatException ex) {
+ // No number, then set default
+ num = null;
+ }
+ }
+
+ // Now, let's try a boolean check, if no null
+ if ((strippedToken != null) && (num == null) && ((strippedToken.equals("true")) || (strippedToken.equals("false")))) { //NOI18N
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("strippedToken={0} - BOOLEAN!", strippedToken)); //NOI18N
+
+ // parseBoolean() is relaxed, so no exceptions
+ bool = Boolean.valueOf(strippedToken);
+ }
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("strippedToken={0},num={1},bool={2}", strippedToken, num, bool)); //NOI18N
+
+ // Now, let's try a gender check, if no null
+ if ((strippedToken != null) && (num == null) && (bool == null) && ((strippedToken.equals("M")) || (strippedToken.equals("F")) || (strippedToken.equals("C")))) { //NOI18N
+ // Get first character
+ gender = Gender.fromChar(strippedToken.charAt(0));
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("strippedToken={0},gender={1}", strippedToken, gender)); //NOI18N
+
+ // This instance must be there
+ assert (gender instanceof Gender) : MessageFormat.format("gender is not set by Gender.fromChar({0})", strippedToken); //NOI18N
+ }
+
+ // Now it depends on the counter which position we need to check
+ switch (count) {
+ case 0: // isOwnContact
+ assert ((bool instanceof Boolean));
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("bool={0}", bool)); //NOI18N
+
+ // Is it own contact?
+ if (true == bool) {
+ // Debug message
+ this.getLogger().debug("Creating UserContact object ..."); //NOI18N
+
+ // Own entry
+ contact = new UserContact();
+ } else {
+ // Debug message
+ this.getLogger().debug("Creating BookContact object ..."); //NOI18N
+
+ // Other contact
+ contact = new BookContact();
+ }
+ break;
+
+ case 1: // Gender
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateNameData(gender, null, null, null);
+ break;
+
+ case 2: // Surname
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+ assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
+
+ // Update data
+ contact.updateNameData(gender, strippedToken, null, null);
+ break;
+
+ case 3: // Family name
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+ assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
+
+ // Update data
+ contact.updateNameData(gender, null, strippedToken, null);
+ break;
+
+ case 4: // Company name
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+ assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
+
+ // Update data
+ contact.updateNameData(gender, null, null, strippedToken);
+ break;
+
+ case 5: // Street number
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateAddressData(strippedToken, 0, null, null);
+ break;
+
+ case 6: // ZIP code
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateAddressData(null, num, null, null);
+ break;
+
+ case 7: // City name
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateAddressData(null, 0, strippedToken, null);
+ break;
+
+ case 8: // Country code
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateAddressData(null, 0, null, strippedToken);
+ break;
+
+ case 9: // Phone number
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateOtherData(strippedToken, null, null, null, null, null);
+ break;
+
+ case 10: // Fax number
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateOtherData(null, strippedToken, null, null, null, null);
+ break;
+
+ case 11: // Cellphone number
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateOtherData(null, null, strippedToken, null, null, null);
+ break;
+
+ case 12: // Email address
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateOtherData(null, null, null, strippedToken, null, null);
+ break;
+
+ case 13: // Birthday
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateOtherData(null, null, null, null, strippedToken, null);
+ break;
+
+ case 14: // Birthday
+ assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
+
+ // Update data
+ contact.updateOtherData(null, null, null, null, null, strippedToken);
+ break;
+
+ default: // New data entry
+ this.getLogger().warn(MessageFormat.format("Will not handle unknown data {0} at index {1}", strippedToken, count)); //NOI18N
+ break;
+ }
+
+ // Increment counter for next round
+ count++;
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
+
+ // Return finished instance
+ return contact;
}
}
--- /dev/null
+/*
+ * Copyright (C) 2015 Roland Häder
+ *
+ * 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.addressbook.database.frontend.contact;
+
+import java.sql.SQLException;
+import org.mxchange.addressbook.contact.Contact;
+import org.mxchange.addressbook.database.frontend.DatabaseFrontend;
+import org.mxchange.addressbook.exceptions.BadTokenException;
+import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
+
+/**
+ *
+ * @author Roland Häder
+ */
+public interface ContactFrontend extends DatabaseFrontend {
+
+ /**
+ * Adds given contact instance to database
+ *
+ * @param contact Contact instance to add
+ * @throws org.mxchange.addressbook.exceptions.ContactAlreadyAddedException If the contact is already added
+ */
+ public void addContact (final Contact contact) throws ContactAlreadyAddedException;
+
+ /**
+ * Shuts down the database layer
+ */
+ public void doShutdown ();
+
+ /**
+ * Some "getter" for total contacts count
+ *
+ * @return Total contacts count
+ * @throws java.sql.SQLException If any SQL error occurs
+ */
+ public int getContactsCount () throws SQLException;
+
+ /**
+ * Checks if given Contact is found
+ *
+ * @param contact Contact instance to check
+ * @return Whether the given Contact instance is found
+ * @throws org.mxchange.addressbook.exceptions.BadTokenException Continued throw
+ */
+ public boolean isContactFound (final Contact contact) throws BadTokenException;
+
+ /**
+ * Some "getter" for own contact instance
+ *
+ * @return Own contact instance
+ */
+ public Contact getOwnContact ();
+
+ /**
+ * Checks whether own contact is found
+ *
+ * @return Whether own contact is found
+ * @throws java.sql.SQLException If any SQL error occurs
+ */
+ public boolean isOwnContactFound () throws SQLException;
+
+ /**
+ * Reads a single row and parses it to a contact instance
+ *
+ * @param rowIndex Row index (also how much to skip)
+ * @return Contact instance
+ */
+ public Contact readSingleContact (final int rowIndex);
+}
+++ /dev/null
-/*
- * Copyright (C) 2015 Roland Häder
- *
- * 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.addressbook.database.frontend.contact;
-
-import java.sql.SQLException;
-import org.mxchange.addressbook.contact.Contact;
-import org.mxchange.addressbook.database.frontend.DatabaseWrapper;
-import org.mxchange.addressbook.exceptions.BadTokenException;
-import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
-
-/**
- *
- * @author Roland Häder
- */
-public interface ContactWrapper extends DatabaseWrapper {
-
- /**
- * Adds given contact instance to database
- *
- * @param contact Contact instance to add
- * @throws org.mxchange.addressbook.exceptions.ContactAlreadyAddedException If the contact is already added
- */
- public void addContact (final Contact contact) throws ContactAlreadyAddedException;
-
- /**
- * Shuts down the database layer
- */
- public void doShutdown ();
-
- /**
- * Some "getter" for total contacts count
- *
- * @return Total contacts count
- * @throws java.sql.SQLException If any SQL error occurs
- */
- public int getContactsCount () throws SQLException;
-
- /**
- * Checks if given Contact is found
- *
- * @param contact Contact instance to check
- * @return Whether the given Contact instance is found
- * @throws org.mxchange.addressbook.exceptions.BadTokenException Continued throw
- */
- public boolean isContactFound (final Contact contact) throws BadTokenException;
-
- /**
- * Some "getter" for own contact instance
- *
- * @return Own contact instance
- */
- public Contact getOwnContact ();
-
- /**
- * Checks whether own contact is found
- *
- * @return Whether own contact is found
- * @throws java.sql.SQLException If any SQL error occurs
- */
- public boolean isOwnContactFound () throws SQLException;
-
- /**
- * Reads a single row and parses it to a contact instance
- *
- * @param rowIndex Row index (also how much to skip)
- * @return Contact instance
- */
- public Contact readSingleContact (final int rowIndex);
-}
* 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 ();
}
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.mxchange.addressbook.client.Client;
import org.mxchange.addressbook.contact.Contact;
import org.mxchange.addressbook.contact.Gender;
import org.mxchange.addressbook.database.frontend.contact.ContactDatabaseFrontend;
-import org.mxchange.addressbook.database.frontend.contact.ContactWrapper;
+import org.mxchange.addressbook.database.frontend.contact.ContactFrontend;
import org.mxchange.addressbook.exceptions.BadTokenException;
import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException;
private final List<String> columnNames;
/**
- * A ContactWrapper instance
+ * Translated column name list
*/
- private final ContactWrapper contactDatabase;
+ private final List<String> translatedColumnNames;
+
+ /**
+ * A ContactFrontend instance
+ */
+ private final ContactFrontend contactDatabase;
/**
* Constructor which accepts maxContacts for maximum (initial) contacts and
// Initialize list
this.columnNames = new ArrayList<>(15);
+ this.translatedColumnNames = new ArrayList<>(15);
// And fill it
this.fillColumnNamesFromBundle();
* Getter for column name at given index.
*
* @param columnIndex Column index
- * @return Human-readable column name
+ * @return Database column name
*/
@Override
public String getColumnName (final int columnIndex) {
return this.columnNames.get(columnIndex);
}
+ /**
+ * Getter for translated column name at given index.
+ *
+ * @param columnIndex Column index
+ * @return Human-readable column name
+ */
+ @Override
+ public String getTranslatedColumnName (final int columnIndex) {
+ assert (this.translatedColumnNames instanceof List) : "this.translatedColumnNames is not initialized"; //NOI18N
+
+ // Get column name at index
+ return this.translatedColumnNames.get(columnIndex);
+ }
+
/**
* Somewhat "getter" for value from given row and column index
*
*/
private void fillColumnNamesFromBundle () {
assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
+ assert (this.translatedColumnNames instanceof List) : "this.translatedColumnNames is not initialized"; //NOI18N
// Debug message
this.getLogger().trace("CALLED!"); //NOI18N
// This is the wanted entry.
this.getLogger().debug(MessageFormat.format("key={0}", key)); //NOI18N
+ // Convert string to array based on delimiter '.'
+ String[] tokens = this.getArrayFromString(key, ".", 4);
+
+ // Token array must contain 4 elements (ContactManager.columnName.foo.text)
+ assert(tokens.length == 4) : MessageFormat.format("Array tokens contains not 4 elements: {0}", Arrays.toString(tokens));
+
+ // Get pre-last element
+ String columnName = tokens[tokens.length - 2];
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("columnName={0} - adding ...", columnName));
+
// So add it
- this.columnNames.add(this.getBundle().getString(key));
+ this.columnNames.add(columnName);
+ this.translatedColumnNames.add(this.getBundle().getString(key));
}
}
}
/**
- * A ContactWrapper instance
+ * A ContactFrontend instance
*
* @return the database
*/
- private ContactWrapper getContactDatabase () {
+ private ContactFrontend getContactDatabase () {
return this.contactDatabase;
}
* Getter for column name at given index.
*
* @param columnIndex Column index
- * @return Human-readable column name
+ * @return Database column name
*/
public String getColumnName (final int columnIndex);
+ /**
+ * Getter for translated column name at given index.
+ *
+ * @param columnIndex Column index
+ * @return Human-readable column name
+ */
+ public String getTranslatedColumnName (int columnIndex);
+
/**
* Somewhat "getter" for value from given row and column index
*
@Override
public String getColumnName (final int columnIndex) {
// Deligate this call to contact manager
- return this.getClient().getContactManager().getColumnName(columnIndex);
+ return this.getClient().getContactManager().getTranslatedColumnName(columnIndex);
}
@Override