]> git.mxchange.org Git - addressbook-swing.git/blobdiff - Addressbook/src/org/mxchange/addressbook/database/backend/csv/CsvDatabaseBackend.java
Continued:
[addressbook-swing.git] / Addressbook / src / org / mxchange / addressbook / database / backend / csv / CsvDatabaseBackend.java
index a070abba32179299fc23f331acf336c0161215da..8a026e1372aa01698654873d3400b250140a40d1 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,54 @@ 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
+     * Get length of underlaying file\r
+     *\r
+     * @return Length of underlaying file\r
+     */\r
     @Override\r
-    public void rewind () {\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
+        this.getLogger().trace("CALLED!");\r
+\r
        try {\r
            // Rewind underlaying database file\r
            this.storageFile.seek(0);\r
@@ -76,6 +130,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 +141,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 +155,186 @@ 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.writeChars(str);\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
+       // Instance list\r
+       // @TODO The maximum length could be guessed from file size?\r
+       List<Contact> list = new ArrayList<>();\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
+                       // Is it own contact?\r
+                       if (true == bool) {\r
+                           // Own entry\r
+                           contact = new UserContact();\r
+                       } else {\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
+                   default: // New data entry\r
+                       this.getLogger().warn("Will not handle unknown data " + strippedToken + " at index " + count);\r
+                       break;\r
+               }\r
+\r
+               // Increment counter for next round\r
+               count++;\r
+           }\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 (IOException ex) {\r
+           this.getLogger().catching(ex);\r
+       }\r
+\r
+       // Return read string or null\r
+       return input;\r
     }\r
 }\r