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