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