From 00f3dde9db34c1c76d6e4c52aaeb40cefa3bcc8d Mon Sep 17 00:00:00 2001 From: Roland Haeder Date: Fri, 24 Jul 2015 11:29:04 +0200 Subject: [PATCH] =?utf8?q?Moved=20exceptions=20in=20own=20package=20Signed?= =?utf8?q?-off-by:Roland=20H=C3=A4der=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../application/AddressbookApplication.java | 2 +- .../mxchange/addressbook/client/Client.java | 2 +- .../client/console/ConsoleClient.java | 2 +- .../client/gui/AddressbookFrame.java | 4 +- .../addressbook/client/gui/ClientFrame.java | 4 +- .../addressbook/client/gui/SwingClient.java | 4 +- .../database/backend/csv/CsvBackend.java | 74 +- .../backend/csv/CsvDatabaseBackend.java | 1002 ++++++++--------- .../contact/ContactDatabaseFrontend.java | 258 ++--- .../{ => exceptions}/BadTokenException.java | 60 +- .../FrameAlreadyInitializedException.java | 2 +- .../UnhandledUserChoiceException.java | 60 +- .../manager/contact/ContactManager.java | 2 +- 13 files changed, 739 insertions(+), 737 deletions(-) rename Addressbook/src/org/mxchange/addressbook/{ => exceptions}/BadTokenException.java (84%) rename Addressbook/src/org/mxchange/addressbook/{ => exceptions}/FrameAlreadyInitializedException.java (95%) rename Addressbook/src/org/mxchange/addressbook/{ => exceptions}/UnhandledUserChoiceException.java (93%) diff --git a/Addressbook/src/org/mxchange/addressbook/application/AddressbookApplication.java b/Addressbook/src/org/mxchange/addressbook/application/AddressbookApplication.java index eab7e71..a7842b0 100644 --- a/Addressbook/src/org/mxchange/addressbook/application/AddressbookApplication.java +++ b/Addressbook/src/org/mxchange/addressbook/application/AddressbookApplication.java @@ -18,10 +18,10 @@ package org.mxchange.addressbook.application; import java.text.MessageFormat; import org.mxchange.addressbook.BaseFrameworkSystem; -import org.mxchange.addressbook.UnhandledUserChoiceException; import org.mxchange.addressbook.client.Client; import org.mxchange.addressbook.client.console.ConsoleClient; import org.mxchange.addressbook.client.gui.SwingClient; +import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException; import org.mxchange.addressbook.manager.application.ApplicationManager; /** diff --git a/Addressbook/src/org/mxchange/addressbook/client/Client.java b/Addressbook/src/org/mxchange/addressbook/client/Client.java index 6e28668..42b7b7c 100644 --- a/Addressbook/src/org/mxchange/addressbook/client/Client.java +++ b/Addressbook/src/org/mxchange/addressbook/client/Client.java @@ -17,7 +17,7 @@ package org.mxchange.addressbook.client; import org.mxchange.addressbook.FrameworkInterface; -import org.mxchange.addressbook.UnhandledUserChoiceException; +import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException; import org.mxchange.addressbook.contact.Contact; import org.mxchange.addressbook.menu.item.SelectableMenuItem; diff --git a/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java b/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java index 2015873..3f58899 100644 --- a/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java +++ b/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java @@ -19,13 +19,13 @@ package org.mxchange.addressbook.client.console; import java.text.MessageFormat; import java.util.Arrays; import java.util.Scanner; -import org.mxchange.addressbook.UnhandledUserChoiceException; import org.mxchange.addressbook.application.AddressbookApplication; import org.mxchange.addressbook.application.Application; import org.mxchange.addressbook.client.BaseClient; import org.mxchange.addressbook.client.Client; import org.mxchange.addressbook.contact.Contact; import org.mxchange.addressbook.contact.user.UserContact; +import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException; import org.mxchange.addressbook.menu.Menu; import org.mxchange.addressbook.menu.MenuTools; import org.mxchange.addressbook.menu.console.ConsoleMenu; diff --git a/Addressbook/src/org/mxchange/addressbook/client/gui/AddressbookFrame.java b/Addressbook/src/org/mxchange/addressbook/client/gui/AddressbookFrame.java index c0f132f..d03358c 100644 --- a/Addressbook/src/org/mxchange/addressbook/client/gui/AddressbookFrame.java +++ b/Addressbook/src/org/mxchange/addressbook/client/gui/AddressbookFrame.java @@ -31,9 +31,9 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import org.mxchange.addressbook.BaseFrameworkSystem; -import org.mxchange.addressbook.FrameAlreadyInitializedException; import org.mxchange.addressbook.application.AddressbookApplication; import org.mxchange.addressbook.client.Client; +import org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException; /** * @@ -146,7 +146,7 @@ public class AddressbookFrame extends BaseFrameworkSystem implements ClientFrame * accessible) means that any other object can initialize components which * you may not want. * - * @throws org.mxchange.addressbook.FrameAlreadyInitializedException If this method has been called twice + * @throws org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException If this method has been called twice */ @Override public void init () throws FrameAlreadyInitializedException { diff --git a/Addressbook/src/org/mxchange/addressbook/client/gui/ClientFrame.java b/Addressbook/src/org/mxchange/addressbook/client/gui/ClientFrame.java index 5039528..389e744 100644 --- a/Addressbook/src/org/mxchange/addressbook/client/gui/ClientFrame.java +++ b/Addressbook/src/org/mxchange/addressbook/client/gui/ClientFrame.java @@ -16,9 +16,9 @@ */ package org.mxchange.addressbook.client.gui; -import org.mxchange.addressbook.FrameAlreadyInitializedException; import org.mxchange.addressbook.FrameworkInterface; import org.mxchange.addressbook.client.Client; +import org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException; /** * An interface for applications with a frame @@ -43,7 +43,7 @@ public interface ClientFrame extends FrameworkInterface { /** * Initializes frame * - * @throws org.mxchange.addressbook.FrameAlreadyInitializedException If this method has been called twice + * @throws org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException If this method has been called twice */ public void init () throws FrameAlreadyInitializedException; diff --git a/Addressbook/src/org/mxchange/addressbook/client/gui/SwingClient.java b/Addressbook/src/org/mxchange/addressbook/client/gui/SwingClient.java index 29fc9a6..0914828 100644 --- a/Addressbook/src/org/mxchange/addressbook/client/gui/SwingClient.java +++ b/Addressbook/src/org/mxchange/addressbook/client/gui/SwingClient.java @@ -16,12 +16,12 @@ */ package org.mxchange.addressbook.client.gui; -import org.mxchange.addressbook.FrameAlreadyInitializedException; -import org.mxchange.addressbook.UnhandledUserChoiceException; import org.mxchange.addressbook.application.Application; import org.mxchange.addressbook.client.BaseClient; import org.mxchange.addressbook.client.Client; import org.mxchange.addressbook.contact.Contact; +import org.mxchange.addressbook.exceptions.FrameAlreadyInitializedException; +import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException; import org.mxchange.addressbook.menu.Menu; import org.mxchange.addressbook.menu.item.SelectableMenuItem; diff --git a/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvBackend.java b/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvBackend.java index f310588..525f624 100644 --- a/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvBackend.java +++ b/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvBackend.java @@ -1,37 +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.addressbook.database.backend.csv; - -import java.util.Iterator; -import org.mxchange.addressbook.BadTokenException; -import org.mxchange.addressbook.contact.Contact; -import org.mxchange.addressbook.database.backend.DatabaseBackend; - -/** - * - * @author Roland Haeder - */ -public interface CsvBackend extends DatabaseBackend { - - /** - * Gets an iterator for contacts - * - * @return Iterator for contacts - * @throws org.mxchange.addressbook.BadTokenException If the CSV token is badly formulated - */ - public Iterator contactIterator () throws BadTokenException; -} +/* + * 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.addressbook.database.backend.csv; + +import java.util.Iterator; +import org.mxchange.addressbook.contact.Contact; +import org.mxchange.addressbook.database.backend.DatabaseBackend; +import org.mxchange.addressbook.exceptions.BadTokenException; + +/** + * + * @author Roland Haeder + */ +public interface CsvBackend extends DatabaseBackend { + + /** + * Gets an iterator for contacts + * + * @return Iterator for contacts + * @throws org.mxchange.addressbook.exceptions.BadTokenException If the CSV token is badly formulated + */ + public Iterator contactIterator () throws BadTokenException; +} diff --git a/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvDatabaseBackend.java b/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvDatabaseBackend.java index 9f3e832..7540254 100644 --- a/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvDatabaseBackend.java +++ b/Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvDatabaseBackend.java @@ -1,501 +1,501 @@ -/* - * 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.addressbook.database.backend.csv; - -import java.io.DataOutput; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; -import org.mxchange.addressbook.BadTokenException; -import org.mxchange.addressbook.contact.Contact; -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.storage.Storeable; -import org.mxchange.addressbook.database.storage.csv.StoreableCsv; - -/** - * A database backend with CSV file as storage implementation - * - * @author Roland Haeder - */ -public class CsvDatabaseBackend extends BaseDatabaseBackend implements CsvBackend { - /** - * Output stream for this storage engine - */ - private RandomAccessFile storageFile; - - /** - * Constructor with table name - * - * @param tableName Name of "table" - */ - public CsvDatabaseBackend (final String tableName) { - // Debug message - this.getLogger().debug(MessageFormat.format("Trying to initialize table {0} ...", tableName)); - - // Set table name here, too - this.setTableName(tableName); - - // Construct file name - String fileName = String.format("data/table_%s.csv", tableName); - - // Debug message - this.getLogger().debug(MessageFormat.format("Trying to open file {0} ...", fileName)); - - try { - // Try to initialize the storage (file instance) - this.storageFile = new RandomAccessFile(fileName, "rw"); - } catch (final FileNotFoundException ex) { - // Did not work - this.getLogger().error(MessageFormat.format("File {0} cannot be opened: {1}", fileName, ex.toString())); - System.exit(1); - } - - // Output message - this.getLogger().debug(MessageFormat.format("Database for {0} has been initialized.", tableName)); - } - - /** - * Gets an iterator for contacts - * - * @return Iterator for contacts - * @throws org.mxchange.addressbook.BadTokenException If the underlaying method has found an invalid token - */ - @Override - public Iterator contactIterator () throws BadTokenException { - /* - * Then read the file into RAM (yes, not perfect for >1000 entries ...) - * and get a List back. - */ - List list = this.readContactList(); - - // Get iterator from list and return it - return list.iterator(); - } - - /** - * Shuts down this backend - */ - @Override - public void doShutdown () { - try { - // Close file - this.getStorageFile().close(); - } catch (final IOException ex) { - this.getLogger().catching(ex); - System.exit(1); - } - } - - /** - * 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)); - } catch (final IOException ex) { - // Length cannot be determined - this.getLogger().catching(ex); - System.exit(1); - } - - // Return result - this.getLogger().trace(MessageFormat.format("length={0} : EXIT!", length)); - return length; - } - - /** - * Rewinds backend - */ - @Override - public void rewind (){ - this.getLogger().trace("CALLED!"); - - try { - // Rewind underlaying database file - this.getStorageFile().seek(0); - } catch (final IOException ex) { - this.getLogger().catching(ex); - System.exit(1); - } - - this.getLogger().trace("EXIT!"); - } - - /** - * 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 { - // 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)); - - // The string is now a valid CSV string - this.getStorageFile().writeBytes(str); - } - - /** - * Adds given contact to list - * - * @param contact Contact instance to add - * @param list List instance - */ - private void addContactToList (final Contact contact, final List list) { - // Debug message - this.getLogger().debug(MessageFormat.format("contact={0}", contact)); - - // Is the contact read? - if (contact instanceof Contact) { - // Then add it - boolean added = list.add(contact); - - // Debug message - this.getLogger().debug(MessageFormat.format("contact={0} added={1}", contact, added)); - - // Has it been added? - if (!added) { - // Not added - this.getLogger().warn("Contact object has not been added."); - } - } - } - - /** - * 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)); - return isEof; - } - - /** - * Reads the database file, if available, and adds all read lines into - * the list. - * - * @return A list with Contact instances - */ - private List readContactList () throws BadTokenException { - this.getLogger().trace("CALLED!"); - - // 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)); - - // Instance list - // @TODO The maximum length could be guessed from file size? - List list = new ArrayList<>(lines); - - // Init variables - StringTokenizer tokenizer; - String line; - - // Read all lines - while (!this.isEndOfFile()) { - // Then read a line - line = this.readLine(); - - // Debug message - this.getLogger().debug(MessageFormat.format("line={0}", line)); - - // Then tokenize it - // @TODO Move this into separate method - tokenizer = new StringTokenizer(line, ";"); - - // Count round - int count = 0; - - // Init contact object - Contact contact = null; - - // The tokens are now available, so get all - while (tokenizer.hasMoreElements()) { - // Get next token - String token = tokenizer.nextToken(); - - // Debug message - this.getLogger().debug(MessageFormat.format("token={0}", token)); - - // Verify token, it must have double-quotes on each side - if ((!token.startsWith("\"")) || (!token.endsWith("\""))) { - // Something bad was read - throw new BadTokenException(MessageFormat.format("Token {0} has not double-quotes on both ends.", token)); - } - - // All fine, so remove it - String strippedToken = token.substring(1, token.length() - 1); - - // Is the string's content "null"? - if (strippedToken.equals("null")) { - // Debug message - this.getLogger().debug(MessageFormat.format("strippedToken={0} - NULL!", strippedToken)); - - // This needs to be set to null - strippedToken = null; - } - - // Debug message - this.getLogger().debug(MessageFormat.format("strippedToken={0}", strippedToken)); - - // Init number/string data values - String strData = strippedToken; - Long num = null; - Boolean bool = null; - char gender = '?'; - - // 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)); - } 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")))) { - // Debug message - this.getLogger().debug(MessageFormat.format("strippedToken={0} - BOOLEAN!", strippedToken)); - - // parseBoolean() is relaxed, so no exceptions - bool = Boolean.valueOf(strippedToken); - } - - // Now, let's try a boolean check, if no null - if ((strippedToken != null) && (num == null) && (bool == null) && ((strippedToken.equals("M")) || (strippedToken.equals("F")) || (strippedToken.equals("C")))) { - // Get first character - gender = strippedToken.charAt(0); - } - - // 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)); - - // Is it own contact? - if (true == bool) { - // Debug message - this.getLogger().debug("Creating UserContact object ..."); - - // Own entry - contact = new UserContact(); - } else { - // Debug message - this.getLogger().debug("Creating BookContact object ..."); - - // Other contact - contact = new BookContact(); - } - break; - - case 1: // Gender - assert(contact instanceof Contact) : "First token was not boolean"; - assert(gender != '?') : "Gender is not detected."; - - // Update data - contact.updateNameData(gender, null, null, null); - break; - - case 2: // Surname - assert(contact instanceof Contact) : "First token was not boolean"; - assert(gender != '?') : "Gender is not detected."; - - // Update data - contact.updateNameData(gender, strippedToken, null, null); - break; - - case 3: // Family name - assert(contact instanceof Contact) : "First token was not boolean"; - assert(gender != '?') : "Gender is not detected."; - - // Update data - contact.updateNameData(gender, null, strippedToken, null); - break; - - case 4: // Company name - assert(contact instanceof Contact) : "First token was not boolean"; - assert(gender != '?') : "Gender is not detected."; - - // Update data - contact.updateNameData(gender, null, null, strippedToken); - break; - - case 5: // Street number - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateAddressData(strippedToken, 0, null, null); - break; - - case 6: // ZIP code - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateAddressData(null, num, null, null); - break; - - case 7: // City name - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateAddressData(null, 0, strippedToken, null); - break; - - case 8: // Country code - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateAddressData(null, 0, null, strippedToken); - break; - - case 9: // Phone number - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateOtherData(strippedToken, null, null, null, null, null); - break; - - case 10: // Fax number - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateOtherData(null, strippedToken, null, null, null, null); - break; - - case 11: // Cellphone number - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateOtherData(null, null, strippedToken, null, null, null); - break; - - case 12: // Email address - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateOtherData(null, null, null, strippedToken, null, null); - break; - - case 13: // Birthday - assert(contact instanceof Contact) : "First token was not boolean"; - - // Update data - contact.updateOtherData(null, null, null, null, strippedToken, null); - break; - - case 14: // Birthday - assert(contact instanceof Contact) : "First token was not boolean"; - - // 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)); - break; - } - - // Increment counter for next round - count++; - } - - // Add contact - this.addContactToList(contact, list); - } - - // Return finished list - this.getLogger().trace(MessageFormat.format("list.size()={0} : EXIT!", list.size())); - return list; - } - - /** - * Reads a line from file base - * - * @return Read line from file - */ - private String readLine () { - // Init input - String input = null; - - try { - input = this.getStorageFile().readLine(); - } catch (final IOException ex) { - this.getLogger().catching(ex); - } - - // Return read string or null - return input; - } -} +/* + * 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.addressbook.database.backend.csv; + +import java.io.DataOutput; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; +import org.mxchange.addressbook.contact.Contact; +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.storage.Storeable; +import org.mxchange.addressbook.database.storage.csv.StoreableCsv; +import org.mxchange.addressbook.exceptions.BadTokenException; + +/** + * A database backend with CSV file as storage implementation + * + * @author Roland Haeder + */ +public class CsvDatabaseBackend extends BaseDatabaseBackend implements CsvBackend { + /** + * Output stream for this storage engine + */ + private RandomAccessFile storageFile; + + /** + * Constructor with table name + * + * @param tableName Name of "table" + */ + public CsvDatabaseBackend (final String tableName) { + // Debug message + this.getLogger().debug(MessageFormat.format("Trying to initialize table {0} ...", tableName)); + + // Set table name here, too + this.setTableName(tableName); + + // Construct file name + String fileName = String.format("data/table_%s.csv", tableName); + + // Debug message + this.getLogger().debug(MessageFormat.format("Trying to open file {0} ...", fileName)); + + try { + // Try to initialize the storage (file instance) + this.storageFile = new RandomAccessFile(fileName, "rw"); + } catch (final FileNotFoundException ex) { + // Did not work + this.getLogger().error(MessageFormat.format("File {0} cannot be opened: {1}", fileName, ex.toString())); + System.exit(1); + } + + // Output message + this.getLogger().debug(MessageFormat.format("Database for {0} has been initialized.", tableName)); + } + + /** + * 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 contactIterator () throws BadTokenException { + /* + * Then read the file into RAM (yes, not perfect for >1000 entries ...) + * and get a List back. + */ + List list = this.readContactList(); + + // Get iterator from list and return it + return list.iterator(); + } + + /** + * Shuts down this backend + */ + @Override + public void doShutdown () { + try { + // Close file + this.getStorageFile().close(); + } catch (final IOException ex) { + this.getLogger().catching(ex); + System.exit(1); + } + } + + /** + * 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)); + } catch (final IOException ex) { + // Length cannot be determined + this.getLogger().catching(ex); + System.exit(1); + } + + // Return result + this.getLogger().trace(MessageFormat.format("length={0} : EXIT!", length)); + return length; + } + + /** + * Rewinds backend + */ + @Override + public void rewind (){ + this.getLogger().trace("CALLED!"); + + try { + // Rewind underlaying database file + this.getStorageFile().seek(0); + } catch (final IOException ex) { + this.getLogger().catching(ex); + System.exit(1); + } + + this.getLogger().trace("EXIT!"); + } + + /** + * 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 { + // 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)); + + // The string is now a valid CSV string + this.getStorageFile().writeBytes(str); + } + + /** + * Adds given contact to list + * + * @param contact Contact instance to add + * @param list List instance + */ + private void addContactToList (final Contact contact, final List list) { + // Debug message + this.getLogger().debug(MessageFormat.format("contact={0}", contact)); + + // Is the contact read? + if (contact instanceof Contact) { + // Then add it + boolean added = list.add(contact); + + // Debug message + this.getLogger().debug(MessageFormat.format("contact={0} added={1}", contact, added)); + + // Has it been added? + if (!added) { + // Not added + this.getLogger().warn("Contact object has not been added."); + } + } + } + + /** + * 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)); + return isEof; + } + + /** + * Reads the database file, if available, and adds all read lines into + * the list. + * + * @return A list with Contact instances + */ + private List readContactList () throws BadTokenException { + this.getLogger().trace("CALLED!"); + + // 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)); + + // Instance list + // @TODO The maximum length could be guessed from file size? + List list = new ArrayList<>(lines); + + // Init variables + StringTokenizer tokenizer; + String line; + + // Read all lines + while (!this.isEndOfFile()) { + // Then read a line + line = this.readLine(); + + // Debug message + this.getLogger().debug(MessageFormat.format("line={0}", line)); + + // Then tokenize it + // @TODO Move this into separate method + tokenizer = new StringTokenizer(line, ";"); + + // Count round + int count = 0; + + // Init contact object + Contact contact = null; + + // The tokens are now available, so get all + while (tokenizer.hasMoreElements()) { + // Get next token + String token = tokenizer.nextToken(); + + // Debug message + this.getLogger().debug(MessageFormat.format("token={0}", token)); + + // Verify token, it must have double-quotes on each side + if ((!token.startsWith("\"")) || (!token.endsWith("\""))) { + // Something bad was read + throw new BadTokenException(MessageFormat.format("Token {0} has not double-quotes on both ends.", token)); + } + + // All fine, so remove it + String strippedToken = token.substring(1, token.length() - 1); + + // Is the string's content "null"? + if (strippedToken.equals("null")) { + // Debug message + this.getLogger().debug(MessageFormat.format("strippedToken={0} - NULL!", strippedToken)); + + // This needs to be set to null + strippedToken = null; + } + + // Debug message + this.getLogger().debug(MessageFormat.format("strippedToken={0}", strippedToken)); + + // Init number/string data values + String strData = strippedToken; + Long num = null; + Boolean bool = null; + char gender = '?'; + + // 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)); + } 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")))) { + // Debug message + this.getLogger().debug(MessageFormat.format("strippedToken={0} - BOOLEAN!", strippedToken)); + + // parseBoolean() is relaxed, so no exceptions + bool = Boolean.valueOf(strippedToken); + } + + // Now, let's try a boolean check, if no null + if ((strippedToken != null) && (num == null) && (bool == null) && ((strippedToken.equals("M")) || (strippedToken.equals("F")) || (strippedToken.equals("C")))) { + // Get first character + gender = strippedToken.charAt(0); + } + + // 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)); + + // Is it own contact? + if (true == bool) { + // Debug message + this.getLogger().debug("Creating UserContact object ..."); + + // Own entry + contact = new UserContact(); + } else { + // Debug message + this.getLogger().debug("Creating BookContact object ..."); + + // Other contact + contact = new BookContact(); + } + break; + + case 1: // Gender + assert(contact instanceof Contact) : "First token was not boolean"; + assert(gender != '?') : "Gender is not detected."; + + // Update data + contact.updateNameData(gender, null, null, null); + break; + + case 2: // Surname + assert(contact instanceof Contact) : "First token was not boolean"; + assert(gender != '?') : "Gender is not detected."; + + // Update data + contact.updateNameData(gender, strippedToken, null, null); + break; + + case 3: // Family name + assert(contact instanceof Contact) : "First token was not boolean"; + assert(gender != '?') : "Gender is not detected."; + + // Update data + contact.updateNameData(gender, null, strippedToken, null); + break; + + case 4: // Company name + assert(contact instanceof Contact) : "First token was not boolean"; + assert(gender != '?') : "Gender is not detected."; + + // Update data + contact.updateNameData(gender, null, null, strippedToken); + break; + + case 5: // Street number + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateAddressData(strippedToken, 0, null, null); + break; + + case 6: // ZIP code + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateAddressData(null, num, null, null); + break; + + case 7: // City name + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateAddressData(null, 0, strippedToken, null); + break; + + case 8: // Country code + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateAddressData(null, 0, null, strippedToken); + break; + + case 9: // Phone number + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateOtherData(strippedToken, null, null, null, null, null); + break; + + case 10: // Fax number + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateOtherData(null, strippedToken, null, null, null, null); + break; + + case 11: // Cellphone number + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateOtherData(null, null, strippedToken, null, null, null); + break; + + case 12: // Email address + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateOtherData(null, null, null, strippedToken, null, null); + break; + + case 13: // Birthday + assert(contact instanceof Contact) : "First token was not boolean"; + + // Update data + contact.updateOtherData(null, null, null, null, strippedToken, null); + break; + + case 14: // Birthday + assert(contact instanceof Contact) : "First token was not boolean"; + + // 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)); + break; + } + + // Increment counter for next round + count++; + } + + // Add contact + this.addContactToList(contact, list); + } + + // Return finished list + this.getLogger().trace(MessageFormat.format("list.size()={0} : EXIT!", list.size())); + return list; + } + + /** + * Reads a line from file base + * + * @return Read line from file + */ + private String readLine () { + // Init input + String input = null; + + try { + input = this.getStorageFile().readLine(); + } catch (final IOException ex) { + this.getLogger().catching(ex); + } + + // Return read string or null + return input; + } +} diff --git a/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java b/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java index df1854c..c181b88 100644 --- a/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java +++ b/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java @@ -1,129 +1,129 @@ -/* - * 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.addressbook.database.frontend.contact; - -import java.io.IOException; -import java.util.Iterator; -import java.util.List; -import org.mxchange.addressbook.BadTokenException; -import org.mxchange.addressbook.contact.Contact; -import org.mxchange.addressbook.database.backend.csv.CsvBackend; -import org.mxchange.addressbook.database.frontend.BaseDatabaseFrontend; -import org.mxchange.addressbook.database.storage.Storeable; -import org.mxchange.addressbook.manager.contact.ContactManager; - -/** - * Stores and retrieves Contact instances - * - * @author Roland Haeder - */ -public class ContactDatabaseFrontend extends BaseDatabaseFrontend implements ContactWrapper { - /** - * Constructor which accepts a contact manager - * @param manager - */ - public ContactDatabaseFrontend (final ContactManager manager) { - // Call own constructor - this(); - - // Set contact manager - this.setContactManager(manager); - } - - /** - * Basic constrcutor - */ - protected ContactDatabaseFrontend () { - super(); - - // Set "table" name - this.setTableName("contacts"); - - // Initalize backend - this.initBackend(); - } - - /** - * Shuts down the database layer - */ - @Override - public void doShutdown () { - // Shutdown backend - this.getBackend().doShutdown(); - } - - /** - * Flushes all contact entries to database - */ - @Override - public void flushAllContacts () { - // Get full list - List contacts = this.getContactManager().getList(); - - // Get iterator - Iterator iterator = contacts.iterator(); - - // Rewind backend - this.getBackend().rewind(); - - // Get all entries - while (iterator.hasNext()) { - // Get next entry - Contact contact = iterator.next(); - - try { - // Store this entry - this.getBackend().store((Storeable) contact); - } catch (final IOException ex) { - // Should not happen? - this.getLogger().catching(ex); - System.exit(1); - } - } - } - - /** - * Reads all contacts from database backend and handles them over to the - * contact manager - */ - @Override - public void readAllContacts () { - // Get iterator and case it - CsvBackend backend = (CsvBackend) this.getBackend(); - - // First rewind to beginning - this.getBackend().rewind(); - - // Get backend iterator - Iterator iterator = null; - try { - iterator = backend.contactIterator(); - } catch (final BadTokenException ex) { - this.getLogger().catching(ex); - System.exit(1); - } - - // Read all entries - while (iterator.hasNext()) { - // Get next entry - Contact contact = iterator.next(); - - // Add contact instance to manager - this.getContactManager().addContact(contact); - } - } -} +/* + * 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.addressbook.database.frontend.contact; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import org.mxchange.addressbook.exceptions.BadTokenException; +import org.mxchange.addressbook.contact.Contact; +import org.mxchange.addressbook.database.backend.csv.CsvBackend; +import org.mxchange.addressbook.database.frontend.BaseDatabaseFrontend; +import org.mxchange.addressbook.database.storage.Storeable; +import org.mxchange.addressbook.manager.contact.ContactManager; + +/** + * Stores and retrieves Contact instances + * + * @author Roland Haeder + */ +public class ContactDatabaseFrontend extends BaseDatabaseFrontend implements ContactWrapper { + /** + * Constructor which accepts a contact manager + * @param manager + */ + public ContactDatabaseFrontend (final ContactManager manager) { + // Call own constructor + this(); + + // Set contact manager + this.setContactManager(manager); + } + + /** + * Basic constrcutor + */ + protected ContactDatabaseFrontend () { + super(); + + // Set "table" name + this.setTableName("contacts"); + + // Initalize backend + this.initBackend(); + } + + /** + * Shuts down the database layer + */ + @Override + public void doShutdown () { + // Shutdown backend + this.getBackend().doShutdown(); + } + + /** + * Flushes all contact entries to database + */ + @Override + public void flushAllContacts () { + // Get full list + List contacts = this.getContactManager().getList(); + + // Get iterator + Iterator iterator = contacts.iterator(); + + // Rewind backend + this.getBackend().rewind(); + + // Get all entries + while (iterator.hasNext()) { + // Get next entry + Contact contact = iterator.next(); + + try { + // Store this entry + this.getBackend().store((Storeable) contact); + } catch (final IOException ex) { + // Should not happen? + this.getLogger().catching(ex); + System.exit(1); + } + } + } + + /** + * Reads all contacts from database backend and handles them over to the + * contact manager + */ + @Override + public void readAllContacts () { + // Get iterator and case it + CsvBackend backend = (CsvBackend) this.getBackend(); + + // First rewind to beginning + this.getBackend().rewind(); + + // Get backend iterator + Iterator iterator = null; + try { + iterator = backend.contactIterator(); + } catch (final BadTokenException ex) { + this.getLogger().catching(ex); + System.exit(1); + } + + // Read all entries + while (iterator.hasNext()) { + // Get next entry + Contact contact = iterator.next(); + + // Add contact instance to manager + this.getContactManager().addContact(contact); + } + } +} diff --git a/Addressbook/src/org/mxchange/addressbook/BadTokenException.java b/Addressbook/src/org/mxchange/addressbook/exceptions/BadTokenException.java similarity index 84% rename from Addressbook/src/org/mxchange/addressbook/BadTokenException.java rename to Addressbook/src/org/mxchange/addressbook/exceptions/BadTokenException.java index ce02e50..ed37c2c 100644 --- a/Addressbook/src/org/mxchange/addressbook/BadTokenException.java +++ b/Addressbook/src/org/mxchange/addressbook/exceptions/BadTokenException.java @@ -1,29 +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.addressbook; - -/** - * - * @author Roland Haeder - */ -public class BadTokenException extends Exception { - - public BadTokenException (final String str) { - super(str); - } - -} +/* + * 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.addressbook.exceptions; + +/** + * 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 { + + public BadTokenException (final String str) { + super(str); + } + +} diff --git a/Addressbook/src/org/mxchange/addressbook/FrameAlreadyInitializedException.java b/Addressbook/src/org/mxchange/addressbook/exceptions/FrameAlreadyInitializedException.java similarity index 95% rename from Addressbook/src/org/mxchange/addressbook/FrameAlreadyInitializedException.java rename to Addressbook/src/org/mxchange/addressbook/exceptions/FrameAlreadyInitializedException.java index 0a4be3c..693ccc2 100644 --- a/Addressbook/src/org/mxchange/addressbook/FrameAlreadyInitializedException.java +++ b/Addressbook/src/org/mxchange/addressbook/exceptions/FrameAlreadyInitializedException.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.mxchange.addressbook; +package org.mxchange.addressbook.exceptions; /** * This exception is thrown when initFrame() is called twice. diff --git a/Addressbook/src/org/mxchange/addressbook/UnhandledUserChoiceException.java b/Addressbook/src/org/mxchange/addressbook/exceptions/UnhandledUserChoiceException.java similarity index 93% rename from Addressbook/src/org/mxchange/addressbook/UnhandledUserChoiceException.java rename to Addressbook/src/org/mxchange/addressbook/exceptions/UnhandledUserChoiceException.java index e97f20a..b2149bb 100644 --- a/Addressbook/src/org/mxchange/addressbook/UnhandledUserChoiceException.java +++ b/Addressbook/src/org/mxchange/addressbook/exceptions/UnhandledUserChoiceException.java @@ -1,30 +1,30 @@ -/* - * 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.addressbook; - -/** - * 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 { - - public UnhandledUserChoiceException (final String message) { - super(message); - } -} +/* + * 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.addressbook.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 { + + public UnhandledUserChoiceException (final String message) { + super(message); + } +} diff --git a/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java b/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java index da2fe32..8dc33aa 100644 --- a/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java +++ b/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java @@ -21,11 +21,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; -import org.mxchange.addressbook.UnhandledUserChoiceException; import org.mxchange.addressbook.client.Client; import org.mxchange.addressbook.contact.Contact; import org.mxchange.addressbook.database.frontend.contact.ContactDatabaseFrontend; import org.mxchange.addressbook.database.frontend.contact.ContactWrapper; +import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException; import org.mxchange.addressbook.manager.BaseManager; /** -- 2.39.5