Hi digulla,

Factory wouldn't need to extend Connection, it could simply provide the same method signatures and delegate to the underlying connection. Take a look at the attached class that does this. Ideally this functionality should be built into Factory instead of having to wrap it with a second class.

Gili

On 13/06/2012 1:48 PM, digulla wrote:
Am Montag, 11. Juni 2012 21:16:56 UTC+2 schrieb Gili Tzabari:

      What about committing transactions? If I have to invoke
    Factory.getConnection().commit() after the JOOQ code I still end
    up having to catch both DataAccessException and SQLException.
    Couldn't Factory.getConnection() return a wrapper object?


Not really. There is no sane way to extend most JDBC classes in Java code - compilation will break with different versions of Java, for example.

I would prefer if "new Factory()" would accept a wrapper object instead; that would ease the migration path to new versions of JDBC and make the API cleaner. If this wrapper would have this API:

    getConnection() // get underlying JDBC connection
    commit() // commit the current transaction
    rollback() // ...

then such things would be possible.

package com.vetailr.service;

import com.google.inject.Inject;
import com.google.inject.servlet.RequestScoped;
import java.math.BigInteger;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.jooq.Attachable;
import org.jooq.Batch;
import org.jooq.BatchBindStep;
import org.jooq.Condition;
import org.jooq.Cursor;
import org.jooq.DeleteQuery;
import org.jooq.DeleteWhereStep;
import org.jooq.FactoryOperations;
import org.jooq.Field;
import org.jooq.Insert;
import org.jooq.InsertQuery;
import org.jooq.InsertSetStep;
import org.jooq.InsertValuesStep;
import org.jooq.LoaderOptionsStep;
import org.jooq.MergeUsingStep;
import org.jooq.Query;
import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.ResultQuery;
import org.jooq.SQLDialect;
import org.jooq.Schema;
import org.jooq.SchemaMapping;
import org.jooq.Select;
import org.jooq.SelectQuery;
import org.jooq.SelectSelectStep;
import org.jooq.Sequence;
import org.jooq.SimpleSelectQuery;
import org.jooq.SimpleSelectWhereStep;
import org.jooq.Table;
import org.jooq.TableLike;
import org.jooq.TableRecord;
import org.jooq.Truncate;
import org.jooq.UDT;
import org.jooq.UDTRecord;
import org.jooq.UpdatableRecord;
import org.jooq.UpdateQuery;
import org.jooq.UpdateSetStep;
import org.jooq.conf.Settings;
import org.jooq.exception.DataAccessException;
import org.jooq.impl.Factory;

/**
 * An abstraction of a database connection.
 * <p/>
 * @author Gili Tzabari
 */
@RequestScoped
public class DatabaseConnection implements FactoryOperations
{
        private static final long serialVersionUID = 1L;
        private final Factory database;

        @Inject
        public DatabaseConnection(Factory database)
        {
                this.database = database;
        }

        /**
         * Sets this session's auto-commit mode to the given state. If a 
session is in auto-commit mode,
         * then all its SQL statements will be executed and committed as 
individual transactions.
         * Otherwise, its SQL statements are grouped into transactions that are 
terminated by a call to
         * either the method
         * <code>commit</code> or the method
         * <code>rollback</code>. By default, new sessions are in auto-commit 
mode. <P> The commit occurs
         * when the statement completes. The time when the statement completes 
depends on the type of SQL
         * Statement: <ul> <li>For DML statements, such as Insert, Update or 
Delete, and DDL statements,
         * the statement is complete as soon as it has finished executing. 
<li>For Select statements, the
         * statement is complete when the associated result set is closed. 
<li>For
         * <code>CallableStatement</code> objects or for statements that return 
multiple results, the
         * statement is complete when all of the associated result sets have 
been closed, and all update
         * counts and output parameters have been retrieved. </ul> <P> 
<B>NOTE:</B> If this method is
         * called during a transaction and the auto-commit mode is changed, the 
transaction is committed.
         * If
         * <code>setAutoCommit</code> is called and the auto-commit mode is not 
changed, the call is a
         * no-op.
         * <p/>
         * @param autoCommit <code>true</code> to enable auto-commit mode; 
<code>false</code> to disable
         *                    it
         * @throws DataAccessException if a database access error occurs, 
setAutoCommit(true) is called
         *                              while participating in a distributed 
transaction, or this method is
         *                              called on a closed session
         * @see #isAutoCommit
         */
        public void setAutoCommit(boolean autoCommit)
        {
                try
                {
                        database.getConnection().setAutoCommit(autoCommit);
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Indicates if the current auto-commit mode for this
         * <code>DatabaseConnection</code> object.
         * <p/>
         * @return the current state of this <code>DatabaseConnection</code> 
object's auto-commit mode
         * @throws DataAccessException if a database access error occurs or 
this method is called on a
         *                              closed session
         * @see #setAutoCommit
         */
        public boolean isAutoCommit()
        {
                try
                {
                        return database.getConnection().getAutoCommit();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Makes all changes made since the previous commit/rollback permanent 
and releases any database
         * locks currently held by this
         * <code>DatabaseConnection</code> object. This method should be used 
only when auto-commit mode
         * has been disabled.
         * <p/>
         * @throws DataAccessException if a database access error occurs, this 
method is called while
         *                              participating in a distributed 
transaction, if this method is
         *                              called on a closed session or the 
<code>DatabaseConnection</code>
         *                              object is in auto-commit mode.
         * @see #setAutoCommit
         */
        public void commit()
        {
                try
                {
                        database.getConnection().commit();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Undoes all changes made in the current transaction and releases any 
database locks currently
         * held by the
         * <code>DatabaseConnection</code> object. This method should be used 
only when auto-commit mode
         * has been disabled.
         * <p/>
         * @throws DataAccessException if a database access error occurs, this 
method is called while
         *                              participating in a distributed 
transaction, this method is called
         *                              on a closed session or the 
<code>DatabaseConnection</code> object
         *                              is in auto-commit mode
         * @see #setAutoCommit
         */
        public void rollback()
        {
                try
                {
                        database.getConnection().rollback();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Releases the
         * <code>DatabaseConnection</code> object's database and JDBC resources 
immediately instead of
         * waiting for them to be automatically released. <P> Calling the method
         * <code>close</code> on a
         * <code>DatabaseConnection</code> object that is already closed is a 
no-op. <P> It is <b>strongly
         * recommended</b> that an application explicitly commits or rolls back 
an active transaction
         * prior to calling the
         * <code>close</code> method. If the
         * <code>close</code> method is called and there is an active 
transaction, the results are
         * implementation-defined. <P>
         * <p/>
         * @throws DataAccessException if a database access error occurs
         */
        public void close()
        {
                try
                {
                        database.getConnection().close();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Indicates whether this
         * <code>DatabaseConnection</code> object has been closed. A session is 
closed if the method
         * <code>close</code> has been called on it or if certain fatal errors 
have occurred. This method
         * is guaranteed to return
         * <code>true</code> only when it is called after the method
         * <code>DatabaseConnection.close</code> has been called. <P> This 
method generally cannot be
         * called to determine whether a connection to a database is valid or 
invalid. A typical client
         * can determine that a connection is invalid by catching any 
exceptions that might be thrown when
         * an operation is attempted.
         * <p/>
         * @return <code>true</code> if this <code>DatabaseConnection</code> 
object is
         *          closed; <code>false</code> if it is still open
         * @throws DataAccessException if a database access error occurs
         */
        public boolean isClosed()
        {
                try
                {
                        return database.getConnection().isClosed();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Puts this session in read-only mode as a hint to the driver to 
enable database optimizations.
         * <p/>
         * <P><B>Note:</B> This method cannot be called during a transaction.
         * <p/>
         * @param readOnly <code>true</code> enables read-only mode; 
<code>false</code> disables it
         * @throws DataAccessException if a database access error occurs, this 
method is called on a
         *                              closed session or this method is called 
during a transaction
         */
        public void setReadOnly(boolean readOnly)
        {
                try
                {
                        database.getConnection().isClosed();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Retrieves whether this
         * <code>DatabaseConnection</code> object is in read-only mode.
         * <p/>
         * @return <code>true</code> if this <code>DatabaseConnection</code> 
object is   *          read-only; <code>false</code> otherwise
         * @throws DataAccessException SQLException if a database access error 
occurs or this method is
         *                              called on a closed session
         */
        public boolean isReadOnly()
        {
                try
                {
                        return database.getConnection().isReadOnly();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Sets the given catalog name in order to select a subspace of this
         * <code>DatabaseConnection</code> object's database in which to work. 
<P> If the driver does not
         * support catalogs, it will silently ignore this request.
         * <p/>
         * @param catalog the name of a catalog (subspace in this 
<code>DatabaseConnection</code> object's
         *                 database) in which to work
         * @throws DataAccessException if a database access error occurs or 
this method is called on a
         *                              closed session
         * @see #getCatalog
         */
        public void setCatalog(String catalog)
        {
                try
                {
                        database.getConnection().setCatalog(catalog);
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Retrieves this
         * <code>DatabaseConnection</code> object's current catalog name.
         * <p/>
         * @return the current catalog name or <code>null</code> if there is 
none
         * @throws DataAccessException if a database access error occurs or 
this method is called on a
         *                              closed session
         * @see #setCatalog
         */
        public String getCatalog()
        {
                try
                {
                        return database.getConnection().getCatalog();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Attempts to change the transaction isolation level for this
         * <code>DatabaseConnection</code> object to the one given. <P> 
<B>Note:</B> If this method is
         * called during a transaction, the result is implementation-defined.
         * <p/>
         * @param level the transaction isolation level. (Note that 
<code>TransactionIsolation.NONE</code>
         *               cannot be used because it specifies that transactions 
are not supported.)
         * @throws DataAccessException if a database access error occurs, this 
method is called on a
         *                              closed session
         * @see DatabaseMetaData#supportsTransactionIsolationLevel
         * @see #getTransactionIsolation
         */
        public void setTransactionIsolation(TransactionIsolation level)
        {
                try
                {
                        
database.getConnection().setTransactionIsolation(level.getId());
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Retrieves this
         * <code>DatabaseConnection</code> object's current transaction 
isolation level.
         * <p/>
         * @return the current transaction isolation level
         * @throws DataAccessException if a database access error occurs or 
this method is called on a
         *                              closed session
         * @see #setTransactionIsolation
         */
        public TransactionIsolation getTransactionIsolation()
        {
                try
                {
                        return 
TransactionIsolation.fromConnection(database.getConnection().getTransactionIsolation());
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Retrieves the first warning reported by calls on this
         * <code>DatabaseConnection</code> object. If there is more than one 
warning, subsequent warnings
         * will be chained to the first one and can be retrieved by calling the 
method
         * <code>SQLWarning.getNextWarning</code> on the warning that was 
retrieved previously. <P> This
         * method may not be called on a closed session; doing so will cause a
         * <code>DataAccessException</code> to be thrown.
         * <p/>
         * <P><B>Note:</B> Subsequent warnings will be chained to this 
SQLWarning.
         * <p/>
         * @return the first <code>SQLWarning</code> object or 
<code>null</code> if there are none
         * @throws DataAccessException if a database access error occurs or 
this method is called on a
         *                              closed session
         * @see SQLWarning
         */
        public SQLWarning getWarnings()
        {
                try
                {
                        return database.getConnection().getWarnings();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Clears all warnings reported for this
         * <code>DatabaseConnection</code> object. After a call to this method, 
the method
         * <code>getWarnings</code> returns
         * <code>null</code> until a new warning is reported for this
         * <code>DatabaseConnection</code> object.
         * <p/>
         * @throws DataAccessException SQLException if a database access error 
occurs or this method is
         *                              called on a closed session
         */
        public void clearWarnings()
        {
                try
                {
                        database.getConnection().clearWarnings();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Returns true if the session has not been closed and is still valid. 
The driver shall submit a
         * query on the session or use some other mechanism that positively 
verifies the session is still
         * valid when this method is called. <p> The query submitted by the 
driver to validate the session
         * shall be executed in the context of the current transaction.
         * <p/>
         * @param timeout The time in seconds to wait for the database 
operation used to validate the
         *                 session to complete. If the timeout period expires 
before the operation
         *                 completes, this method returns false. A value of 0 
indicates a timeout is not
         *                 applied to the database operation.
         * @return true if the session is valid, false otherwise
         * @throws DataAccessException if the value supplied for 
<code>timeout</code> is less then 0
         * @since 1.6
         * @see java.sql.DatabaseMetaData#getClientInfoProperties
         */
        public boolean isValid(int timeout)
        {
                try
                {
                        return database.getConnection().isValid(timeout);
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        /**
         * Constructs an object that implements the
         * <code>Blob</code> interface. The object returned initially contains 
no data. The
         * <code>setBinaryStream</code> and
         * <code>setBytes</code> methods of the
         * <code>Blob</code> interface may be used to add data to the
         * <code>Blob</code>.
         * <p/>
         * @return An object that implements the <code>Blob</code> interface
         * @throws DataAccessException if an object that implements the 
<code>Blob</code> interface can
         *                              not be constructed, this method is 
called on a closed connection, a
         *                              database access error occurs or if the 
JDBC driver does not support
         *                              this data type
         * @since 1.6
         */
        public Blob createBlob()
        {
                try
                {
                        return database.getConnection().createBlob();
                }
                catch (SQLException e)
                {
                        throw new DataAccessException("", e);
                }
        }

        @Override
        public final SQLDialect getDialect()
        {
                return database.getDialect();
        }

        @Override
        public final Connection getConnection()
        {
                return database.getConnection();
        }

        @Override
        public final void setConnection(Connection connection)
        {
                database.setConnection(connection);
        }

        @Override
        @SuppressWarnings("deprecation")
        public final SchemaMapping getSchemaMapping()
        {
                return database.getSchemaMapping();
        }

        @Override
        public final Settings getSettings()
        {
                return database.getSettings();
        }

        @Override
        public final Map<String, Object> getData()
        {
                return database.getData();
        }

        @Override
        public final Object getData(String key)
        {
                return database.getData(key);
        }

        @Override
        public final Object setData(String key, Object value)
        {
                return database.setData(key, value);
        }

        @Override
        public final String render(QueryPart part)
        {
                return database.render(part);
        }

        @Override
        public final String renderNamedParams(QueryPart part)
        {
                return database.renderNamedParams(part);
        }

        @Override
        public final String renderInlined(QueryPart part)
        {
                return database.renderInlined(part);
        }

        @Override
        public final void attach(Attachable... attachables)
        {
                database.attach(attachables);
        }

        @Override
        public final void attach(Collection<Attachable> attachables)
        {
                database.attach(attachables);
        }

        @Override
        public final <R extends TableRecord<R>> LoaderOptionsStep<R> 
loadInto(Table<R> table)
        {
                return database.loadInto(table);
        }

        @Override
        public final Query query(String sql)
        {
                return database.query(sql);
        }

        @Override
        public final Query query(String sql, Object... bindings)
        {
                return database.query(sql, bindings);
        }

        @Override
        public final Result<Record> fetch(String sql)
        {
                return database.fetch(sql);
        }

        @Override
        public final Result<Record> fetch(String sql, Object... bindings)
        {
                return database.fetch(sql, bindings);
        }

        @Override
        public final Cursor<Record> fetchLazy(String sql) throws 
DataAccessException
        {
                return database.fetchLazy(sql);
        }

        @Override
        public final Cursor<Record> fetchLazy(String sql, Object... bindings) 
throws DataAccessException
        {
                return database.fetchLazy(sql, bindings);
        }

        @Override
        public final List<Result<Record>> fetchMany(String sql)
        {
                return database.fetchMany(sql);
        }

        @Override
        public final List<Result<Record>> fetchMany(String sql, Object... 
bindings)
        {
                return database.fetchMany(sql, bindings);
        }

        @Override
        public final Record fetchOne(String sql)
        {
                return database.fetchOne(sql);
        }

        @Override
        public final Record fetchOne(String sql, Object... bindings)
        {
                return database.fetchOne(sql, bindings);
        }

        @Override
        public final int execute(String sql) throws DataAccessException
        {
                return database.execute(sql);
        }

        @Override
        public final int execute(String sql, Object... bindings) throws 
DataAccessException
        {
                return database.execute(sql, bindings);
        }

        @Override
        public final ResultQuery<Record> resultQuery(String sql) throws 
DataAccessException
        {
                return database.resultQuery(sql);
        }

        @Override
        public final ResultQuery<Record> resultQuery(String sql, Object... 
bindings) throws
                DataAccessException
        {
                return database.resultQuery(sql, bindings);
        }

        @Override
        public final Result<Record> fetch(ResultSet rs)
        {
                return database.fetch(rs);
        }

        @Override
        public final <R extends Record> SimpleSelectWhereStep<R> 
selectFrom(Table<R> table)
        {
                return database.selectFrom(table);
        }

        @Override
        public final SelectSelectStep select(Field<?>... fields)
        {
                return database.select(fields);
        }

        @Override
        public final SelectSelectStep selectZero()
        {
                return database.selectZero();
        }

        @Override
        public final SelectSelectStep selectOne()
        {
                return database.selectOne();
        }

        @Override
        public final SelectSelectStep selectCount()
        {
                return database.selectCount();
        }

        @Override
        public final SelectSelectStep selectDistinct(Field<?>... fields)
        {
                return database.selectDistinct(fields);
        }

        @Override
        public final SelectSelectStep select(Collection<? extends Field<?>> 
fields)
        {
                return database.select(fields);
        }

        @Override
        public final SelectSelectStep selectDistinct(Collection<? extends 
Field<?>> fields)
        {
                return database.selectDistinct(fields);
        }

        @Override
        public final SelectQuery selectQuery()
        {
                return database.selectQuery();
        }

        @Override
        public final <R extends Record> SimpleSelectQuery<R> 
selectQuery(TableLike<R> table)
        {
                return database.selectQuery(table);
        }

        @Override
        public final <R extends Record> InsertQuery<R> insertQuery(Table<R> 
into)
        {
                return database.insertQuery(into);
        }

        @Override
        public final <R extends Record> InsertSetStep<R> insertInto(Table<R> 
into)
        {
                return database.insertInto(into);
        }

        @Override
        public final <R extends Record> InsertValuesStep<R> insertInto(Table<R> 
into,
                Field<?>... fields)
        {
                return database.insertInto(into, fields);
        }

        @Override
        public final <R extends Record> InsertValuesStep<R> insertInto(Table<R> 
into,
                Collection<? extends Field<?>> fields)
        {
                return database.insertInto(into, fields);
        }

        @Override
        @SuppressWarnings("deprecation")
        public final <R extends Record> Insert<R> insertInto(Table<R> into,
                Select<?> select)
        {
                return database.insertInto(into, select);
        }

        @Override
        public final <R extends Record> UpdateQuery<R> updateQuery(Table<R> 
table)
        {
                return database.updateQuery(table);
        }

        @Override
        public final <R extends Record> UpdateSetStep<R> update(Table<R> table)
        {
                return database.update(table);
        }

        @Override
        public final <R extends Record> MergeUsingStep<R> mergeInto(Table<R> 
table)
        {
                return database.mergeInto(table);
        }

        @Override
        public final <R extends Record> DeleteQuery<R> deleteQuery(Table<R> 
table)
        {
                return database.deleteQuery(table);
        }

        @Override
        public final <R extends Record> DeleteWhereStep<R> delete(Table<R> 
table)
        {
                return database.delete(table);
        }

        @Override
        public final Batch batch(Query... queries)
        {
                return database.batch(queries);
        }

        @Override
        public final Batch batch(Collection<? extends Query> queries)
        {
                return database.batch(queries);
        }

        @Override
        public final BatchBindStep batch(Query query)
        {
                return database.batch(query);
        }

        @Override
        public final Batch batchStore(UpdatableRecord<?>... records)
        {
                return database.batchStore(records);
        }

        @Override
        public final <R extends TableRecord<R>> Truncate<R> truncate(Table<R> 
table)
        {
                return database.truncate(table);
        }

        @Override
        public final BigInteger lastID()
        {
                return database.lastID();
        }

        @Override
        public final <T extends Number> T nextval(Sequence<T> sequence)
        {
                return database.nextval(sequence);
        }

        @Override
        public final <T extends Number> T currval(Sequence<T> sequence)
        {
                return database.currval(sequence);
        }

        @Override
        public final int use(Schema schema)
        {
                return database.use(schema);
        }

        @Override
        public final int use(String schema)
        {
                return database.use(schema);
        }

        @Override
        public final <R extends UDTRecord<R>> R newRecord(UDT<R> type)
        {
                return database.newRecord(type);
        }

        @Override
        public final <R extends TableRecord<R>> R newRecord(Table<R> table)
        {
                return database.newRecord(table);
        }

        @Override
        public final <R extends TableRecord<R>> R newRecord(Table<R> table, 
Object source)
        {
                return database.newRecord(table, source);
        }

        @Override
        public final <R extends Record> Result<R> fetch(Table<R> table)
        {
                return database.fetch(table);
        }

        @Override
        public final <R extends Record> Result<R> fetch(Table<R> table, 
Condition condition)
        {
                return database.fetch(table, condition);
        }

        @Override
        public final <R extends Record> R fetchOne(Table<R> table)
        {
                return database.fetchOne(table);
        }

        @Override
        public final <R extends Record> R fetchOne(Table<R> table, Condition 
condition)
        {
                return database.fetchOne(table, condition);
        }

        @Override
        public final <R extends Record> R fetchAny(Table<R> table)
        {
                return database.fetchAny(table);
        }

        @Override
        public final <R extends TableRecord<R>> int executeInsert(Table<R> 
table, R record)
        {
                return database.executeInsert(table, record);
        }

        @Override
        public final <R extends TableRecord<R>> int executeUpdate(Table<R> 
table, R record)
        {
                return database.executeUpdate(table, record);
        }

        @Override
        public final <R extends TableRecord<R>, T> int executeUpdate(Table<R> 
table, R record,
                Condition condition)
        {
                return database.executeUpdate(table, record, condition);
        }

        @Override
        public final <R extends TableRecord<R>> int executeUpdateOne(Table<R> 
table, R record)
        {
                return database.executeUpdateOne(table, record);
        }

        @Override
        public final <R extends TableRecord<R>, T> int 
executeUpdateOne(Table<R> table, R record,
                Condition condition)
        {
                return database.executeUpdateOne(table, record, condition);
        }

        @Override
        public final <R extends TableRecord<R>> int executeDelete(Table<R> 
table)
        {
                return database.executeDelete(table);
        }

        @Override
        public final <R extends TableRecord<R>, T> int executeDelete(Table<R> 
table, Condition condition)
        {
                return database.executeDelete(table, condition);
        }

        @Override
        public final <R extends TableRecord<R>> int executeDeleteOne(Table<R> 
table)
        {
                return database.executeDeleteOne(table);
        }

        @Override
        public final <R extends TableRecord<R>, T> int 
executeDeleteOne(Table<R> table,
                Condition condition)
        {
                return database.executeDeleteOne(table, condition);
        }

        @Override
        public String toString()
        {
                return database.toString();
        }
}

Reply via email to