2 * Copyright (C) 2015 Roland Haeder
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.
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.
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/>.
17 package org.mxchange.addressbook;
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;
42 * @author Roland Haeder
44 public class BaseFrameworkSystem implements FrameworkInterface {
47 * Instance for own properties
49 private static final Properties properties = new Properties(System.getProperties());
54 private final Logger LOG;
57 * Application instance
59 private Application application;
64 private final ResourceBundle bundle;
69 private Client client;
72 * Contact manager instance
74 private ManageableContact contactManager;
77 * Name of used database table, handled over to backend
79 private String tableName;
82 * DatabaseFrontend instance
84 private DatabaseFrontend wrapper;
90 LOG = LogManager.getLogger(this);
91 bundle = ResourceBundle.getBundle("org/mxchange/addressbook/localization/bundle"); // NOI18N
95 * No instances can be created of this class
97 protected BaseFrameworkSystem () {
98 // Init properties file
99 this.initProperties();
103 * Application instance
105 * @return the application
108 public final Application getApplication () {
109 return this.application;
113 * Getter for human-readable string from given key
115 * @param key Key to return
116 * @return Human-readable message
119 public final String getMessageStringFromKey (final String key) {
121 return this.getBundle().getString(key);
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.
128 * @param columnName Column name
129 * @return Value from field
132 public Object getValueFromColumn (final String columnName) {
133 throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0}", columnName)); //NOI18N
137 * Some "getter" for target class instance from given name.
139 * @param instance Instance to iterate on
140 * @param targetClass Class name to look for
141 * @return Class instance
143 @SuppressWarnings ("unchecked")
144 private Class<? extends FrameworkInterface> getClassFromTarget (final FrameworkInterface instance, final String targetClass) {
146 this.getLogger().debug(MessageFormat.format("instance={0},targetClass={1}", instance, targetClass)); //NOI18N
148 // Instance reflaction of this class
149 Class<? extends FrameworkInterface> c = instance.getClass();
152 while (!targetClass.equals(c.getSimpleName())) {
154 this.getLogger().debug(MessageFormat.format("c={0}", c.getSimpleName())); //NOI18N
156 // Get super class (causes unchecked warning)
157 c = (Class<? extends FrameworkInterface>) c.getSuperclass();
161 this.getLogger().trace(MessageFormat.format("c={0} - EXIT!", c)); //NOI18N
168 * Some "getter" for a Method instance from given method name
170 * @param instance Actual instance to call
171 * @param targetClass Target class name
172 * @param methodName Method name
173 * @return A Method instance
175 private Method getMethodFromName (final FrameworkInterface instance, final String targetClass, final String methodName) {
177 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
179 // Get target class instance
180 Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
182 // Init field instance
183 Method method = null;
185 // Use reflection to get all attributes
187 method = c.getDeclaredMethod(methodName, new Class<?>[0]);
188 } catch (final SecurityException ex) {
190 this.abortProgramWithException(ex);
191 } catch (final NoSuchMethodException ex) {
193 this.abortProgramWithException(ex);
197 assert (method instanceof Method) : "method is not a Method instance"; //NOI18N
200 this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method)); //NOI18N
207 * Aborts program with given exception
209 * @param throwable Any type of Throwable
211 protected final void abortProgramWithException (final Throwable throwable) {
213 this.getLogger().catching(throwable);
221 * Application instance
223 * @param application the application to set
225 protected final void setApplication (final Application application) {
226 this.application = application;
235 public final Client getClient () {
240 * Getter for bundle instance
242 * @return Resource bundle
244 protected final ResourceBundle getBundle () {
251 * @param client the client to set
253 protected final void setClient (final Client client) {
254 this.client = client;
258 * Contact manager instance
260 * @return the contactManager
263 public final ManageableContact getContactManager () {
264 return this.contactManager;
268 * Contact manager instance
270 * @param contactManager the contactManager to set
272 protected final void setContactManager (final ManageableContact contactManager) {
273 this.contactManager = contactManager;
277 * Checks if given boolean field is available and set to same value
279 * @param columnName Column name to check
280 * @param bool Boolean value
281 * @return Whether all conditions are met
284 public boolean isValueEqual (final String columnName, final boolean bool) {
286 throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0},bool={1}", columnName, bool)); //NOI18N
292 * @param exception Exception to log
295 public final void logException (final Throwable exception) {
296 // Log this exception
297 this.getLogger().catching(exception);
301 * Prepares all properties, the file is written if it is not found
303 private void initProperties () {
305 this.getLogger().trace("CALLED!"); //NOI18N
308 this.getLogger().debug(MessageFormat.format("{0} properties are loaded already.", BaseFrameworkSystem.properties.size())); //NOI18N
310 // Are some properties loaded?
311 if (!BaseFrameworkSystem.properties.isEmpty()) {
312 // Some are already loaded, abort here
318 BaseFrameworkSystem.properties.load(new BufferedReader(new InputStreamReader(new FileInputStream(FrameworkInterface.PROPERTIES_CONFIG_FILE))));
321 this.getLogger().debug(MessageFormat.format("{0} properties has been loaded.", BaseFrameworkSystem.properties.size())); //NOI18N
322 } catch (final FileNotFoundException ex) {
324 this.getLogger().debug(MessageFormat.format("Properties file {0} not found: {1}", FrameworkInterface.PROPERTIES_CONFIG_FILE, ex)); //NOI18N
327 * The file is not found which is normal for first run, so
328 * initialize default values.
330 this.initPropertiesWithDefault();
333 this.writePropertiesFile();
334 } catch (final IOException ex) {
335 // Something else didn't work
336 this.abortProgramWithException(ex);
340 this.getLogger().trace("EXIT!"); //NOI18N
344 * Initializes properties with default values
346 private void initPropertiesWithDefault () {
348 this.getLogger().trace("CALLED!"); //NOI18N
350 // Init default values:
351 // Default database backend
352 BaseFrameworkSystem.properties.put("org.mxchange.addressbook.database.backendType", "base64csv"); //NOI18N
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
361 this.getLogger().trace("EXIT!"); //NOI18N
365 * Writes the properties file to disk
367 private void writePropertiesFile () {
369 this.getLogger().trace("CALLED!"); //NOI18N
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);
379 this.getLogger().trace("EXIT!"); //NOI18N
383 * Converts a column name like "foo_bar" to an attribute name like "fooBar"
385 * @param columnName Column name to convert
386 * @return Attribute name
388 protected String convertColumnNameToAttribute (final String columnName) {
390 this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
392 // First all lower case
393 String lower = columnName.toLowerCase();
396 StringTokenizer tokenizer = new StringTokenizer(lower, "_"); //NOI18N
399 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
405 while (tokenizer.hasMoreTokens()) {
407 String token = tokenizer.nextToken();
409 // Is later than first element?
411 // Make first character upper-case
412 char c = token.charAt(0);
413 token = String.valueOf(c).toUpperCase() + token.substring(1);
417 builder.append(token);
424 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
427 return builder.toString();
431 * Converts a column name like "foo_bar" to a method name like "getFooBar"
432 * for non-booleans and to "isFooBar" for boolean fields.
434 * @param columnName Column name to convert
435 * @param isBool Whether the parameter is boolean
436 * @return Attribute name
438 protected String convertColumnNameToGetterMethod (final String columnName, boolean isBool) {
440 this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName)); //NOI18N
443 StringTokenizer tokenizer = new StringTokenizer(columnName, "_"); //NOI18N
446 StringBuilder builder = new StringBuilder(tokenizer.countTokens());
451 builder.append("is"); //NOI18N
454 builder.append("get"); //NOI18N
458 while (tokenizer.hasMoreTokens()) {
460 String token = tokenizer.nextToken();
463 this.getLogger().debug(MessageFormat.format("token={0}", token)); //NOI18N
465 // Make it upper-case
466 char c = token.charAt(0);
467 token = String.valueOf(c).toUpperCase() + token.substring(1);
470 builder.append(token);
474 this.getLogger().trace(MessageFormat.format("builder={0} - EXIT!", builder)); //NOI18N
477 return builder.toString();
481 * Returns boolean field value from given method call
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
488 protected boolean getBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName) {
490 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
492 // Get method instance
493 Method method = this.getMethodFromName(instance, targetClass, methodName);
495 // Get value from field
496 Boolean value = false;
499 value = (Boolean) method.invoke(instance);
500 } catch (final IllegalArgumentException ex) {
502 this.abortProgramWithException(ex);
503 } catch (final IllegalAccessException ex) {
505 this.abortProgramWithException(ex);
506 } catch (final InvocationTargetException ex) {
508 this.abortProgramWithException(ex);
516 * Returns any field value from given method call
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
523 protected Object getField (final FrameworkInterface instance, final String targetClass, final String methodName) {
525 this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName)); //NOI18N
527 // Get method to call
528 Method method = this.getMethodFromName(instance, targetClass, methodName);
530 // Get value from field
531 Object object = null;
534 object = method.invoke(instance);
535 } catch (final IllegalArgumentException ex) {
537 this.abortProgramWithException(ex);
538 } catch (final IllegalAccessException ex) {
540 this.abortProgramWithException(ex);
541 } catch (final InvocationTargetException ex) {
543 this.abortProgramWithException(ex);
555 protected final Logger getLogger () {
560 * Getter for property which must exist
562 * @param key Key to get
563 * @return Propety value
565 protected final String getProperty (final String key) {
566 return BaseFrameworkSystem.properties.getProperty(String.format("org.mxchange.addressbook.%s", key)); //NOI18N
570 * Name of used database table, handled over to backend
572 * @return the tableName
574 protected final String getTableName () {
575 return this.tableName;
579 * Name of used database table, handled over to backend
581 * @param tableName the tableName to set
583 protected final void setTableName (final String tableName) {
584 this.tableName = tableName;
588 * Getter for DatabaseFrontend instance
590 * @return DatabaseFrontend instance
592 protected DatabaseFrontend getWrapper () {
597 * Setter for wrapper instance
599 * @param wrapper A DatabaseFrontend instance
601 protected void setWrapper (final DatabaseFrontend wrapper) {
602 this.wrapper = wrapper;
606 * Some "getter" for an array from given string and tokenizer
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
613 protected String[] getArrayFromString (final String str, final String delimiter, final int size) {
615 this.getLogger().trace(MessageFormat.format("str={0},delimiter={1},size={2} - CALLED!", str, delimiter, size)); //NOI18N
618 StringTokenizer tokenizer = new StringTokenizer(str, delimiter);
620 // Init array and index
621 String[] tokens = new String[size];
624 // Run through all tokens
625 while (tokenizer.hasMoreTokens()) {
626 // Get current token and add it
627 tokens[index] = tokenizer.nextToken();
630 this.getLogger().debug(MessageFormat.format("Token at index{0}: {1}", index, tokens[1])); //NOI18N
637 this.getLogger().trace(MessageFormat.format("tokens({0})={1} - EXIT!", tokens.length, Arrays.toString(tokens))); //NOI18N
644 * Checks whether the given field is a boolean field by probing it.
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
651 protected boolean isBooleanField (final FrameworkInterface instance, final String targetClass, final String columnName) {
653 this.getLogger().trace(MessageFormat.format("instance={0},targetCLass={1},columnName={2} - CALLED!", instance, targetClass, columnName)); //NOI18N
655 // Convert column name to getter name (boolean)
656 String methodName = this.convertColumnNameToGetterMethod(columnName, true);
658 // Get class instance
659 Class<? extends FrameworkInterface> c = this.getClassFromTarget(instance, targetClass);
661 // Defauzlt is boolean
662 boolean isBool = true;
665 // Now try to instance the method
666 Method method = c.getDeclaredMethod(methodName, new Class<?>[0]);
667 } catch (final NoSuchMethodException ex) {
669 this.getLogger().debug(MessageFormat.format("Method {0} does not exist, field {1} cannot be boolean: {2}", methodName, columnName, ex)); //NOI18N
673 } catch (final SecurityException ex) {
675 this.abortProgramWithException(ex);
679 this.getLogger().trace(MessageFormat.format("isBool={0} - EXIT!", isBool)); //NOI18N