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