]> git.mxchange.org Git - jcore.git/blob - src/org/mxchange/jcore/BaseFrameworkSystem.java
added debug message
[jcore.git] / src / org / mxchange / jcore / BaseFrameworkSystem.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.jcore;
18
19 import java.io.BufferedReader;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStreamReader;
24 import java.io.PrintWriter;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.text.MessageFormat;
29 import java.util.Arrays;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Properties;
34 import java.util.ResourceBundle;
35 import java.util.StringTokenizer;
36 import org.apache.logging.log4j.LogManager;
37 import org.apache.logging.log4j.Logger;
38 import org.mxchange.jcore.application.Application;
39 import org.mxchange.jcore.client.Client;
40 import org.mxchange.jcore.contact.Contact;
41 import org.mxchange.jcore.database.backend.DatabaseBackend;
42 import org.mxchange.jcore.database.frontend.DatabaseFrontend;
43 import org.mxchange.jcore.database.storage.Storeable;
44 import org.mxchange.jcore.manager.Manageable;
45
46 /**
47  * General class
48  *
49  * @author Roland Haeder
50  */
51 public class BaseFrameworkSystem implements FrameworkInterface {
52
53         /**
54          * Bundle instance
55          */
56         private static ResourceBundle bundle;
57
58         /**
59          * Instance for own properties
60          */
61         private static final Properties properties = new Properties(System.getProperties());
62
63         /**
64          * Self instance
65          */
66         private static FrameworkInterface selfInstance;
67
68         /**
69          * Class' logger
70          */
71         private final Logger LOG;
72
73         /**
74          * Application instance
75          */
76         private Application application;
77
78         /**
79          * Instance for database backend
80          */
81         private DatabaseBackend backend;
82
83         /**
84          * Client instance
85          */
86         private Client client;
87
88         /**
89          * Contact instance
90          */
91         private Contact contact;
92
93         /**
94          * Manager instance
95          */
96         private Manageable manager;
97
98         /**
99          * Name of used database table, handled over to backend
100          */
101         private String tableName;
102
103         /**
104          * DatabaseFrontend instance
105          */
106         private DatabaseFrontend frontend;
107
108         /**
109          * Initialize object
110          */
111         {
112                 LOG = LogManager.getLogger(this);
113         }
114
115         /**
116          * No instances can be created of this class
117          */
118         protected BaseFrameworkSystem () {
119                 // Set own instance
120                 this.setSelfInstance();
121         }
122
123         /**
124          * Getter for this application
125          *
126          * @return Instance from this application
127          */
128         public static final FrameworkInterface getInstance () {
129                 // Return it
130                 return selfInstance;
131         }
132
133         /**
134          * Application instance
135          *
136          * @return the application
137          */
138         @Override
139         public final Application getApplication () {
140                 return this.application;
141         }
142
143         /**
144          * Getter for logger
145          *
146          * @return Logger
147          */
148         @Override
149         public final Logger getLogger () {
150                 return this.LOG;
151         }
152
153         /**
154          * Manager instance
155          *
156          * @return the contactManager
157          */
158         @Override
159         public final Manageable getManager () {
160                 return this.manager;
161         }
162
163         /**
164          * Getter for human-readable string from given key
165          *
166          * @param key Key to return
167          * @return Human-readable message
168          */
169         @Override
170         public final String getMessageStringFromKey (final String key) {
171                 // Return message
172                 return this.getBundle().getString(key);
173         }
174
175         /**
176          * Some "getter" for target class instance from given name.
177          *
178          * @param instance Instance to iterate on
179          * @param targetClass Class name to look for
180          * @return Class instance
181          */
182         @SuppressWarnings("unchecked")
183         private Class<? extends FrameworkInterface> getClassFromTarget (final FrameworkInterface instance, final String targetClass) {
184                 // Trace message
185                 this.getLogger().debug(MessageFormat.format("instance={0},targetClass={1}", instance, targetClass)); //NOI18N
186
187                 // Instance reflaction of this class
188                 Class<? extends FrameworkInterface> c = instance.getClass();
189
190                 // Analyze class
191                 while (!targetClass.equals(c.getSimpleName())) {
192                         // Debug message
193                         this.getLogger().debug(MessageFormat.format("c={0}", c.getSimpleName())); //NOI18N
194
195                         // Get super class (causes unchecked warning)
196                         c = (Class<? extends FrameworkInterface>) c.getSuperclass();
197                 }
198
199                 // Trace message
200                 this.getLogger().trace(MessageFormat.format("c={0} - EXIT!", c)); //NOI18N
201
202                 // Return it
203                 return c;
204         }
205
206         /**
207          * Some "getter" for a Method instance from given method name
208          *
209          * @param instance Actual instance to call
210          * @param targetClass Target class name
211          * @param methodName Method name
212          * @return A Method instance
213          */
214         private Method getMethodFromName (final FrameworkInterface instance, final String targetClass, final String methodName) throws NoSuchMethodException {
215                 // Trace messahe
216                 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
217
218                 // Get target class instance
219                 Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
220
221                 // Init field instance
222                 Method method = c.getDeclaredMethod(methodName, new Class<?>[0]);
223
224                 // Assert on field
225                 assert (method instanceof Method) : "method is not a Method instance"; //NOI18N
226
227                 // Trace message
228                 this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method)); //NOI18N
229
230                 // Return it
231                 return method;
232         }
233
234         /**
235          * Some "getter" for a Method instance from given method name
236          *
237          * @param instance Actual instance to call
238          * @param targetClass Target class name
239          * @param methodName Method name
240          * @param type Type reflection to check type from
241          * @return A Method instance
242          */
243         private Method getMethodFromName (final FrameworkInterface instance, final String targetClass, final String methodName, final Class<?> type) throws NoSuchMethodException {
244                 // Trace messahe
245                 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1},type={2}", targetClass, methodName, type)); //NOI18N
246
247                 // Get target class instance
248                 Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
249
250                 // Init field instance
251                 Method method = c.getDeclaredMethod(methodName, type);
252
253                 // Assert on field
254                 assert (method instanceof Method) : "method is not a Method instance"; //NOI18N
255
256                 // Trace message
257                 this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method)); //NOI18N
258
259                 // Return it
260                 return method;
261         }
262
263         /**
264          * Setter for self instance
265          */
266         private void setSelfInstance () {
267                 // Need to set it here
268                 selfInstance = this;
269         }
270
271         /**
272          * Aborts program with given exception
273          *
274          * @param throwable Any type of Throwable
275          */
276         protected final void abortProgramWithException (final Throwable throwable) {
277                 // Log exception ...
278                 this.logException(throwable);
279
280                 // .. and exit
281                 System.exit(1);
282         }
283
284         /**
285          * Application instance
286          *
287          * @param application the application to set
288          */
289         protected final void setApplication (final Application application) {
290                 this.application = application;
291         }
292
293         /**
294          * Client instance
295          *
296          * @return the client
297          */
298         @Override
299         public final Client getClient () {
300                 return this.client;
301         }
302
303         /**
304          * Getter for bundle instance
305          *
306          * @return Resource bundle
307          */
308         protected final ResourceBundle getBundle () {
309                 return BaseFrameworkSystem.bundle;
310         }
311
312         /**
313          * Setter for bundle instance
314          *
315          * @param bundle the bundle to set
316          */
317         protected static void setBundle (final ResourceBundle bundle) {
318                 BaseFrameworkSystem.bundle = bundle;
319         }
320
321         /**
322          * Client instance
323          *
324          * @param client the client to set
325          */
326         protected final void setClient (final Client client) {
327                 this.client = client;
328         }
329
330         /**
331          * Name of used database table, handled over to backend
332          *
333          * @return the tableName
334          */
335         public final String getTableName () {
336                 return this.tableName;
337         }
338
339         /**
340          * Checks if given boolean field is available and set to same value
341          *
342          * @param columnName Column name to check
343          * @param bool Boolean value
344          * @return Whether all conditions are met
345          * @throws NoSuchMethodException May be thrown by some implementations
346          * @throws java.lang.IllegalAccessException If the method cannot be accessed
347          * @throws java.lang.reflect.InvocationTargetException Any other problems?
348          */
349         @Override
350         public boolean isFieldValueEqual (final String columnName, final boolean bool) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
351                 // Not implemented
352                 throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0},bool={1}", columnName, bool)); //NOI18N
353         }
354
355         /**
356          * Log exception
357          *
358          * @param exception Exception to log
359          */
360         @Override
361         public final void logException (final Throwable exception) {
362                 // Log this exception
363                 this.getLogger().catching(exception);
364         }
365
366         /**
367          * Initializes properties with default values
368          */
369         private void initPropertiesWithDefault () {
370                 // Trace message
371                 this.getLogger().trace("CALLED!"); //NOI18N
372
373                 // Init default values:
374                 // Default database backend
375                 BaseFrameworkSystem.properties.put("org.mxchange.database.backend.class", "org.mxchange.jcore.database.backend.base64.Base64CsvDatabaseBackend"); //NOI18N
376                 BaseFrameworkSystem.properties.put("org.mxchange.database.backend.storagepath", "data/"); //NOI18N
377                 BaseFrameworkSystem.properties.put("org.mxchange.database.datasource.name", ""); //NOI18N
378
379                 // For MySQL backend
380                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.host", "localhost"); //NOI18N
381                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.dbname", "test"); //NOI18N
382                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.login", ""); //NOI18N
383                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.password", ""); //NOI18N
384
385                 // Trace message
386                 this.getLogger().trace("EXIT!"); //NOI18N
387         }
388
389         /**
390          * Writes the properties file to disk
391          */
392         private void writePropertiesFile () throws IOException {
393                 // Trace message
394                 this.getLogger().trace("CALLED!"); //NOI18N
395
396                 // Write it
397                 BaseFrameworkSystem.properties.store(new PrintWriter(FrameworkInterface.PROPERTIES_CONFIG_FILE), "This file is automatically generated. You may wish to alter it."); //NOI18N
398
399                 // Trace message
400                 this.getLogger().trace("EXIT!"); //NOI18N
401         }
402
403         /**
404          * Converts a column name like "foo_bar" to an attribute name like "fooBar"
405          *
406          * @param columnName Column name to convert
407          * @return Attribute name
408          */
409         protected String convertColumnNameToFieldName (final String columnName) {
410                 // Trace message
411                 this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
412
413                 // First all lower case
414                 String lower = columnName.toLowerCase();
415
416                 // Then split on "_"
417                 StringTokenizer tokenizer = new StringTokenizer(lower, "_"); //NOI18N
418
419                 // Resulting string
420                 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
421
422                 // Init counter
423                 int count = 0;
424
425                 // Walk through all
426                 while (tokenizer.hasMoreTokens()) {
427                         // Get token
428                         String token = tokenizer.nextToken();
429
430                         // Is later than first element?
431                         if (count > 0) {
432                                 // Make first character upper-case
433                                 char c = token.charAt(0);
434                                 token = String.valueOf(c).toUpperCase() + token.substring(1);
435                         }
436
437                         // Add token
438                         builder.append(token);
439
440                         // Increment counter
441                         count++;
442                 }
443
444                 // Trace message
445                 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
446
447                 // Return result
448                 return builder.toString();
449         }
450
451         /**
452          * Converts a column name like "foo_bar" to a method name like "getFooBar"
453          * for non-booleans and to "isFooBar" for boolean fields.
454          *
455          * @param columnName Column name to convert
456          * @param isBool Whether the parameter is boolean
457          * @return Attribute name
458          */
459         protected String convertColumnNameToGetterMethod (final String columnName, boolean isBool) {
460                 // Trace message
461                 this.getLogger().trace(MessageFormat.format("columnName={0},isBool={1} - CALLED!", columnName, isBool)); //NOI18N
462
463                 // Then split on "_"
464                 StringTokenizer tokenizer = new StringTokenizer(columnName, "_"); //NOI18N
465
466                 // Resulting string
467                 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
468
469                 // Is it boolean?
470                 if (isBool) {
471                         // Append "is"
472                         builder.append("is"); //NOI18N
473                 } else {
474                         // Append "get"
475                         builder.append("get"); //NOI18N
476                 }
477
478                 // Walk through all
479                 while (tokenizer.hasMoreTokens()) {
480                         // Get token
481                         String token = tokenizer.nextToken();
482
483                         // Debug message
484                         this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
485
486                         // Make it upper-case
487                         char c = token.charAt(0);
488                         token = String.valueOf(c).toUpperCase() + token.substring(1);
489
490                         // Add token
491                         builder.append(token);
492                 }
493
494                 // Trace message
495                 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
496
497                 // Return result
498                 return builder.toString();
499         }
500
501         /**
502          * Converts a column name like "foo_bar" to a method name like "getFooBar"
503          * for non-booleans and to "isFooBar" for boolean fields.
504          *
505          * @param columnName Column name to convert
506          * @return Attribute name
507          */
508         protected String convertColumnNameToSetterMethod (final String columnName) {
509                 // Trace message
510                 this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
511
512                 // Then split on "_"
513                 StringTokenizer tokenizer = new StringTokenizer(columnName, "_"); //NOI18N
514
515                 // Resulting string
516                 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
517
518                 // Append "set"
519                 builder.append("set"); //NOI18N
520
521                 // Walk through all
522                 while (tokenizer.hasMoreTokens()) {
523                         // Get token
524                         String token = tokenizer.nextToken();
525
526                         // Debug message
527                         this.getLogger().debug(MessageFormat.format("token={0} - BEFORE", token)); //NOI18N
528
529                         // Make it upper-case
530                         char c = token.charAt(0);
531                         token = String.valueOf(c).toUpperCase() + token.substring(1);
532
533                         // Debug message
534                         this.getLogger().debug(MessageFormat.format("token={0} - AFTER", token)); //NOI18N
535
536                         // Add token
537                         builder.append(token);
538                 }
539
540                 // Trace message
541                 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
542
543                 // Return result
544                 return builder.toString();
545         }
546
547         /**
548          * Some "getter" for an array from given string and tokenizer
549          *
550          * @param str String to tokenize and get array from
551          * @param delimiter Delimiter
552          * @param size Size of array
553          * @return Array from tokenized string
554          * @todo Get rid of size parameter
555          */
556         protected String[] getArrayFromString (final String str, final String delimiter, final int size) {
557                 // Trace message
558                 this.getLogger().trace(MessageFormat.format("str={0},delimiter={1},size={2} - CALLED!", str, delimiter, size)); //NOI18N
559
560                 // Get tokenizer
561                 StringTokenizer tokenizer = new StringTokenizer(str, delimiter);
562
563                 // Init array and index
564                 String[] tokens = new String[size];
565                 int index = 0;
566
567                 // Run through all tokens
568                 while (tokenizer.hasMoreTokens()) {
569                         // Get current token and add it
570                         tokens[index] = tokenizer.nextToken();
571
572                         // Debug message
573                         this.getLogger().debug(MessageFormat.format("Token at index{0}: {1}", index, tokens[1])); //NOI18N
574
575                         // Increment index
576                         index++;
577                 }
578
579                 // Trace message
580                 this.getLogger().trace(MessageFormat.format("tokens({0})={1} - EXIT!", tokens.length, Arrays.toString(tokens))); //NOI18N
581
582                 // Return it
583                 return tokens;
584         }
585
586         /**
587          * Returns boolean field value from given method name by invoking it
588          *
589          * @param instance The instance to call
590          * @param targetClass Target class to look in
591          * @param methodName Method name to look for
592          * @return Boolean value from field
593          * @throws java.lang.NoSuchMethodException If the method was not found
594          * @throws java.lang.IllegalAccessException If the method cannot be accessed
595          * @throws java.lang.reflect.InvocationTargetException Some other problems?
596          */
597         protected boolean getBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
598                 // Trace messahe
599                 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
600
601                 // Get method instance
602                 Method method = this.getMethodFromName(instance, targetClass, methodName);
603
604                 // Get value from field
605                 Boolean value = (Boolean) method.invoke(instance);
606
607                 // Trace message
608                 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
609
610                 // Return value
611                 return value;
612         }
613
614         /**
615          * Sets boolean field value with given method name by invoking it
616          *
617          * @param instance The instance to call
618          * @param targetClass Target class to look in
619          * @param methodName Method name to look for
620          * @param columnName Column name
621          * @param value Boolean value from field
622          * @throws java.lang.NoSuchMethodException If the method was not found
623          * @throws java.lang.IllegalAccessException If the method cannot be accessed
624          * @throws java.lang.reflect.InvocationTargetException Some other problems?
625          */
626         protected void setBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName, final String columnName, final Boolean value) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
627                 // Trace messahe
628                 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
629
630                 // Get field type
631                 Class<?> type = this.getType(instance, targetClass, columnName);
632
633                 // Get method instance
634                 Method method = this.getMethodFromName(instance, targetClass, methodName, type);
635
636                 // Try to get the value by invoking the method
637                 method.invoke(instance, value);
638
639                 // Trace message
640                 this.getLogger().trace("EXIT!"); //NOI18N
641         }
642
643         /**
644          * Manager instance
645          *
646          * @param manager the manager instance to set
647          */
648         protected final void setContactManager (final Manageable manager) {
649                 this.manager = manager;
650         }
651
652         /**
653          * Returns any field value from given method name by invoking it
654          *
655          * @param instance The instance to call
656          * @param targetClass Target class to look in
657          * @param methodName Method name to look for
658          * @return Any value from field
659          * @throws java.lang.NoSuchMethodException If the method was not found
660          * @throws java.lang.IllegalAccessException If the method cannot be accessed
661          * @throws java.lang.reflect.InvocationTargetException Some other problems?
662          */
663         protected Object getField (final FrameworkInterface instance, final String targetClass, final String methodName) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
664                 // Trace messahe
665                 this.getLogger().trace(MessageFormat.format("instance={0},targetClass={1},methodName={2}", instance, targetClass, methodName)); //NOI18N
666
667                 // Get method to call
668                 Method method = this.getMethodFromName(instance, targetClass, methodName);
669
670                 // Debug message
671                 this.getLogger().debug(MessageFormat.format("method={0},instance={1}", method, instance)); //NOI18N
672
673                 // Get value from field
674                 Object value = method.invoke(instance);
675
676                 // Trace messahe
677                 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
678
679                 // Return value
680                 return value;
681         }
682
683         /**
684          * Sets any field value with given method name by invoking it
685          *
686          * @param instance The instance to call
687          * @param targetClass Target class to look in
688          * @param methodName Method name to look for
689          * @param columnName Column name
690          * @param value Any value from field
691          * @throws java.lang.NoSuchMethodException If the method was not found
692          * @throws java.lang.IllegalAccessException If the method cannot be accessed
693          * @throws java.lang.reflect.InvocationTargetException Some other problems?
694          */
695         protected void setField (final FrameworkInterface instance, final String targetClass, final String methodName, final String columnName, final Object value) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
696                 // Trace messahe
697                 this.getLogger().trace(MessageFormat.format("instance={0},targetClass={1},methodName={2},value={3}", instance, targetClass, methodName, value)); //NOI18N
698
699                 // Get field type
700                 Class<?> type = this.getType(instance, targetClass, columnName);
701
702                 // Debug message
703                 this.getLogger().debug(MessageFormat.format("type={0}", type)); //NOI18N
704
705                 // Init object
706                 Object object = value;
707
708                 // Is the value null?
709                 if ("null".equals(value)) { //NOI18N
710                         // Warning message
711                         this.getLogger().warn(MessageFormat.format("columnName={0} has null value.", columnName)); //NOI18N
712
713                         // Set null
714                         object = null;
715                 } else {
716                         // Hard-coded "cast" again ... :-(
717                         // @TODO Can't we get rid of this???
718                         switch (type.getSimpleName()) {
719                                 case "Long": // Long object //NOI18N
720                                         object = Long.parseLong((String) value);
721                                         break;
722
723                                 case "Float": // Float object //NOI18N
724                                         object = Float.parseFloat((String) value);
725                                         break;
726
727                                 case "Boolean": // Boolean object //NOI18N
728                                         object = Boolean.parseBoolean((String) value);
729                                         break;
730
731                                 case "String": // String object //NOI18N
732                                         break;
733
734                                 default: // Unsupported type
735                                         throw new IllegalArgumentException(MessageFormat.format("value {0} has unsupported type {1}", value, type.getSimpleName())); //NOI18N
736                         }
737                 }
738
739                 // Debug message
740                 this.getLogger().debug(MessageFormat.format("object={0}", object)); //NOI18N
741
742                 // Get method to call
743                 Method method = this.getMethodFromName(instance, targetClass, methodName, type);
744
745                 // Debug message
746                 this.getLogger().debug(MessageFormat.format("method={0},instance={1},value[{2}]={3}", method, instance, value.getClass().getSimpleName(), value)); //NOI18N
747
748                 // Get value from field
749                 method.invoke(instance, object);
750
751                 // Trace messahe
752                 this.getLogger().trace("EXIT!"); //NOI18N
753         }
754
755         /**
756          * Getter for property which must exist
757          *
758          * @param key Key to get
759          * @return Propety value
760          */
761         protected final String getProperty (final String key) {
762                 return BaseFrameworkSystem.properties.getProperty(String.format("org.mxchange.%s", key)); //NOI18N
763         }
764
765         /**
766          * Name of used database table, handled over to backend
767          *
768          * @param tableName the tableName to set
769          */
770         protected final void setTableName (final String tableName) {
771                 this.tableName = tableName;
772         }
773
774         /**
775          * Converts null to empty string or leaves original string.
776          *
777          * @param str Any string
778          * @return Empty string if null or original string
779          */
780         protected Object convertNullToEmpty (final Object str) {
781                 // Trace message
782                 this.getLogger().trace(MessageFormat.format("str={0}", str)); //NOI18N
783
784                 // Is it null?
785                 if (null == str) {
786                         // Return empty string
787                         return ""; //NOI18N
788                 }
789
790                 // Trace message
791                 this.getLogger().trace(MessageFormat.format("str={0} - EXIT!", str)); //NOI18N
792
793                 // Return it
794                 return str;
795         }
796
797         /**
798          * Creates an iterator from given instance and class name.
799          *
800          * @param instance Instance to run getter calls on
801          * @param className Class name to iterate over
802          * @return An iterator over all object's fields
803          * @throws java.lang.NoSuchMethodException If the called method does not exist
804          * @throws java.lang.IllegalAccessException If the method cannot be accessed
805          * @throws java.lang.reflect.InvocationTargetException Any other problems?
806          */
807         protected Iterator<Map.Entry<Field, Object>> fieldIterator (final Storeable instance, final String className) throws IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
808                 // Trace message
809                 this.getLogger().trace(MessageFormat.format("instance={0},className={1} - CALLED!", instance, className)); //NOI18N
810
811                 // Get all attributes from given instance
812                 Field[] fields = this.getClassFromTarget(instance, className).getDeclaredFields();
813
814                 // Debug message
815                 this.getLogger().debug(MessageFormat.format("Found {0} fields.", fields.length)); //NOI18N
816
817                 // A simple map with K=fieldName and V=Value is fine
818                 Map<Field, Object> map = new HashMap<>(fields.length);
819
820                 // Walk through all
821                 for (final Field field : fields) {
822                         // Debug log
823                         this.getLogger().debug(MessageFormat.format("field={0}", field.getName())); //NOI18N
824
825                         // Does the field start with "$"?
826                         if (field.getName().startsWith("$")) { //NOI18N
827                                 // Debug message
828                                 this.getLogger().debug(MessageFormat.format("Skipping field={0} as it starts with a dollar character.", field.getName())); //NOI18N
829
830                                 // Skip it silently
831                                 continue;
832                         }
833
834                         // Debug message
835                         this.getLogger().debug(MessageFormat.format("Calling getValueFromColumn({0}) on instance {1} ...", field.getName(), instance)); //NOI18N
836
837                         // Get value from it
838                         Object value = instance.getValueFromColumn(field.getName());
839
840                         // Debug message
841                         this.getLogger().debug(MessageFormat.format("Adding field={0},value={1}", field.getName(), value)); //NOI18N
842
843                         // Add it to list
844                         map.put(field, value);
845                 }
846
847                 // Debug message
848                 this.getLogger().debug(MessageFormat.format("Returning iterator for {0} entries ...", map.size())); //NOI18N
849
850                 // Return list iterator
851                 return map.entrySet().iterator();
852         }
853
854         /**
855          * Instance for database backend
856          *
857          * @return the backend
858          */
859         protected final DatabaseBackend getBackend () {
860                 return this.backend;
861         }
862
863         /**
864          * Instance for database backend
865          *
866          * @param backend the backend to set
867          */
868         protected final void setBackend (final DatabaseBackend backend) {
869                 this.backend = backend;
870         }
871
872         /**
873          * Getter for Contact instance
874          *
875          * @return Contact instance
876          */
877         protected final Contact getContact () {
878                 return this.contact;
879         }
880
881         /**
882          * Setter for Contact instance
883          *
884          * @param contact A Contact instance
885          */
886         protected final void setContact (final Contact contact) {
887                 this.contact = contact;
888         }
889
890         /**
891          * Getter for DatabaseFrontend instance
892          *
893          * @return DatabaseFrontend instance
894          */
895         protected final DatabaseFrontend getFrontend () {
896                 return this.frontend;
897         }
898
899         /**
900          * Setter for wrapper instance
901          *
902          * @param frontend A DatabaseFrontend instance
903          */
904         protected final void setFrontend (final DatabaseFrontend frontend) {
905                 this.frontend = frontend;
906         }
907
908         /**
909          * Initializes i18n bundles
910          */
911         protected void initBundle () {
912                 // Trace message
913                 this.getLogger().trace("CALLED!"); //NOI18N
914
915                 // Is the bundle set?
916                 if (bundle instanceof ResourceBundle) {
917                         // Is already set
918                         throw new IllegalStateException("called twice"); //NOI18N
919                 }
920
921                 // Set instance
922                 setBundle(ResourceBundle.getBundle(FrameworkInterface.I18N_BUNDLE_FILE)); // NOI18N
923
924                 // Trace message
925                 this.getLogger().trace("EXIT!"); //NOI18N
926         }
927
928         /**
929          * Prepares all properties, the file is written if it is not found
930          *
931          * @throws java.io.IOException If any IO problem occurs
932          */
933         protected void initProperties () throws IOException {
934                 // Trace message
935                 this.getLogger().trace("CALLED!"); //NOI18N
936
937                 // Debug message
938                 this.getLogger().debug(MessageFormat.format("{0} properties are loaded already.", BaseFrameworkSystem.properties.size())); //NOI18N
939
940                 // Are some properties loaded?
941                 if (!BaseFrameworkSystem.properties.isEmpty()) {
942                         // Some are already loaded, abort here
943                         return;
944                 }
945
946                 try {
947                         // Try to read it
948                         BaseFrameworkSystem.properties.load(new BufferedReader(new InputStreamReader(new FileInputStream(FrameworkInterface.PROPERTIES_CONFIG_FILE))));
949
950                         // Debug message
951                         this.getLogger().debug(MessageFormat.format("{0} properties has been loaded.", BaseFrameworkSystem.properties.size())); //NOI18N
952                 } catch (final FileNotFoundException ex) {
953                         // Debug message
954                         this.getLogger().debug(MessageFormat.format("Properties file {0} not found: {1}", FrameworkInterface.PROPERTIES_CONFIG_FILE, ex)); //NOI18N
955
956                         /*
957                          * The file is not found which is normal for first run, so
958                          * initialize default values.
959                          */
960                         this.initPropertiesWithDefault();
961
962                         // Write file
963                         this.writePropertiesFile();
964                 }
965
966                 // Trace message
967                 this.getLogger().trace("EXIT!"); //NOI18N
968         }
969
970         /**
971          * Checks whether the given field is a boolean field by probing it.
972          *
973          * @param instance Instance to call
974          * @param targetClass Target class
975          * @param columnName Column name to check
976          * @return Whether the given column name represents a boolean field
977          */
978         protected boolean isBooleanField (final FrameworkInterface instance, final String targetClass, final String columnName) {
979                 // Trace message
980                 this.getLogger().trace(MessageFormat.format("instance={0},targetCLass={1},columnName={2} - CALLED!", instance, targetClass, columnName)); //NOI18N
981
982                 // Convert column name to getter name (boolean)
983                 String methodName = this.convertColumnNameToGetterMethod(columnName, true);
984
985                 // Get class instance
986                 Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
987
988                 // Defauzlt is boolean
989                 boolean isBool = true;
990
991                 try {
992                         // Now try to instance the method
993                         Method method = c.getDeclaredMethod(methodName, new Class<?>[0]);
994                 } catch (final NoSuchMethodException ex) {
995                         // Debug message
996                         this.getLogger().debug(MessageFormat.format("Method {0} does not exist, field {1} cannot be boolean: {2}", methodName, columnName, ex)); //NOI18N
997
998                         // Not found
999                         isBool = false;
1000                 }
1001
1002                 // Trace message
1003                 this.getLogger().trace(MessageFormat.format("isBool={0} - EXIT!", isBool)); //NOI18N
1004
1005                 // Return result
1006                 return isBool;
1007         }
1008
1009         /**
1010          * Sets value in properties instance.
1011          *
1012          * @param key Property key (part) to set
1013          * @param value Property value to set
1014          */
1015         protected void setProperty (final String key, final String value) {
1016                 // Trace message
1017                 this.getLogger().trace(MessageFormat.format("key={0},value={1} - CALLED!", key, value)); //NOI18N
1018
1019                 // Both should not be null
1020                 if (null == key) {
1021                         // key is null
1022                         throw new NullPointerException("key is null"); //NOI18N
1023                 } else if (null == value) {
1024                         // value is null
1025                         throw new NullPointerException("value is null"); //NOI18N
1026                 }
1027
1028                 // Set it
1029                 properties.setProperty(String.format("org.mxchange.%s", key), value); //NOI18N
1030
1031                 // Trace message
1032                 this.getLogger().trace("EXIT!"); //NOI18N
1033         }
1034
1035         /**
1036          * Some getter for properties names (without org.mxchange)
1037          *
1038          * @return An array with property names
1039          */
1040         protected String[] getPropertyNames () {
1041                 // Init array
1042                 String[] names = {
1043                         "database.backend.class", //NOI18N
1044                         "database.backend.storagepath", //NOI18N
1045                         "database.mysql.login", //NOI18N
1046                         "database.mysql.host", //NOI18N
1047                         "database.mysql.password", //NOI18N
1048                         "database.mysql.dbname", //NOI18N
1049                 };
1050
1051                 // Return it
1052                 return names;
1053         }
1054
1055         /**
1056          * Some "setter" for a value in given Storeable instance and target class
1057          * 
1058          * @param instance An instance of a Storeable class
1059          * @param targetClass The target class (where the field resides)
1060          * @param columnName Column name (= field name)
1061          * @param value Value to set
1062          * @throws java.lang.NoSuchMethodException If the setter is not found
1063          * @throws java.lang.IllegalAccessException If the setter cannot be accessed
1064          * @throws java.lang.reflect.InvocationTargetException Any other problem?
1065          */
1066         protected void setValueInStoreableFromColumn (final Storeable instance, final String targetClass, final String columnName, final Object value) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
1067                 // Trace message
1068                 this.getLogger().trace(MessageFormat.format("instance={0},targetClass={1},columnName={2},value={3} - CALLED!", instance, targetClass, columnName, value)); //NOI18N
1069
1070                 // A '$' means not our field
1071                 if (columnName.startsWith("$")) { //NOI18N
1072                         // Don't handle these
1073                         throw new IllegalArgumentException("columnsName contains $"); //NOI18N
1074                 }
1075
1076                 // Determine if the given column is boolean
1077                 if (this.isBooleanField(instance, targetClass, columnName)) {
1078                         // Debug message
1079                         this.getLogger().debug(MessageFormat.format("Column {0} represents a boolean field.", columnName)); //NOI18N
1080
1081                         // Yes, then call other method
1082                         this.setBooleanField(instance, targetClass, this.convertColumnNameToSetterMethod(columnName), columnName, (Boolean) value);
1083                 }
1084
1085                 // Convert column name to field name
1086                 String methodName = this.convertColumnNameToSetterMethod(columnName);
1087
1088                 // Debug message
1089                 this.getLogger().debug(MessageFormat.format("methodName={0}", methodName)); //NOI18N
1090
1091                 // Get field
1092                 this.setField(instance, targetClass, methodName, columnName, value);
1093
1094                 // Trace message
1095                 this.getLogger().trace("EXIT!"); //NOI18N
1096         }
1097
1098         /**
1099          * Some "getter" for a value from given Storeable instance and target class
1100          *
1101          * @param instance An instance of a Storeable class
1102          * @param targetClass The target class (where the field resides)
1103          * @param columnName Column name (= field name)
1104          * @return  value Value to get
1105          * @throws java.lang.NoSuchMethodException If the getter was not found
1106          * @throws java.lang.IllegalAccessException If the getter cannot be accessed
1107          * @throws java.lang.reflect.InvocationTargetException Some other problems?
1108          */
1109         protected Object getValueInStoreableFromColumn (final Storeable instance, final String targetClass, final String columnName) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
1110                 // Trace message
1111                 this.getLogger().trace(MessageFormat.format("instance={0},targetClass={1},columnName={2} - CALLED!", instance, targetClass, columnName)); //NOI18N
1112
1113                 // A '$' means not our field
1114                 if (columnName.startsWith("$")) { //NOI18N
1115                         // Don't handle these
1116                         throw new IllegalArgumentException("columnsName contains $"); //NOI18N
1117                 }
1118
1119                 // Determine if the given column is boolean
1120                 if (this.isBooleanField(instance, targetClass, columnName)) {
1121                         // Debug message
1122                         this.getLogger().debug(MessageFormat.format("Column {0} represents a boolean field.", columnName)); //NOI18N
1123
1124                         // Yes, then call other method
1125                         return this.getBooleanField(instance, targetClass, this.convertColumnNameToGetterMethod(columnName, true));
1126                 }
1127
1128                 // Convert column name to field name
1129                 String methodName = this.convertColumnNameToGetterMethod(columnName, false);
1130
1131                 // Debug message
1132                 this.getLogger().debug(MessageFormat.format("methodName={0}", methodName)); //NOI18N
1133
1134                 // Get field
1135                 Object value = this.getField(instance, targetClass, methodName);
1136
1137                 // Trace message
1138                 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
1139
1140                 // Return value
1141                 return value;
1142         }
1143
1144         /**
1145          * Some getter for type reflection of given column name
1146          *
1147          * @param instance The instance to check
1148          * @param targetClass Target class to check
1149          * @param columnName Column name
1150          * @return Type reflection of value
1151          */
1152         private Class<?> getType (final FrameworkInterface instance, final String targetClass, final String columnName) {
1153                 // Trace message
1154                 this.getLogger().trace(MessageFormat.format("instance={0},targetClass={1},columnName={2} - CALLED!", instance, targetClass, columnName)); //NOI18N
1155
1156                 // Init field tye
1157                 Class<?> type = null;
1158
1159                 // Get all attributes from given instance
1160                 Field[] fields = this.getClassFromTarget(instance, targetClass).getDeclaredFields();
1161
1162                 // Debug message
1163                 this.getLogger().debug(MessageFormat.format("fields()={0}", fields.length)); //NOI18N
1164
1165                 // Convert column_name to fieldName ;-)
1166                 String fieldName = this.convertColumnNameToFieldName(columnName);
1167
1168                 // Debug message
1169                 this.getLogger().debug(MessageFormat.format("fieldName={0}", fieldName)); //NOI18N
1170
1171                 // Search for proper field instance
1172                 for (final Field field : fields) {
1173                         // Debug message
1174                         this.getLogger().debug(MessageFormat.format("field.getName()={0},fieldName={1}", field.getName(), fieldName)); //NOI18N
1175
1176                         // Does it match?
1177                         if (field.getName().equals(fieldName)) {
1178                                 // Found it
1179                                 type = field.getType();
1180
1181                                 // Debug message
1182                                 this.getLogger().debug(MessageFormat.format("Found fieldName={0}: setting type={1}", fieldName, type.getSimpleName())); //NOI18N
1183
1184                                 // Don't continue with searching
1185                                 break;
1186                         }
1187                 }
1188
1189                 // Debug message
1190                 this.getLogger().debug(MessageFormat.format("type={0}", type));
1191
1192                 // type should not be null
1193                 if (null == type) {
1194                         // No null allowed
1195                         throw new NullPointerException("type is null"); //NOI18N
1196                 }
1197
1198                 // Trace message
1199                 this.getLogger().debug(MessageFormat.format("type={0} - EXIT!", type)); //NOI18N
1200
1201                 // Return it
1202                 return type;
1203         }
1204 }