Implementing Callbacks
This section describes how to implement callbacks.
Implementing Database Callbacks
To implement a database callback:
2. Redefine the necessary callback methods in the derived class. All the callback methods in the base class are defined as empty methods. The redefined methods can use the accessor method environmentHandle() to access the database specific environment/context handles. They can use the status() and setError() methods to set any errors and invoke the error handler.
3. Optionally, redefine the producer method
produceConnCallback() to produce a
RWDBConnCallback object to be associated with every new connection produced from this
RWDBDatabase object this callback will be associated with. Note, however, this method will not be used if a custom
RWDBConnCallback object is supplied in the
RWDBDatabase::connection() call.
4. Provide an instance of the derived class in the method
RWDBManager::database() to produce an
RWDBDatabase object that will call the callback methods. Each
RWDBDatabase object has its own database callback instance, thus allowing different behaviors for different
RWDBDatabase objects.
RWDBManager::database(
"accesslib", "servername", "username",
"password", "databasename",
RWDBDATABASECALLBACK(UserDatabaseCallbackImp));
The instance of the derived class must be produced using the macro
RWDBDATABASECALLBACK. This ensures that a new instance of the database callback gets produced for each
RWDBDatabase object. Just providing the name of the derived callback class, will create its instance using the default constructor. To use a different constructor, pass the arguments along with it. For example:
RWDBDATABASECALLBACK(UserDatabaseCallbackImp(100, "abc")).
Providing a Password using connParams()
You can enable your application to request a password via the connParams() callback rather than passing it directly in the RWDBManager::database() call. This option may provide increased security as it avoids storing the password in memory and instead requests it using the callback only when needed. This method takes all the parameters to establish a database connection, but all parameters except password are const so cannot be changed:
virtual void
connParams (const RWCString &serverName, const RWCString &userName,
RWCString &password, const RWCString &databaseName,
const RWCString &propertyString)
To use this API, define a database callback class as usual derived from
RWDBDatabaseCallbackImp, then implement its
connParams() method to retrieve the database password to use while establishing a connection.
For example:
class MyDBCallback: public RWDBDatabaseCallbackImp
{
public:
// Constructors
MyDBCallback() {...}
...
virtual void connParams(const RWCString& dbServer, // server name
const RWCString& username, // username
RWCString& password, // password
const RWCString& databaseName, // database name
// string used for access module specific properties
const RWCString& propertyString)
{
// user function to retrieve the password
password = getThePassword();
}
...
};
Provide this callback to the
RWDBManager’s
database() function when connecting to the database, and SourcePro DB will invoke the callback you implemented to retrieve the password.
RWDBDatabase myDbase = RWDBManager::database(
"accesslib", "servername", "username",
"password", "databasename",
RWDBDATABASECALLBACK(MyDBCallback));
Implementing Connection Callbacks
To implement connection callbacks:
1. Create a derived class (for example,
UserConnCallbackImp) from the base class
RWDBConnCallbackImp.
2. Redefine the necessary callback methods in the derived class. All the callback methods in the base class are defined as empty methods. The redefined methods can use the accessor method
systemHandle() to access the database-specific connection handle. Accessor methods
databaseCallback() and
environmentHandle() provide access to the
RWDBDatabaseCallback associated with the
RWDBDatabase object that produced this
RWDBConnection and to the environment handle associated with the
RWDBDatabase object. The callback methods can use the
status() and
setError() methods to set any errors and invoke the error handler.
3. Provide an instance of the derived class in the method
RWDBDatabase::connection() to produce an
RWDBConnection object that will call the callback methods. Each
RWDBConnection object may be associated with different connection callback classes to have different behavior. For example:
dbase.connection(RWDBCONNCALLBACK(UserConnCallbackImp));
The instance of the derived class must be produced using the macro RWDBCONNCALLBACK. This ensures that a new instance of the connection callback gets produced for each
RWDBConnection produced. Just providing the name of the derived callback class, will create its instance using the default constructor. To use a different constructor, pass the arguments along with it. For example:
RWDBCONNCALLBACK(UserConnCallbackImp(10, "xyz")).
4. To avoid passing an instance of the connection callback to every new connection, you can produce the instance of the connection callback by redefining the producer method
produceConnCallback() in
RWDBDatabaseCallbackImp class.
The connection callback will be produced for all implicit and explicit connections produced from that
RWDBDatabase with which the database callback is associated. For example:
RWDBConnCallback
UserDatabaseCallbackImp::produceConnCallback() {
return RWDBCONNCALLBACK(UserConnCallbackImp));
}