From d669393da622147ef775a088564719dbc5ff9391 Mon Sep 17 00:00:00 2001
From: Roland Haeder <roland@mxchange.org>
Date: Fri, 31 Jul 2015 13:04:17 +0200
Subject: [PATCH] Continued with refacturing: - getBooleanField() - getField()
 - getValueFromColumn() - getMethodFromName() - And more!
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

Signed-off-by:Roland Häder <roland@mxchange.org>
---
 .../addressbook/BaseFrameworkSystem.java      | 220 +++++++++++++-----
 .../addressbook/FrameworkInterface.java       |  18 ++
 .../addressbook/contact/BaseContact.java      |  54 +++--
 .../database/backend/DatabaseBackend.java     |   8 +
 .../backend/csv/Base64CsvDatabaseBackend.java |  41 +++-
 .../backend/mysql/MySqlDatabaseBackend.java   |   5 +
 .../frontend/BaseDatabaseFrontend.java        |   4 +-
 .../database/frontend/DatabaseWrapper.java    |  10 +
 .../contact/ContactDatabaseFrontend.java      |  25 ++
 .../frontend/contact/ContactWrapper.java      |   8 +
 .../manager/contact/ContactManager.java       |  41 ++++
 .../manager/contact/ManageableContact.java    |   9 +
 .../model/contact/ContactTableModel.java      |   6 +-
 13 files changed, 365 insertions(+), 84 deletions(-)

diff --git a/Addressbook/src/org/mxchange/addressbook/BaseFrameworkSystem.java b/Addressbook/src/org/mxchange/addressbook/BaseFrameworkSystem.java
index efd21ff..f0fd4d4 100644
--- a/Addressbook/src/org/mxchange/addressbook/BaseFrameworkSystem.java
+++ b/Addressbook/src/org/mxchange/addressbook/BaseFrameworkSystem.java
@@ -32,6 +32,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.mxchange.addressbook.application.Application;
 import org.mxchange.addressbook.client.Client;
+import org.mxchange.addressbook.database.frontend.DatabaseWrapper;
 import org.mxchange.addressbook.manager.contact.ManageableContact;
 
 /**
@@ -76,6 +77,11 @@ public class BaseFrameworkSystem implements FrameworkInterface {
 	 */
 	private String tableName;
 
+	/**
+	 * DatabaseWrapper instance
+	 */
+	private DatabaseWrapper wrapper;
+
 	/**
 	 * Initialize object
 	 */
@@ -114,6 +120,67 @@ public class BaseFrameworkSystem implements FrameworkInterface {
 		return this.getBundle().getString(key);
 	}
 
+	/**
+	 * Some "getter for a value from given column name. This name will be
+	 * translated into a method name and then this method is called.
+	 *
+	 * @param columnName Column name
+	 * @return Value from field
+	 */
+	@Override
+	public Object getValueFromColumn (final String columnName) {
+		throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0}", columnName));
+	}
+
+	/**
+	 * Some "getter" for a Method instance from given method name
+	 *
+	 * @param instance Actual instance to call
+	 * @param targetClass Target class name
+	 * @param methodName Method name
+	 * @return A Method instance
+	 */
+	@SuppressWarnings ("unchecked")
+	private Method getMethodFromName (final FrameworkInterface instance, final String targetClass, final String methodName) {
+		// Trace messahe
+		this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName));
+
+		// Instance reflaction of this class
+		Class<? extends FrameworkInterface> c = instance.getClass();
+		
+		// Analyze class
+		while (!targetClass.equals(c.getSimpleName())) {
+			// Debug message
+			this.getLogger().debug("c=" + c.getSimpleName());
+
+			// Get super class (causes unchecked warning)
+			c = (Class<? extends FrameworkInterface>) c.getSuperclass();
+		}
+
+		// Init field instance
+		Method method = null;
+
+		// Use reflection to get all attributes
+		try {
+			method = c.getDeclaredMethod(methodName, new Class<?>[0]);
+		} catch (final SecurityException ex) {
+			// Security problem
+			this.abortProgramWithException(ex);
+		} catch (final NoSuchMethodException ex) {
+			// Method not found
+			this.abortProgramWithException(ex);
+		}
+
+		// Assert on field
+		assert(method instanceof Method) : "method is not a Method instance";
+
+		// Trace message
+		this.getLogger().trace(MessageFormat.format("method={0} - EXIT!", method));
+
+		// Return it
+		return method;
+	}
+
 	/**
 	 * Aborts program with given exception
 	 *
@@ -122,7 +189,7 @@ public class BaseFrameworkSystem implements FrameworkInterface {
 	protected final void abortProgramWithException (final Throwable throwable) {
 		// Log exception ...
 		this.getLogger().catching(throwable);
-		
+
 		// .. and exit
 		System.exit(1);
 		
@@ -184,6 +251,19 @@ public class BaseFrameworkSystem implements FrameworkInterface {
 		this.contactManager = contactManager;
 	}
 
+	/**
+	 * Checks if given boolean field is available and set to same value
+	 *
+	 * @param columnName Column name to check
+	 * @param bool Boolean value
+	 * @return Whether all conditions are met
+	 */
+	@Override
+	public boolean isValueEqual (final String columnName, final boolean bool) {
+		// Not implemented
+		throw new UnsupportedOperationException(MessageFormat.format("Not implemented. columnName={0},bool={1}", columnName, bool));
+	}
+
 	/**
 	 * Log exception
 	 *
@@ -378,6 +458,76 @@ public class BaseFrameworkSystem implements FrameworkInterface {
 		return builder.toString();
 	}
 
+	/**
+	 * Returns boolean field value from given method call
+	 *
+	 * @param instance The instance to call
+	 * @param targetClass Target class to look in
+	 * @param methodName Method name to look for
+	 * @return Boolean value from field
+	 */
+	protected boolean getBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName) {
+		// Trace messahe
+		this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName));
+
+		// Get method instance
+		Method method = this.getMethodFromName(instance, targetClass, methodName);
+
+		// Get value from field
+		Boolean value = false;
+
+		try {
+			value = (Boolean) method.invoke(instance);
+		} catch (final IllegalArgumentException ex) {
+			// Other problem
+			this.abortProgramWithException(ex);
+		} catch (final IllegalAccessException ex) {
+			// Other problem
+			this.abortProgramWithException(ex);
+		} catch (final InvocationTargetException ex) {
+			// Other problem
+			this.abortProgramWithException(ex);
+		}
+
+		// Return value
+		return value;
+	}
+
+	/**
+	 * Returns any field value from given method call
+	 *
+	 * @param instance The instance to call
+	 * @param targetClass Target class to look in
+	 * @param methodName Method name to look for
+	 * @return Any value from field
+	 */
+	protected Object getField (final FrameworkInterface instance, final String targetClass, final String methodName) {
+		// Trace messahe
+		this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName));
+
+		// Get method to call
+		Method method = this.getMethodFromName(instance, targetClass, methodName);
+
+		// Get value from field
+		Object object = null;
+
+		try {
+			object = method.invoke(instance);
+		} catch (final IllegalArgumentException ex) {
+			// Other problem
+			this.abortProgramWithException(ex);
+		} catch (final IllegalAccessException ex) {
+			// Other problem
+			this.abortProgramWithException(ex);
+		} catch (final InvocationTargetException ex) {
+			// Other problem
+			this.abortProgramWithException(ex);
+		}
+
+		// Return value
+		return object;
+	}
+	
 	/**
 	 * Getter for logger
 	 *
@@ -416,64 +566,20 @@ public class BaseFrameworkSystem implements FrameworkInterface {
 	}
 
 	/**
-	 * Returns boolean field value from given method call
+	 * Getter for DatabaseWrapper instance
 	 *
-	 * @param instance The instance to call
-	 * @param targetClass Target class to look in
-	 * @param methodName Method name to look for
-	 * @return Boolean value from field
+	 * @return DatabaseWrapper instance
 	 */
-	@SuppressWarnings ("unchecked")
-	protected boolean getBooleanField (final FrameworkInterface instance, final String targetClass, final String methodName) {
-		// Trace messahe
-		this.getLogger().trace(MessageFormat.format("targetClass={0},methodName={1}", targetClass, methodName));
-
-		// Instance reflaction of this class
-		Class<? extends FrameworkInterface> c = instance.getClass();
-
-		// Analyze class
-		while (!targetClass.equals(c.getSimpleName())) {
-			// Debug message
-			this.getLogger().debug("c=" + c.getSimpleName());
-
-			// Get super class (causes unchecked warning)
-			c = (Class<? extends FrameworkInterface>) c.getSuperclass();
-		}
-
-		// Init field instance
-		Method method = null;
-
-		// Use reflection to get all attributes
-		try {
-			method = c.getDeclaredMethod(methodName, new Class<?>[0]);
-		} catch (final SecurityException ex) {
-			// Security problem
-			this.abortProgramWithException(ex);
-		} catch (final NoSuchMethodException ex) {
-			// Method not found
-			this.abortProgramWithException(ex);
-		}
-
-		// Assert on field
-		assert(method instanceof Method) : "method is not a Method instance";
-
-		// Get value from field
-		boolean value = false;
-
-		try {
-			value = (boolean) method.invoke(instance);
-		} catch (final IllegalArgumentException ex) {
-			// Other problem
-			this.abortProgramWithException(ex);
-		} catch (final IllegalAccessException ex) {
-			// Other problem
-			this.abortProgramWithException(ex);
-		} catch (final InvocationTargetException ex) {
-			// Other problem
-			this.abortProgramWithException(ex);
-		}
+	protected DatabaseWrapper getWrapper () {
+		return this.wrapper;
+	}
 
-		// Return value
-		return value;
+	/**
+	 * Setter for wrapper instance
+	 *
+	 * @param wrapper A DatabaseWrapper instance
+	 */
+	protected void setWrapper (final DatabaseWrapper wrapper) {
+		this.wrapper = wrapper;
 	}
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/FrameworkInterface.java b/Addressbook/src/org/mxchange/addressbook/FrameworkInterface.java
index 0ef8206..8253f6d 100644
--- a/Addressbook/src/org/mxchange/addressbook/FrameworkInterface.java
+++ b/Addressbook/src/org/mxchange/addressbook/FrameworkInterface.java
@@ -66,4 +66,22 @@ public interface FrameworkInterface {
 	 * @param exception Exception to log
 	 */
 	public void logException (final Throwable exception);
+
+	/**
+	 * Checks if given boolean field is available and set to same value
+	 *
+	 * @param columnName Column name to check
+	 * @param bool Boolean value
+	 * @return Whether all conditions are met
+	 */
+	public boolean isValueEqual (final String columnName, final boolean bool);
+
+	/**
+	 * Some "getter for a value from given column name. This name will be
+	 * translated into a method name and then this method is called.
+	 *
+	 * @param columnName Column name
+	 * @return Value from field
+	 */
+	public Object getValueFromColumn (final String columnName);
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/contact/BaseContact.java b/Addressbook/src/org/mxchange/addressbook/contact/BaseContact.java
index 983bdea..4ecf0c3 100644
--- a/Addressbook/src/org/mxchange/addressbook/contact/BaseContact.java
+++ b/Addressbook/src/org/mxchange/addressbook/contact/BaseContact.java
@@ -243,7 +243,7 @@ public class BaseContact extends BaseFrameworkSystem {
 
 		// Get all together
 		String csvString = String.format(
-				"\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\"",
+				"\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\";\"%s\"", //NOI18N
 				this.isOwnContact(),
 				this.getGender().getDatabaseValue(),
 				this.getSurname(),
@@ -388,27 +388,8 @@ public class BaseContact extends BaseFrameworkSystem {
 	 * @return gender Human-readable gender
 	 */
 	public String getTranslatedGender () {
-		// Default init
-		String translated = null;
-
 		// "Translate" it
-		switch (this.getGender()) {
-			case MALE: // Mr.
-				translated = "Herr";
-				break;
-
-			case FEMALE: // Mrs.
-				translated = "Frau";
-				break;
-
-			case COMPANY: // "Company"
-				translated = "Firma";
-				break;
-
-			default: // Unsupported
-				this.getLogger().error("Gender " + this.getGender() + " not supported.");
-				break;
-		}
+		String translated = this.getBundle().getString(this.getGender().getMessageKey());
 
 		// Return it
 		return translated;
@@ -635,6 +616,7 @@ public class BaseContact extends BaseFrameworkSystem {
 	 * @param bool Boolean value
 	 * @return Whether all conditions are met
 	 */
+	@Override
 	public boolean isValueEqual (final String columnName, final boolean bool) {
 		// Trace message
 		this.getLogger().trace(MessageFormat.format("columnName={0},bool={1} - CALLED!", columnName, bool));
@@ -655,9 +637,37 @@ public class BaseContact extends BaseFrameworkSystem {
 		boolean isFound = (bool == value);
 
 		// Trace message
-		this.getLogger().trace("isFound=" + isFound + " - EXIT!");
+		this.getLogger().trace(MessageFormat.format("isFound={0} - EXIT!", isFound));
 
 		// Return result
 		return isFound;
 	}
+
+	/**
+	 * Some "getter for a value from given column name. This name will be
+	 * translated into a method name and then this method is called.
+	 *
+	 * @param columnName Column name
+	 * @return Value from field
+	 */
+	@Override
+	public Object getValueFromColumn (final String columnName) {
+		// Trace message
+		this.getLogger().trace(MessageFormat.format("columnName={0} - CALLED!", columnName));
+
+		// Convert column name to field name
+		String methodName = this.convertColumnNameToGetterMethod(columnName, true);
+
+		// Debug message
+		this.getLogger().debug(MessageFormat.format("field={0}", methodName));
+
+		// Get field
+		Object value = this.getField(this, "BaseContact", methodName);
+
+		// Trace message
+		this.getLogger().trace("value=" + value + " - EXIT!");
+
+		// Return it
+		return value;
+	}
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/database/backend/DatabaseBackend.java b/Addressbook/src/org/mxchange/addressbook/database/backend/DatabaseBackend.java
index dfcf583..d2def25 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/backend/DatabaseBackend.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/backend/DatabaseBackend.java
@@ -87,4 +87,12 @@ public interface DatabaseBackend extends FrameworkInterface {
 	 * @throws org.mxchange.addressbook.exceptions.BadTokenException If the CSV token is badly formulated
 	 */
 	public Iterator<? extends Storeable> iterator () throws BadTokenException;
+
+	/**
+	 * Reads a single row from database.
+	 * 
+	 * @param rowIndex Row index (or how much to skip)
+	 * @return A Storeable instance
+	 */
+	public Storeable readRow (final int rowIndex);
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/database/backend/csv/Base64CsvDatabaseBackend.java b/Addressbook/src/org/mxchange/addressbook/database/backend/csv/Base64CsvDatabaseBackend.java
index 0cfb7eb..ea1b7bf 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/backend/csv/Base64CsvDatabaseBackend.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/backend/csv/Base64CsvDatabaseBackend.java
@@ -34,6 +34,7 @@ import org.mxchange.addressbook.contact.book.BookContact;
 import org.mxchange.addressbook.contact.user.UserContact;
 import org.mxchange.addressbook.database.backend.BaseDatabaseBackend;
 import org.mxchange.addressbook.database.backend.DatabaseBackend;
+import org.mxchange.addressbook.database.frontend.DatabaseWrapper;
 import org.mxchange.addressbook.database.storage.Storeable;
 import org.mxchange.addressbook.database.storage.csv.StoreableCsv;
 import org.mxchange.addressbook.exceptions.BadTokenException;
@@ -54,14 +55,21 @@ public class Base64CsvDatabaseBackend extends BaseDatabaseBackend implements Dat
 	 * Constructor with table name
 	 *
 	 * @param tableName Name of "table"
+	 * @param wrapper Wrapper instance to call back
 	 */
-	public Base64CsvDatabaseBackend (final String tableName) {
+	public Base64CsvDatabaseBackend (final String tableName, final DatabaseWrapper wrapper) {
+		// Trace message
+		this.getLogger().trace(MessageFormat.format("tableName={0},wrapper={1}", tableName, wrapper)); //NOI18N
+
 		// Debug message
 		this.getLogger().debug(MessageFormat.format("Trying to initialize table {0} ...", tableName)); //NOI18N
 
 		// Set table name here, too
 		this.setTableName(tableName);
 
+		// Set wrapper here
+		this.setWrapper(wrapper);
+
 		// Construct file name
 		String fileName = String.format("data/table_%s.b64", tableName); //NOI18N
 
@@ -246,6 +254,37 @@ public class Base64CsvDatabaseBackend extends BaseDatabaseBackend implements Dat
 		return length;
 	}
 
+	/**
+	 * Reads a single row from database.
+	 * 
+	 * @param rowIndex Row index (or how much to skip)
+	 * @return A Storeable instance
+	 */
+	@Override
+	public Storeable readRow (final int rowIndex) {
+		// First rewind
+		this.rewind();
+
+		// Intialize variables
+		int count = 0;
+		Storeable storeable = null;
+
+		// Read all rows
+		do {
+			// Read row
+			String line = this.readLine();
+
+			// Callback the wrapper to handle parsing
+			storeable = this.getWrapper().parseLineToStoreable(line);
+
+			// Increment counter
+			count++;
+		} while (!this.isEndOfFile() || (count > rowIndex));
+
+		// Return found element
+		return storeable;
+	}
+
 	/**
 	 * Rewinds backend
 	 */
diff --git a/Addressbook/src/org/mxchange/addressbook/database/backend/mysql/MySqlDatabaseBackend.java b/Addressbook/src/org/mxchange/addressbook/database/backend/mysql/MySqlDatabaseBackend.java
index da96483..c2c63f9 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/backend/mysql/MySqlDatabaseBackend.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/backend/mysql/MySqlDatabaseBackend.java
@@ -183,6 +183,11 @@ public class MySqlDatabaseBackend extends BaseDatabaseBackend implements Databas
 		throw new UnsupportedOperationException("Not implemented for this backend."); //NOI18N
 	}
 
+	@Override
+	public Storeable readRow (final int rowIndex) {
+		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+	}
+
 	@Override
 	public void rewind () {
 		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
diff --git a/Addressbook/src/org/mxchange/addressbook/database/frontend/BaseDatabaseFrontend.java b/Addressbook/src/org/mxchange/addressbook/database/frontend/BaseDatabaseFrontend.java
index 3873ef6..10bd035 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/frontend/BaseDatabaseFrontend.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/frontend/BaseDatabaseFrontend.java
@@ -29,7 +29,7 @@ import org.mxchange.addressbook.exceptions.UnsupportedDatabaseDriverException;
  *
  * @author Roland Haeder
  */
-public class BaseDatabaseFrontend extends BaseFrameworkSystem {
+public abstract class BaseDatabaseFrontend extends BaseFrameworkSystem implements DatabaseWrapper {
 
 	/**
 	 * Instance for database backend
@@ -83,7 +83,7 @@ public class BaseDatabaseFrontend extends BaseFrameworkSystem {
 					break;
 
 				case "base64csv": // BASE64-encoded CSV rows //NOI18N
-					this.backend = new Base64CsvDatabaseBackend(this.getTableName());
+					this.backend = new Base64CsvDatabaseBackend(this.getTableName(), this);
 					break;
 
 				default: // Unsupported
diff --git a/Addressbook/src/org/mxchange/addressbook/database/frontend/DatabaseWrapper.java b/Addressbook/src/org/mxchange/addressbook/database/frontend/DatabaseWrapper.java
index ad50bff..d49e630 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/frontend/DatabaseWrapper.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/frontend/DatabaseWrapper.java
@@ -17,6 +17,7 @@
 package org.mxchange.addressbook.database.frontend;
 
 import org.mxchange.addressbook.FrameworkInterface;
+import org.mxchange.addressbook.database.storage.Storeable;
 
 /**
  * A generic interface for database frontends
@@ -24,4 +25,13 @@ import org.mxchange.addressbook.FrameworkInterface;
  * @author Roland Haeder
  */
 public interface DatabaseWrapper extends FrameworkInterface {
+
+	/**
+	 * Parses given line from database backend into a Storeable instance. Please
+	 * note that not all backends need this.
+	 *
+	 * @param line Line from database backend
+	 * @return A Storeable instance
+	 */
+	public Storeable parseLineToStoreable (final String line);
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java b/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java
index 971dd7d..1155aef 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactDatabaseFrontend.java
@@ -213,4 +213,29 @@ public class ContactDatabaseFrontend extends BaseDatabaseFrontend implements Con
 		// Deligate this call to backend
 		return this.getBackend().isRowFound(ContactDatabaseConstants.COLUMN_NAME_OWN_CONTACT, true);
 	}
+
+	/**
+	 * Parses given line from database backend into a Storeable instance. Please
+	 * note that not all backends need this.
+	 *
+	 * @param line Line from database backend
+	 * @return A Storeable instance
+	 */
+	@Override
+	public Storeable parseLineToStoreable (final String line) {
+		throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+	}
+
+	/**
+	 * Reads a single row and parses it to a contact instance
+	 *
+	 * @param rowIndex Row index (also how much to skip)
+	 * @return Contact instance
+	 */
+	@Override
+	public Contact readSingleContact (final int rowIndex) {
+		// Deligate this to backend instance
+		return (Contact) this.getBackend().readRow(rowIndex);
+		
+	}
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactWrapper.java b/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactWrapper.java
index 011f1a5..45e015f 100644
--- a/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactWrapper.java
+++ b/Addressbook/src/org/mxchange/addressbook/database/frontend/contact/ContactWrapper.java
@@ -72,4 +72,12 @@ public interface ContactWrapper extends DatabaseWrapper {
 	 * @throws java.sql.SQLException If any SQL error occurs
 	 */
 	public boolean isOwnContactFound () throws SQLException;
+
+	/**
+	 * Reads a single row and parses it to a contact instance
+	 *
+	 * @param rowIndex Row index (also how much to skip)
+	 * @return Contact instance
+	 */
+	public Contact readSingleContact (final int rowIndex);
 }
diff --git a/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java b/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java
index 66cd7ee..6942ed2 100644
--- a/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java
+++ b/Addressbook/src/org/mxchange/addressbook/manager/contact/ContactManager.java
@@ -508,6 +508,47 @@ public class ContactManager extends BaseManager implements ManageableContact {
 		return this.columnNames.get(columnIndex);
 	}
 
+	/**
+	 * Somewhat "getter" for value from given row and column index
+	 *
+	 * @param rowIndex Row index
+	 * @param columnIndex Column index
+	 * @return Value from given row/column
+	 */
+	@Override
+	public Object getValueFromRowColumn (final int rowIndex, final int columnIndex) {
+		// Trace message
+		this.getLogger().trace(MessageFormat.format("rowIndex={0},columnIndex={1} CALLED!", rowIndex, columnIndex));
+
+		// Then get specific row from database which is a Contact instance
+		Contact contact = this.getContactDatabase().readSingleContact(rowIndex);
+
+		// Debug message
+		this.getLogger().debug(MessageFormat.format("contact={0}", contact));
+
+		// It may return null
+		if (contact == null) {
+			// Nothing found
+			this.getLogger().warn("contact is null - returning null ...");
+			return null;
+		}
+
+		// Convert column index -> name
+		String columnName = this.getColumnName(columnIndex);
+
+		// Debug message
+		this.getLogger().debug(MessageFormat.format("columnName={0}", columnName));
+
+		// Now get that column
+		Object value = contact.getValueFromColumn(columnName);
+
+		// Trace message
+		this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value));
+
+		// Return it
+		return value;
+	}
+
 	/**
 	 * Checks whether own contact is already added by checking all entries for
 	 * isOwnContact flag
diff --git a/Addressbook/src/org/mxchange/addressbook/manager/contact/ManageableContact.java b/Addressbook/src/org/mxchange/addressbook/manager/contact/ManageableContact.java
index 8343ffa..e2d0ce0 100644
--- a/Addressbook/src/org/mxchange/addressbook/manager/contact/ManageableContact.java
+++ b/Addressbook/src/org/mxchange/addressbook/manager/contact/ManageableContact.java
@@ -143,6 +143,15 @@ public interface ManageableContact extends Manageable {
 	 */
 	public String getColumnName (final int columnIndex);
 
+	/**
+	 * Somewhat "getter" for value from given row and column index
+	 *
+	 * @param rowIndex Row index
+	 * @param columnIndex Column index
+	 * @return Value from given row/column
+	 */
+	public Object getValueFromRowColumn (final int rowIndex, final int columnIndex);
+
 	/**
 	 * Adds given contact to address book
 	 *
diff --git a/Addressbook/src/org/mxchange/addressbook/model/contact/ContactTableModel.java b/Addressbook/src/org/mxchange/addressbook/model/contact/ContactTableModel.java
index c9ad5bd..7a0a48e 100644
--- a/Addressbook/src/org/mxchange/addressbook/model/contact/ContactTableModel.java
+++ b/Addressbook/src/org/mxchange/addressbook/model/contact/ContactTableModel.java
@@ -49,7 +49,8 @@ public class ContactTableModel extends BaseModel implements TableModel {
 
 	@Override
 	public Class<?> getColumnClass (final int columnIndex) {
-		throw new UnsupportedOperationException("Not supported yet. columnIndex=" + columnIndex); //To change body of generated methods, choose Tools | Templates.
+		// All is the same
+		return Object.class;
 	}
 
 	@Override
@@ -72,7 +73,8 @@ public class ContactTableModel extends BaseModel implements TableModel {
 
 	@Override
 	public Object getValueAt (final int rowIndex, final int columnIndex) {
-		throw new UnsupportedOperationException("Not supported yet. rowIndex=" + rowIndex + ",columnIndex=" + columnIndex); //To change body of generated methods, choose Tools | Templates.
+		// Let the manager do this job for us
+		return this.getClient().getContactManager().getValueFromRowColumn(rowIndex, columnIndex);
 	}
 
 	@Override
-- 
2.39.5