]> git.mxchange.org Git - jfinancials-lib.git/blobdiff - Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvDatabaseBackend.java
Added a lot stuff:
[jfinancials-lib.git] / Addressbook / src / org / mxchange / addressbook / database / backend / csv / CsvDatabaseBackend.java
index a070abba32179299fc23f331acf336c0161215da..0bc97f3a78b9d12436195296e223d2ce7c44639e 100644 (file)
@@ -21,6 +21,14 @@ import java.io.FileNotFoundException;
 import java.io.IOException;\r
 import java.io.RandomAccessFile;\r
 import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.StringTokenizer;\r
+import org.mxchange.addressbook.BadTokenException;\r
+import org.mxchange.addressbook.contact.Contact;\r
+import org.mxchange.addressbook.contact.book.BookContact;\r
+import org.mxchange.addressbook.contact.user.UserContact;\r
 import org.mxchange.addressbook.database.backend.BaseDatabaseBackend;\r
 import org.mxchange.addressbook.database.storage.Storeable;\r
 import org.mxchange.addressbook.database.storage.csv.StoreableCsv;\r
@@ -67,8 +75,68 @@ public class CsvDatabaseBackend extends BaseDatabaseBackend implements CsvBacken
        this.getLogger().debug(MessageFormat.format("Database for {0} has been initialized.", tableName));\r
     }\r
 \r
+    /**\r
+     * Gets an iterator for contacts\r
+     * \r
+     * @return Iterator for contacts\r
+     * @throws org.mxchange.addressbook.BadTokenException If the underlaying method has found an invalid token\r
+     */\r
+    @Override\r
+    public Iterator<Contact> contactIterator () throws BadTokenException {\r
+       /*\r
+        * Then read the file into RAM (yes, not perfect for >1000 entries ...)\r
+        * and get a List back.\r
+        */\r
+       List<Contact> list = this.readContactList();\r
+\r
+       // Get iterator from list and return it\r
+       return list.iterator();\r
+    }\r
+\r
+    /**\r
+     * Shuts down this backend\r
+     */\r
+    @Override\r
+    public void doShutdown () {\r
+       try {\r
+           // Close file\r
+           this.storageFile.close();\r
+       } catch (final IOException ex) {\r
+           this.getLogger().catching(ex);\r
+           System.exit(1);\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Get length of underlaying file\r
+     *\r
+     * @return Length of underlaying file\r
+     */\r
+    @Override\r
+    public long length () {\r
+       long length = 0;\r
+       \r
+       try {\r
+           length = this.storageFile.length();\r
+           this.getLogger().debug(MessageFormat.format("length={0}", length));\r
+       } catch (final IOException ex) {\r
+           // Length cannot be determined\r
+           this.getLogger().catching(ex);\r
+           System.exit(1);\r
+       }\r
+       \r
+       // Return result\r
+        this.getLogger().trace(MessageFormat.format("length={0} : EXIT!", length));\r
+       return length;\r
+    }\r
+\r
+    /**\r
+     * Rewinds backend\r
+     */\r
     @Override\r
-    public void rewind () {\r
+    public void rewind (){\r
+        this.getLogger().trace("CALLED!");\r
+\r
        try {\r
            // Rewind underlaying database file\r
            this.storageFile.seek(0);\r
@@ -76,6 +144,8 @@ public class CsvDatabaseBackend extends BaseDatabaseBackend implements CsvBacken
            this.getLogger().catching(ex);\r
            System.exit(1);\r
        }\r
+\r
+       this.getLogger().trace("EXIT!");\r
     }\r
 \r
     /**\r
@@ -85,7 +155,7 @@ public class CsvDatabaseBackend extends BaseDatabaseBackend implements CsvBacken
      * @throws java.io.IOException From "inner" class\r
      */\r
     @Override\r
-    public void store (final Storeable object) throws IOException{\r
+    public void store (final Storeable object) throws IOException {\r
        // Make sure the instance is there (DataOutput flawor)\r
        assert(this.storageFile instanceof DataOutput);\r
 \r
@@ -99,6 +169,324 @@ public class CsvDatabaseBackend extends BaseDatabaseBackend implements CsvBacken
        this.getLogger().debug(MessageFormat.format("str({0})={1}", str.length(), str));\r
 \r
        // The string is now a valid CSV string\r
-       this.storageFile.writeUTF(str);\r
+       this.storageFile.writeBytes(str);\r
+    }\r
+\r
+    /**\r
+     * Adds given contact to list\r
+     * \r
+     * @param contact Contact instance to add\r
+     * @param list List instance\r
+     */\r
+    private void addContactToList (final Contact contact, final List<Contact> list) {\r
+       // Debug message\r
+       this.getLogger().debug(MessageFormat.format("contact={0}", contact));\r
+\r
+       // Is the contact read?\r
+       if (contact instanceof Contact) {\r
+           // Then add it\r
+           boolean added = list.add(contact);\r
+\r
+           // Debug message\r
+           this.getLogger().debug(MessageFormat.format("contact={0} added={1}", contact, added));\r
+\r
+           // Has it been added?\r
+           if (!added) {\r
+               // Not added\r
+               this.getLogger().warn("Contact object has not been added.");\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Checks whether end of file has been reached\r
+     * \r
+     * @return Whether lines are left to read\r
+     */\r
+    private boolean isEndOfFile () {\r
+       // Default is EOF\r
+       boolean isEof = true;\r
+\r
+       try {\r
+           isEof = (this.storageFile.getFilePointer() >= this.length());\r
+       } catch (final IOException ex) {\r
+           // Length cannot be determined\r
+           this.getLogger().catching(ex);\r
+       }\r
+\r
+       // Return status\r
+       this.getLogger().trace(MessageFormat.format("isEof={0} : EXIT!", isEof));\r
+       return isEof;\r
+    }\r
+\r
+    /**\r
+     * Reads the database file, if available, and adds all read lines into\r
+     * the list.\r
+     * \r
+     * @return A list with Contact instances\r
+     */\r
+    private List<Contact> readContactList () throws BadTokenException {\r
+       this.getLogger().trace("CALLED!");\r
+\r
+       // First rewind\r
+       this.rewind();\r
+\r
+       // Get file size and divide it by 140 (possible average length of one line)\r
+       int lines = Math.round(this.length() / 140 + 0.5f);\r
+\r
+       // Debug message\r
+       this.getLogger().debug(MessageFormat.format("lines={0}", lines));\r
+\r
+       // Instance list\r
+       // @TODO The maximum length could be guessed from file size?\r
+       List<Contact> list = new ArrayList<>(lines);\r
+\r
+       // Init variables\r
+       StringTokenizer tokenizer;\r
+       String line;\r
+\r
+       // Read all lines\r
+       while (!this.isEndOfFile()) {\r
+           // Then read a line\r
+           line = this.readLine();\r
+\r
+           // Debug message\r
+           this.getLogger().debug(MessageFormat.format("line={0}", line));\r
+\r
+           // Then tokenize it\r
+           // @TODO Move this into separate method\r
+           tokenizer = new StringTokenizer(line, ";");\r
+\r
+           // Count round\r
+           int count = 0;\r
+\r
+           // Init contact object\r
+           Contact contact = null;\r
+\r
+           // The tokens are now available, so get all\r
+           while (tokenizer.hasMoreElements()) {\r
+               // Get next token\r
+               String token = tokenizer.nextToken();\r
+\r
+               // Debug message\r
+               this.getLogger().debug(MessageFormat.format("token={0}", token));\r
+\r
+               // Verify token, it must have double-quotes on each side\r
+               if ((!token.startsWith("\"")) || (!token.endsWith("\""))) {\r
+                   // Something bad was read\r
+                   throw new BadTokenException(MessageFormat.format("Token {0} has not double-quotes on both ends.", token));\r
+               }\r
+\r
+               // All fine, so remove it\r
+               String strippedToken = token.substring(1, token.length() - 1);\r
+\r
+               // Is the string's content "null"?\r
+               if (strippedToken.equals("null")) {\r
+                   // Debug message\r
+                   this.getLogger().debug(MessageFormat.format("strippedToken={0} - NULL!", strippedToken));\r
+\r
+                   // This needs to be set to null\r
+                   strippedToken = null;\r
+               }\r
+\r
+               // Debug message\r
+               this.getLogger().debug(MessageFormat.format("strippedToken={0}", strippedToken));\r
+\r
+               // Init number/string data values\r
+               String strData = strippedToken;\r
+               Long num = null;\r
+               Boolean bool = null;\r
+               char gender = '?';\r
+               \r
+               // Now, let's try a number check, if no null\r
+               if (strippedToken != null) {\r
+                   // Okay, no null, maybe the string bears a decimal number?\r
+                   try {\r
+                       num = Long.valueOf(strippedToken);\r
+\r
+                       // Debug message\r
+                       this.getLogger().debug(MessageFormat.format("strippedToken={0} - NUMBER!", strippedToken));\r
+                   } catch (final NumberFormatException ex) {\r
+                       // No number, then set default\r
+                       num = null;\r
+                   }\r
+               }\r
+               \r
+               // Now, let's try a boolean check, if no null\r
+               if ((strippedToken != null) && (num == null) && ((strippedToken.equals("true")) || (strippedToken.equals("false")))) {\r
+                   // Debug message\r
+                   this.getLogger().debug(MessageFormat.format("strippedToken={0} - BOOLEAN!", strippedToken));\r
+\r
+                   // parseBoolean() is relaxed, so no exceptions\r
+                   bool = Boolean.valueOf(strippedToken);\r
+               }\r
+               \r
+               // Now, let's try a boolean check, if no null\r
+               if ((strippedToken != null) && (num == null) && (bool == null) && ((strippedToken.equals("M")) || (strippedToken.equals("F")) || (strippedToken.equals("C")))) {\r
+                   // Get first character\r
+                   gender = strippedToken.charAt(0);\r
+               }\r
+\r
+               // Now it depends on the counter which position we need to check\r
+               switch (count) {\r
+                   case 0: // isOwnContact\r
+                       assert((bool instanceof Boolean));\r
+\r
+                       // Debug message\r
+                       this.getLogger().debug(MessageFormat.format("bool={0}", bool));\r
+\r
+                       // Is it own contact?\r
+                       if (true == bool) {\r
+                           // Debug message\r
+                           this.getLogger().debug("Creating UserContact object ...");\r
+\r
+                           // Own entry\r
+                           contact = new UserContact();\r
+                       } else {\r
+                           // Debug message\r
+                           this.getLogger().debug("Creating BookContact object ...");\r
+\r
+                           // Other contact\r
+                           contact = new BookContact();\r
+                       }\r
+                       break;\r
+\r
+                   case 1: // Gender\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+                       assert(gender != '?') : "Gender is not detected.";\r
+\r
+                       // Update data\r
+                       contact.updateNameData(gender, null, null, null);\r
+                       break;\r
+\r
+                   case 2: // Surname\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+                       assert(gender != '?') : "Gender is not detected.";\r
+\r
+                       // Update data\r
+                       contact.updateNameData(gender, strippedToken, null, null);\r
+                       break;\r
+\r
+                   case 3: // Family name\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+                       assert(gender != '?') : "Gender is not detected.";\r
+\r
+                       // Update data\r
+                       contact.updateNameData(gender, null, strippedToken, null);\r
+                       break;\r
+\r
+                   case 4: // Company name\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+                       assert(gender != '?') : "Gender is not detected.";\r
+\r
+                       // Update data\r
+                       contact.updateNameData(gender, null, null, strippedToken);\r
+                       break;\r
+\r
+                   case 5: // Street number\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateAddressData(strippedToken, 0, null, null);\r
+                       break;\r
+\r
+                   case 6: // ZIP code\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateAddressData(null, num, null, null);\r
+                       break;\r
+\r
+                   case 7: // City name\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateAddressData(null, 0, strippedToken, null);\r
+                       break;\r
+\r
+                   case 8: // Country code\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateAddressData(null, 0, null, strippedToken);\r
+                       break;\r
+\r
+                   case 9: // Phone number\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateOtherData(strippedToken, null, null, null, null, null);\r
+                       break;\r
+\r
+                   case 10: // Fax number\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateOtherData(null, strippedToken, null, null, null, null);\r
+                       break;\r
+\r
+                   case 11: // Cellphone number\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateOtherData(null, null, strippedToken, null, null, null);\r
+                       break;\r
+\r
+                   case 12: // Email address\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateOtherData(null, null, null, strippedToken, null, null);\r
+                       break;\r
+\r
+                   case 13: // Birthday\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateOtherData(null, null, null, null, strippedToken, null);\r
+                       break;\r
+\r
+                   case 14: // Birthday\r
+                       assert(contact instanceof Contact) : "First token was not boolean";\r
+\r
+                       // Update data\r
+                       contact.updateOtherData(null, null, null, null, null, strippedToken);\r
+                       break;\r
+\r
+                   default: // New data entry\r
+                       this.getLogger().warn(MessageFormat.format("Will not handle unknown data {0} at index {1}", strippedToken, count));\r
+                       break;\r
+               }\r
+\r
+               // Increment counter for next round\r
+               count++;\r
+           }\r
+\r
+           // Add contact\r
+           this.addContactToList(contact, list);\r
+       }\r
+\r
+       // Return finished list\r
+       this.getLogger().trace(MessageFormat.format("list.size()={0} : EXIT!", list.size()));\r
+       return list;\r
+    }\r
+\r
+    /**\r
+     * Reads a line from file base\r
+     *\r
+     * @return Read line from file\r
+     */\r
+    private String readLine () {\r
+       // Init input\r
+       String input = null;\r
+\r
+       try {\r
+           input = this.storageFile.readLine();\r
+       } catch (final IOException ex) {\r
+           this.getLogger().catching(ex);\r
+       }\r
+\r
+       // Return read string or null\r
+       return input;\r
     }\r
 }\r