From d669393da622147ef775a088564719dbc5ff9391 Mon Sep 17 00:00:00 2001 From: Roland Haeder 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 --- .../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 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) 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 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) 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 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