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