]> git.mxchange.org Git - jaddressbook-share-lib.git/blob - Addressbook/src/org/mxchange/addressbook/database/frontend/contact/AddressbookContactDatabaseFrontend.java
97593c63b880bce0b96f052c36b4c3abeff53445
[jaddressbook-share-lib.git] / Addressbook / src / org / mxchange / addressbook / database / frontend / contact / AddressbookContactDatabaseFrontend.java
1 /*
2  * Copyright (C) 2015 Roland Haeder
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 package org.mxchange.addressbook.database.frontend.contact;
18
19 import java.io.IOException;
20 import java.sql.SQLException;
21 import java.text.MessageFormat;
22 import java.util.Iterator;
23 import java.util.StringTokenizer;
24 import org.mxchange.addressbook.contact.book.BookContact;
25 import org.mxchange.addressbook.contact.user.UserContact;
26 import org.mxchange.addressbook.database.contact.AddressbookContactDatabaseConstants;
27 import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
28 import org.mxchange.addressbook.manager.contact.AddressbookContactManager;
29 import org.mxchange.jcore.contact.Contact;
30 import org.mxchange.jcore.contact.Gender;
31 import org.mxchange.jcore.database.frontend.BaseDatabaseFrontend;
32 import org.mxchange.jcore.database.storage.Storeable;
33 import org.mxchange.jcore.exceptions.BadTokenException;
34 import org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException;
35
36 /**
37  * Stores and retrieves Contact instances
38  *
39  * @author Roland Haeder
40  */
41 public class AddressbookContactDatabaseFrontend extends BaseDatabaseFrontend implements AddressbookContactFrontend {
42
43         /**
44          * Constructor which accepts a contact manager
45          *
46          * @param manager Manager instance
47          */
48         public AddressbookContactDatabaseFrontend (final AddressbookContactManager manager) {
49                 // Call own constructor
50                 this();
51
52                 // Trace message
53                 this.getLogger().trace(MessageFormat.format("manager={0} - CALLED!", manager)); //NOI18N
54
55                 // Manager instance must not be null
56                 if (manager == null) {
57                         // Abort here
58                         throw new NullPointerException("manager is null"); //NOI18N
59                 }
60
61                 // Set contact manager
62                 this.setContactManager(manager);
63         }
64
65         /**
66          * Basic constrcutor
67          */
68         protected AddressbookContactDatabaseFrontend () {
69                 // Trace message
70                 this.getLogger().trace("CALLED!"); //NOI18N
71
72                 // Set "table" name
73                 this.setTableName("contacts"); //NOI18N
74
75                 try {
76                         // Initalize backend
77                         this.initBackend();
78                 } catch (final UnsupportedDatabaseBackendException ex) {
79                         // Abort program
80                         this.abortProgramWithException(ex);
81                 } catch (final SQLException ex) {
82                         // Abort here
83                         this.abortProgramWithException(ex);
84                 }
85         }
86
87         /**
88          * Adds given contact instance to database
89          *
90          * @param contact Contact instance
91          * @throws org.mxchange.addressbook.exceptions.ContactAlreadyAddedException If the contact instance is already found
92          */
93         @Override
94         public void addContact (final Contact contact) throws ContactAlreadyAddedException {
95                 // Trace message
96                 this.getLogger().trace("CALLED!"); //NOI18N
97
98                 // Make sure the contact is set
99                 if (contact == null) {
100                         // Abort here
101                         throw new NullPointerException("contact is null"); //NOI18N
102                 }
103
104                 try {
105                         // First check if the contact is there
106                         if (this.isContactFound(contact)) {
107                                 // Already there
108                                 throw new ContactAlreadyAddedException(contact);
109                         }
110
111                         // Then add it
112                         this.getBackend().store((Storeable) contact);
113                 } catch (final IOException ex) {
114                         // Abort here
115                         this.abortProgramWithException(ex);
116                 } catch (final BadTokenException ex) {
117                         // Abort here
118                         this.abortProgramWithException(ex);
119                 }
120
121                 // Trace message
122                 this.getLogger().trace("CALLED!"); //NOI18N
123         }
124
125         /**
126          * Shuts down the database layer
127          */
128         @Override
129         public void doShutdown () {
130                 // Trace message
131                 this.getLogger().trace("CALLED!"); //NOI18N
132
133                 // Shutdown backend
134                 this.getBackend().doShutdown();
135
136                 // Trace message
137                 this.getLogger().trace("EXIT!"); //NOI18N
138         }
139
140         /**
141          * Some "getter" for total contact count
142          *
143          * @return Total contact count
144          */
145         @Override
146         public int getContactsCount () throws SQLException {
147                 // And deligate to backend
148                 return this.getBackend().getTotalCount(); //NOI18N
149         }
150
151         /**
152          * Some "getter" for own contact instance
153          *
154          * @return Own contact instance
155          */
156         @Override
157         public Contact getOwnContact () {
158                 // Trace message
159                 this.getLogger().trace("CALLED!"); //NOI18N
160
161                 // Get row index back from backend
162                 int rowIndex = this.getBackend().getRowIndexFromColumn(AddressbookContactDatabaseConstants.COLUMN_NAME_OWN_CONTACT, true);
163
164                 // Debug message
165                 this.getLogger().debug(MessageFormat.format("rowIndex={0}", rowIndex));
166
167                 // Init instance
168                 Contact contact = null;
169
170                 try {
171                         // Now simply read the row
172                         contact = (Contact) this.getBackend().readRow(rowIndex);
173                 } catch (final BadTokenException ex) {
174                         // Bad token found
175                         this.abortProgramWithException(ex);
176                 }
177
178                 // Trace message
179                 this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact));
180
181                 // Return it
182                 return contact;
183         }
184
185         /**
186          * Checks if given Contact is found
187          * 
188          * @param contact Contact instance to check
189          * @return Whether the given Contact instance is found
190          */
191         @Override
192         public boolean isContactFound (final Contact contact) throws BadTokenException {
193                 // Trace message
194                 this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
195
196                 // contact should not be null
197                 if (contact == null) {
198                         // Abort here
199                         throw new NullPointerException("contact is null"); //NOI18N
200                 }
201
202                 // Default is not found
203                 boolean isFound = false;
204
205                 // Start iteration
206                 Iterator<? extends Storeable> iterator = this.getBackend().iterator();
207
208                 // Check all entries
209                 while (iterator.hasNext()) {
210                         // Get next element
211                         Contact c = (Contact) iterator.next();
212
213                         // Debug message
214                         this.getLogger().debug(MessageFormat.format("c={0},contact={1}", c, contact)); //NOI18N
215
216                         // Is it added?
217                         if (c.equals(contact)) {
218                                 // Is found
219                                 isFound = true;
220                                 break;
221                         }
222                 }
223
224                 // Trace message
225                 this.getLogger().trace(MessageFormat.format("isFound={0} - EXIT!", isFound)); //NOI18N
226
227                 // Return it
228                 return isFound;
229         }
230
231         /**
232          * Checks whether own contact is found in database
233          *
234          * @return Whether own contact is found
235          */
236         @Override
237         public boolean isOwnContactFound () throws SQLException {
238                 // Deligate this call to backend
239                 return this.getBackend().isRowFound(AddressbookContactDatabaseConstants.COLUMN_NAME_OWN_CONTACT, true);
240         }
241
242         /**
243          * Parses given line from database backend into a Storeable instance. Please
244          * note that not all backends need this.
245          *
246          * @param line Line from database backend
247          * @return A Storeable instance
248          */
249         @Override
250         public Storeable parseLineToStoreable (final String line) throws BadTokenException {
251                 // Trace message
252                 this.getLogger().trace(MessageFormat.format("line={0} - CALLED!", line)); //NOI18N
253
254                 // Call inner method
255                 Contact contact = this.parseLineToContact(line);
256
257                 // Debug message
258                 this.getLogger().debug(MessageFormat.format("contact={0}", contact));
259
260                 // Return it
261                 return (Storeable) contact;
262         }
263
264         /**
265          * Reads a single row and parses it to a contact instance
266          *
267          * @param rowIndex Row index (also how much to skip)
268          * @return Contact instance
269          */
270         @Override
271         public Contact readSingleContact (final int rowIndex) {
272                 try {
273                         // Deligate this to backend instance
274                         return (Contact) this.getBackend().readRow(rowIndex);
275                 } catch (final BadTokenException ex) {
276                         // Bad token found
277                         this.abortProgramWithException(ex);
278                 }
279
280                 // Bad state, should not be reached
281                 throw new IllegalStateException("This should not be reached");
282         }
283
284         /**
285          * Parses given line and creates a Contact instance
286          * 
287          * @param line Raw line to parse
288          *
289          * @return Contact instance
290          */
291         private Contact parseLineToContact (final String line) throws BadTokenException {
292                 // Trace message
293                 this.getLogger().trace(MessageFormat.format("line={0} - CALLED!", line)); //NOI18N
294
295                 // Init A lot variables
296                 Long num = null;
297                 Boolean bool = null;
298                 Gender gender = null;
299                 int count = 0;
300                 Contact contact = null;
301
302                 // Debug message
303                 this.getLogger().debug(MessageFormat.format("line={0}", line)); //NOI18N
304
305                 // Then tokenize it
306                 // @TODO Move this into separate method
307                 StringTokenizer tokenizer = new StringTokenizer(line, ";"); //NOI18N
308
309                 // Reset variables
310                 count = 0;
311                 contact = null;
312
313                 // The tokens are now available, so get all
314                 while (tokenizer.hasMoreElements()) {
315                         // Reset variables
316                         num = null;
317                         bool = null;
318
319                         // Get next token
320                         String token = tokenizer.nextToken();
321
322                         // If char " is at pos 2 (0,1,2), then cut it of there
323                         if ((token.charAt(0) != '"') && (token.charAt(2) == '"')) {
324                                 // UTF-8 writer characters found
325                                 token = token.substring(2);
326                         }
327
328                         // Debug message
329                         this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
330
331                         // Verify token, it must have double-quotes on each side
332                         if ((!token.startsWith("\"")) || (!token.endsWith("\""))) { //NOI18N
333                                 // Something bad was read
334                                 throw new BadTokenException(token, count); //NOI18N
335                         }
336
337                         // All fine, so remove it
338                         String strippedToken = token.substring(1, token.length() - 1);
339
340                         // Is the string's content "null"?
341                         if (strippedToken.equals("null")) { //NOI18N
342                                 // Debug message
343                                 this.getLogger().debug(MessageFormat.format("strippedToken={0} - NULL!", strippedToken)); //NOI18N
344
345                                 // This needs to be set to null
346                                 strippedToken = null;
347                         }
348
349                         // Debug message
350                         this.getLogger().debug(MessageFormat.format("strippedToken={0}", strippedToken)); //NOI18N
351
352                         // Now, let's try a number check, if no null
353                         if (strippedToken != null) {
354                                 // Okay, no null, maybe the string bears a decimal number?
355                                 try {
356                                         num = Long.valueOf(strippedToken);
357
358                                         // Debug message
359                                         this.getLogger().debug(MessageFormat.format("strippedToken={0} - NUMBER!", strippedToken)); //NOI18N
360                                 } catch (final NumberFormatException ex) {
361                                         // No number, then set default
362                                         num = null;
363                                 }
364                         }
365
366                         // Now, let's try a boolean check, if no null
367                         if ((strippedToken != null) && (num == null) && ((strippedToken.equals("true")) || (strippedToken.equals("false")))) { //NOI18N
368                                 // Debug message
369                                 this.getLogger().debug(MessageFormat.format("strippedToken={0} - BOOLEAN!", strippedToken)); //NOI18N
370
371                                 // parseBoolean() is relaxed, so no exceptions
372                                 bool = Boolean.valueOf(strippedToken);
373                         }
374
375                         // Debug message
376                         this.getLogger().debug(MessageFormat.format("strippedToken={0},num={1},bool={2}", strippedToken, num, bool)); //NOI18N
377
378                         // Now, let's try a gender check, if no null
379                         if ((strippedToken != null) && (num == null) && (bool == null) && (Gender.valueOf(strippedToken) instanceof Gender)) { //NOI18N
380                                 // Get first character
381                                 gender = Gender.valueOf(strippedToken);
382
383                                 // Debug message
384                                 this.getLogger().debug(MessageFormat.format("strippedToken={0},gender={1}", strippedToken, gender)); //NOI18N
385
386                                 // This instance must be there
387                                 assert (gender instanceof Gender) : MessageFormat.format("gender is not set by Gender.fromChar({0})", strippedToken); //NOI18N
388                         }
389
390                         // Now it depends on the counter which position we need to check
391                         switch (count) {
392                                 case 0: // isOwnContact
393                                         assert ((bool instanceof Boolean));
394
395                                         // Debug message
396                                         this.getLogger().debug(MessageFormat.format("bool={0}", bool)); //NOI18N
397
398                                         // Is it own contact?
399                                         if (true == bool) {
400                                                 // Debug message
401                                                 this.getLogger().debug("Creating UserContact object ..."); //NOI18N
402
403                                                 // Own entry
404                                                 contact = new UserContact();
405                                         } else {
406                                                 // Debug message
407                                                 this.getLogger().debug("Creating BookContact object ..."); //NOI18N
408
409                                                 // Other contact
410                                                 contact = new BookContact();
411                                         }
412                                         break;
413
414                                 case 1: // Gender
415                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
416
417                                         // Update data
418                                         contact.setGender(gender);
419                                         break;
420
421                                 case 2: // Surname
422                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
423                                         assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
424
425                                         // Update data
426                                         contact.setSurname(strippedToken);
427                                         break;
428
429                                 case 3: // Family name
430                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
431                                         assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
432
433                                         // Update data
434                                         contact.setFamilyName(strippedToken);
435                                         break;
436
437                                 case 4: // Company name
438                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
439                                         assert (gender instanceof Gender) : "gender instance is not set"; //NOI18N
440
441                                         // Update data
442                                         contact.setCompanyName(strippedToken);
443                                         break;
444
445                                 case 5: // Street number
446                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
447
448                                         // Update data
449                                         contact.setHouseNumber(num);
450                                         break;
451
452                                 case 6: // ZIP code
453                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
454
455                                         // Update data
456                                         contact.setZipCode(num);
457                                         break;
458
459                                 case 7: // City name
460                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
461
462                                         // Update data
463                                         contact.setCity(strippedToken);
464                                         break;
465
466                                 case 8: // Country code
467                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
468
469                                         // Update data
470                                         contact.setCountryCode(strippedToken);
471                                         break;
472
473                                 case 9: // Phone number
474                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
475
476                                         // Update data
477                                         contact.setPhoneNumber(strippedToken);
478                                         break;
479
480                                 case 10: // Fax number
481                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
482
483                                         // Update data
484                                         contact.setFaxNumber(strippedToken);
485                                         break;
486
487                                 case 11: // Cellphone number
488                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
489
490                                         // Update data
491                                         contact.setCellphoneNumber(strippedToken);
492                                         break;
493
494                                 case 12: // Email address
495                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
496
497                                         // Update data
498                                         contact.setEmailAddress(strippedToken);
499                                         break;
500
501                                 case 13: // Birthday
502                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
503
504                                         // Update data
505                                         contact.setBirthday(strippedToken);
506                                         break;
507
508                                 case 14: // Comment
509                                         assert (contact instanceof Contact) : "First token was not boolean"; //NOI18N
510
511                                         // Update data
512                                         contact.setComment(strippedToken);
513                                         break;
514
515                                 default: // New data entry
516                                         this.getLogger().warn(MessageFormat.format("Will not handle unknown data {0} at index {1}", strippedToken, count)); //NOI18N
517                                         break;
518                         }
519
520                         // Increment counter for next round
521                         count++;
522                 }
523
524                 // Trace message
525                 this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
526
527                 // Return finished instance
528                 return contact;
529         }
530 }