]> git.mxchange.org Git - jcore.git/blob - src/org/mxchange/jcore/BaseFrameworkSystem.java
24048eed7526b2724724ef0238e3f9325c5742dc
[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.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.text.MessageFormat;
28 import java.util.Arrays;
29 import java.util.Properties;
30 import java.util.ResourceBundle;
31 import java.util.StringTokenizer;
32 import org.apache.logging.log4j.LogManager;
33 import org.apache.logging.log4j.Logger;
34 import org.mxchange.jcore.application.Application;
35 import org.mxchange.jcore.client.Client;
36 import org.mxchange.jcore.contact.Contact;
37 import org.mxchange.jcore.database.frontend.DatabaseFrontend;
38 import org.mxchange.jcore.manager.Manageable;
39
40 /**
41  * General class
42  *
43  * @author Roland Haeder
44  */
45 public class BaseFrameworkSystem implements FrameworkInterface {
46         /**
47          * Bundle instance
48          */
49         private static ResourceBundle bundle;
50
51         /**
52          * Instance for own properties
53          */
54         private static final Properties properties = new Properties(System.getProperties());
55
56         /**
57          * Self instance
58          */
59         private static FrameworkInterface selfInstance;
60
61         /**
62          * Class' logger
63          */
64         private final Logger LOG;
65
66         /**
67          * Application instance
68          */
69         private Application application;
70
71
72         /**
73          * Client instance
74          */
75         private Client client;
76
77         /**
78          * Contact instance
79          */
80         private Contact contact;
81
82         /**
83          * Manager instance
84          */
85         private Manageable manager;
86
87         /**
88          * Name of used database table, handled over to backend
89          */
90         private String tableName;
91
92         /**
93          * DatabaseFrontend instance
94          */
95         private DatabaseFrontend wrapper;
96
97
98         /**
99          * Initialize object
100          */
101         {
102                 LOG = LogManager.getLogger(this);
103         }
104
105         /**
106          * Getter for this application
107          *
108          * @return Instance from this application
109          */
110         public static final FrameworkInterface getInstance () {
111                 // Return it
112                 return selfInstance;
113         }
114
115         /**
116          * No instances can be created of this class
117          */
118         protected BaseFrameworkSystem () {
119                 // Init properties file
120                 this.initProperties();
121
122                 // Set own instance
123                 this.setSelfInstance();
124         }
125
126         /**
127          * Application instance
128          *
129          * @return the application
130          */
131         @Override
132         public final Application getApplication () {
133                 return this.application;
134         }
135
136         /**
137          * Getter for logger
138          *
139          * @return Logger
140          */
141         @Override
142         public final Logger getLogger () {
143                 return this.LOG;
144         }
145
146         /**
147          * Manager instance
148          *
149          * @return the contactManager
150          */
151         @Override
152         public final Manageable getManager () {
153                 return this.manager;
154         }
155
156         /**
157          * Getter for human-readable string from given key
158          *
159          * @param key Key to return
160          * @return Human-readable message
161          */
162         @Override
163         public final String getMessageStringFromKey (final String key) {
164                 // Return message
165                 return this.getBundle().getString(key);
166         }
167
168         /**
169          * Some "getter for a value from given column name. This name will be
170          * translated into a method name and then this method is called.
171          *
172          * @param columnName Column name
173          * @return Value from field
174          */
175         @Override
176         public Object getValueFromColumn (final String columnName) {
177                 throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0}", columnName)); //NOI18N
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) {
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 = null;
228                 
229                 // Use reflection to get all attributes
230                 try {
231                         method = c.getDeclaredMethod(methodName, new Class<?>[0]);
232                 } catch (final SecurityException ex) {
233                         // Security problem
234                         this.abortProgramWithException(ex);
235                 } catch (final NoSuchMethodException ex) {
236                         // Method not found
237                         this.abortProgramWithException(ex);
238                 }
239                 
240                 // Assert on field
241                 assert (method instanceof Method) : "method is not a Method instance"; //NOI18N
242                 
243                 // Trace message
244                 this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method)); //NOI18N
245                 
246                 // Return it
247                 return method;
248         }
249
250         /**
251          * Setter for self instance
252          */
253         private void setSelfInstance () {
254                 // Need to set it here
255                 selfInstance = this;
256         }
257
258         /**
259          * Aborts program with given exception
260          *
261          * @param       throwable Any type of Throwable
262          */
263         protected final void abortProgramWithException (final Throwable throwable) {
264                 // Log exception ...
265                 this.getLogger().catching(throwable);
266                 
267                 // .. and exit
268                 System.exit(1);
269                 
270         }
271
272         /**
273          * Application instance
274          *
275          * @param application the application to set
276          */
277         protected final void setApplication (final Application application) {
278                 this.application = application;
279         }
280
281         /**
282          * Client instance
283          *
284          * @return the client
285          */
286         @Override
287         public final Client getClient () {
288                 return this.client;
289         }
290
291         /**
292          * Getter for bundle instance
293          *
294          * @return Resource bundle
295          */
296         protected final ResourceBundle getBundle () {
297                 return BaseFrameworkSystem.bundle;
298         }
299
300         /**
301          * Client instance
302          *
303          * @param client the client to set
304          */
305         protected final void setClient (final Client client) {
306                 this.client = client;
307         }
308
309         /**
310          * Checks if given boolean field is available and set to same value
311          *
312          * @param columnName Column name to check
313          * @param bool Boolean value
314          * @return Whether all conditions are met
315          */
316         @Override
317         public boolean isValueEqual (final String columnName, final boolean bool) {
318                 // Not implemented
319                 throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0},bool={1}", columnName, bool)); //NOI18N
320         }
321
322         /**
323          * Log exception
324          *
325          * @param exception Exception to log
326          */
327         @Override
328         public final void logException (final Throwable exception) {
329                 // Log this exception
330                 this.getLogger().catching(exception);
331         }
332
333         /**
334          * Prepares all properties, the file is written if it is not found
335          */
336         private void initProperties () {
337                 // Trace message
338                 this.getLogger().trace("CALLED!"); //NOI18N
339
340                 // Debug message
341                 this.getLogger().debug(MessageFormat.format("{0} properties are loaded already.", BaseFrameworkSystem.properties.size())); //NOI18N
342
343                 // Are some properties loaded?
344                 if (!BaseFrameworkSystem.properties.isEmpty()) {
345                         // Some are already loaded, abort here
346                         return;
347                 }
348
349                 try {
350                         // Try to read it
351                         BaseFrameworkSystem.properties.load(new BufferedReader(new InputStreamReader(new FileInputStream(FrameworkInterface.PROPERTIES_CONFIG_FILE))));
352
353                         // Debug message
354                         this.getLogger().debug(MessageFormat.format("{0} properties has been loaded.", BaseFrameworkSystem.properties.size())); //NOI18N
355                 } catch (final FileNotFoundException ex) {
356                         // Debug message
357                         this.getLogger().debug(MessageFormat.format("Properties file {0} not found: {1}", FrameworkInterface.PROPERTIES_CONFIG_FILE, ex)); //NOI18N
358
359                         /*
360                          * The file is not found which is normal for first run, so
361                          * initialize default values.
362                          */
363                         this.initPropertiesWithDefault();
364
365                         // Write file
366                         this.writePropertiesFile();
367                 } catch (final IOException ex) {
368                         // Something else didn't work
369                         this.abortProgramWithException(ex);
370                 }
371
372                 // Trace message
373                 this.getLogger().trace("EXIT!"); //NOI18N
374         }
375
376         /**
377          * Initializes properties with default values
378          */
379         private void initPropertiesWithDefault () {
380                 // Trace message
381                 this.getLogger().trace("CALLED!"); //NOI18N
382
383                 // Init default values:
384                 // Default database backend
385                 BaseFrameworkSystem.properties.put("org.mxchange.database.backendType", "base64csv"); //NOI18N
386
387                 // For MySQL backend
388                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.host", "localhost"); //NOI18N
389                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.dbname", "test"); //NOI18N
390                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.login", ""); //NOI18N
391                 BaseFrameworkSystem.properties.put("org.mxchange.database.mysql.password", ""); //NOI18N
392
393                 // Trace message
394                 this.getLogger().trace("EXIT!"); //NOI18N
395         }
396
397         /**
398          * Writes the properties file to disk
399          */
400         private void writePropertiesFile () {
401                 // Trace message
402                 this.getLogger().trace("CALLED!"); //NOI18N
403
404                 try {
405                         // Write it
406                         BaseFrameworkSystem.properties.store(new PrintWriter(FrameworkInterface.PROPERTIES_CONFIG_FILE), "This file is automatically generated. You may wish to alter it."); //NOI18N
407                 } catch (final IOException ex) {
408                         this.abortProgramWithException(ex);
409                 }
410
411                 // Trace message
412                 this.getLogger().trace("EXIT!"); //NOI18N
413         }
414
415         /**
416          * Converts a column name like "foo_bar" to an attribute name like "fooBar"
417          *
418          * @param columnName Column name to convert
419          * @return Attribute name
420          */
421         protected String convertColumnNameToAttribute (final String columnName) {
422                 // Trace message
423                 this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
424
425                 // First all lower case
426                 String lower = columnName.toLowerCase();
427
428                 // Then split on "_"
429                 StringTokenizer tokenizer = new StringTokenizer(lower, "_"); //NOI18N
430
431                 // Resulting string
432                 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
433
434                 // Init counter
435                 int count = 0;
436
437                 // Walk through all
438                 while (tokenizer.hasMoreTokens()) {
439                         // Get token
440                         String token = tokenizer.nextToken();
441
442                         // Is later than first element?
443                         if (count > 0) {
444                                 // Make first character upper-case
445                                 char c = token.charAt(0);
446                                 token = String.valueOf(c).toUpperCase() + token.substring(1);
447                         }
448
449                         // Add token
450                         builder.append(token);
451
452                         // Increment counter
453                         count++;
454                 }
455
456                 // Trace message
457                 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
458
459                 // Return result
460                 return builder.toString();
461         }
462
463         /**
464          * Converts a column name like "foo_bar" to a method name like "getFooBar"
465          * for non-booleans and to "isFooBar" for boolean fields.
466          *
467          * @param columnName Column name to convert
468          * @param isBool Whether the parameter is boolean
469          * @return Attribute name
470          */
471         protected String convertColumnNameToGetterMethod (final String columnName, boolean isBool) {
472                 // Trace message
473                 this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
474
475                 // Then split on "_"
476                 StringTokenizer tokenizer = new StringTokenizer(columnName, "_"); //NOI18N
477
478                 // Resulting string
479                 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
480
481                 // Is it boolean?
482                 if (isBool) {
483                         // Append "is"
484                         builder.append("is"); //NOI18N
485                 } else {
486                         // Append "get"
487                         builder.append("get"); //NOI18N
488                 }
489
490                 // Walk through all
491                 while (tokenizer.hasMoreTokens()) {
492                         // Get token
493                         String token = tokenizer.nextToken();
494
495                         // Debug message
496                         this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
497
498                         // Make it upper-case
499                         char c = token.charAt(0);
500                         token = String.valueOf(c).toUpperCase() + token.substring(1);
501
502                         // Add token
503                         builder.append(token);
504                 }
505
506                 // Trace message
507                 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
508
509                 // Return result
510                 return builder.toString();
511         }
512
513         /**
514          * Some "getter" for an array from given string and tokenizer
515          *
516          * @param str String to tokenize and get array from
517          * @param delimiter Delimiter
518          * @param size Size of array
519          * @return Array from tokenized string
520          */
521         protected String[] getArrayFromString (final String str, final String delimiter, final int size) {
522                 // Trace message
523                 this.getLogger().trace(MessageFormat.format("str={0},delimiter={1},size={2} - CALLED!", str, delimiter, size)); //NOI18N
524                 
525                 // Get tokenizer
526                 StringTokenizer tokenizer = new StringTokenizer(str, delimiter);
527                 
528                 // Init array and index
529                 String[] tokens = new String[size];
530                 int index = 0;
531                 
532                 // Run through all tokens
533                 while (tokenizer.hasMoreTokens()) {
534                         // Get current token and add it
535                         tokens[index] = tokenizer.nextToken();
536                         
537                         // Debug message
538                         this.getLogger().debug(MessageFormat.format("Token at index{0}: {1}", index, tokens[1])); //NOI18N
539                         
540                         // Increment index
541                         index++;
542                 }
543                 
544                 // Trace message
545                 this.getLogger().trace(MessageFormat.format("tokens({0})={1} - EXIT!", tokens.length, Arrays.toString(tokens))); //NOI18N
546
547                 // Return it
548                 return tokens;
549         }
550
551         /**
552          * Returns boolean field value from given method call
553          *
554          * @param instance The instance to call
555          * @param targetClass Target class to look in
556          * @param methodName Method name to look for
557          * @return Boolean value from field
558          */
559         protected boolean getBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName) {
560                 // Trace messahe
561                 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
562
563                 // Get method instance
564                 Method method = this.getMethodFromName(instance, targetClass, methodName);
565
566                 // Get value from field
567                 Boolean value = false;
568
569                 try {
570                         value = (Boolean) method.invoke(instance);
571                 } catch (final IllegalArgumentException ex) {
572                         // Other problem
573                         this.abortProgramWithException(ex);
574                 } catch (final IllegalAccessException ex) {
575                         // Other problem
576                         this.abortProgramWithException(ex);
577                 } catch (final InvocationTargetException ex) {
578                         // Other problem
579                         this.abortProgramWithException(ex);
580                 }
581
582                 // Return value
583                 return value;
584         }
585
586         /**
587          * Manager instance
588          *
589          * @param manager the manager instance to set
590          */
591         protected final void setContactManager (final Manageable manager) {
592                 this.manager = manager;
593         }
594
595         /**
596          * Returns any field value from given method call
597          *
598          * @param instance The instance to call
599          * @param targetClass Target class to look in
600          * @param methodName Method name to look for
601          * @return Any value from field
602          */
603         protected Object getField (final FrameworkInterface instance, final String targetClass, final String methodName) {
604                 // Trace messahe
605                 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
606
607                 // Get method to call
608                 Method method = this.getMethodFromName(instance, targetClass, methodName);
609
610                 // Get value from field
611                 Object object = null;
612
613                 try {
614                         object = method.invoke(instance);
615                 } catch (final IllegalArgumentException ex) {
616                         // Other problem
617                         this.abortProgramWithException(ex);
618                 } catch (final IllegalAccessException ex) {
619                         // Other problem
620                         this.abortProgramWithException(ex);
621                 } catch (final InvocationTargetException ex) {
622                         // Other problem
623                         this.abortProgramWithException(ex);
624                 }
625
626                 // Return value
627                 return object;
628         }
629
630         /**
631          * Getter for property which must exist
632          *
633          * @param key Key to get
634          * @return Propety value
635          */
636         protected final String getProperty (final String key) {
637                 return BaseFrameworkSystem.properties.getProperty(String.format("org.mxchange.addressbook.%s", key)); //NOI18N
638         }
639
640         /**
641          * Name of used database table, handled over to backend
642          *
643          * @return the tableName
644          */
645         protected final String getTableName () {
646                 return this.tableName;
647         }
648
649         /**
650          * Name of used database table, handled over to backend
651          *
652          * @param tableName the tableName to set
653          */
654         protected final void setTableName (final String tableName) {
655                 this.tableName = tableName;
656         }
657
658         /**
659          * Getter for DatabaseFrontend instance
660          *
661          * @return DatabaseFrontend instance
662          */
663         protected final DatabaseFrontend getWrapper () {
664                 return this.wrapper;
665         }
666
667         /**
668          * Setter for wrapper instance
669          *
670          * @param wrapper A DatabaseFrontend instance
671          */
672         protected final void setWrapper (final DatabaseFrontend wrapper) {
673                 this.wrapper = wrapper;
674         }
675
676         /**
677          * Getter for Contact instance
678          *
679          * @return Contact instance
680          */
681         protected final Contact getContact () {
682                 return this.contact;
683         }
684
685         /**
686          * Setter for Contact instance
687          *
688          * @param contact A Contact instance
689          */
690         protected final void setContact (final Contact contact) {
691                 this.contact = contact;
692         }
693
694         /**
695          * Initializes i18n bundles
696          */
697         protected void initBundle () {
698                 // Is the bundle set?
699                 if (bundle instanceof ResourceBundle) {
700                         // Is already set
701                         throw new IllegalStateException("called twice");
702                 }
703                 
704                 // Set instance
705                 bundle = ResourceBundle.getBundle(FrameworkInterface.I18N_BUNDLE_FILE); // NOI18N
706         }
707
708         /**
709          * Checks whether the given field is a boolean field by probing it.
710          * 
711          * @param instance Instance to call
712          * @param targetClass Target class
713          * @param columnName Column name to check
714          * @return Whether the given column name represents a boolean field
715          */
716         protected boolean isBooleanField (final FrameworkInterface instance, final String targetClass, final String columnName) {
717                 // Trace message
718                 this.getLogger().trace(MessageFormat.format("instance={0},targetCLass={1},columnName={2} - CALLED!", instance, targetClass, columnName)); //NOI18N
719
720                 // Convert column name to getter name (boolean)
721                 String methodName = this.convertColumnNameToGetterMethod(columnName, true);
722
723                 // Get class instance
724                 Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
725
726                 // Defauzlt is boolean
727                 boolean isBool = true;
728
729                 try {
730                         // Now try to instance the method
731                         Method method = c.getDeclaredMethod(methodName, new Class<?>[0]);
732                 } catch (final NoSuchMethodException ex) {
733                         // Debug message
734                         this.getLogger().debug(MessageFormat.format("Method {0} does not exist, field {1} cannot be boolean: {2}", methodName, columnName, ex)); //NOI18N
735
736                         // Not found
737                         isBool = false;
738                 } catch (final SecurityException ex) {
739                         // Really bad?
740                         this.abortProgramWithException(ex);
741                 }
742
743                 // Trace message
744                 this.getLogger().trace(MessageFormat.format("isBool={0} - EXIT!", isBool)); //NOI18N
745
746                 // Return result
747                 return isBool;
748         }
749 }