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