dtl
Category: functors | Component type: concept |
An IOHandler is a
function object (or a wrapped function pointer if you use
cb_ptr_fun_w_ret())
that is called when exceptions are thrown in DB_iterator operations. The
handler uses the state of the iterator passed in to decide how to
process the exception. After performing its work, the handler
tells the iterator whether to suppress the error (dtl_ios_base::SUPPRESS_ERROR) or
to re-throw the exception (dtl_ios_base::THROW_EXCEPTION). To use
the IOHandler facility,
declare your own handler class as shown in the examples below. To install a handler,
pass your handler to the iterator's set_io_handler() function.
For example, suppose your handler is of type MyHandler<DataObj, ParamObj> and you wish to pass it
to an iterator called DB_iterator<DataObj,
ParamObj> it. You would use set_io_handler() by saying: it.set_io_handler(MyHandler<DataObj,
ParamObj>()). Later on, you may need to
extract things such as an error log from your handler or other
state information. To query your handler,
extract it by invoking
it.get_io_handler((MyHandler *) NULL). The dummy pointer is passed in to tell the compiler the
type of the result of get_io_handler().
You can also set a default handler for a DBView so that all
newly created iterators over that view will use this default handler if they don't
explicitly install their own handler. To set the default handlder for a DBView call the get_io_handler() and set_io_handler()
methods for the DBView. The handler for a DBView defaults
to whatever handler is #defined as the macro DEFAULT_IO_HANDLER
. If the user
doesn't specify a default, then DTL sets the macro to be AlwaysThrowsHandler
, which rethrows the exception. Finally, if you are working with an IndexedDBView you can call IndexedDBView::get_io_handler() to get the handler of the underlying DBView that it uses.
Defined in the DBView.h header file.
AlwaysThrowsHandler, LoggingHandler.
// *** Note: this is the actual LoggingHandler template from the DTL code ***
// this handler logs exceptions to a vector
// then tells caller to reperform the action
template<class DataObj, class ParamObj = DefaultParamObj<DataObj> > class LoggingHandler
{
public:
struct LoggedTriple
{
string errmsg;
DataObj dataObj;
ParamObj paramObj;
LoggedTriple() : errmsg(""), dataObj(), paramObj() { }
LoggedTriple(const string &msg, const DataObj &data, const ParamObj ¶m) :
errmsg(msg), dataObj(data), paramObj(param) { }
};
private:
CountedPtr<vector<LoggedTriple> > errorLog;// all copies of the handler will share this error log
public:
LoggingHandler() :
errorLog() { }
dtl_ios_base::MeansOfRecovery
operator()(RootException &ex, dtl_ios_base &base,
DataObj &data, ParamObj ¶ms)
{
// log the error
errorLog.push_back(LoggedTriple(ex.what(), data, params));
// tell the program to continue
return dtl_ios_base::SUPPRESS_ERROR;
}
vector<LoggedTriple> GetLog() const
{
return errorLog;
}
};
// Example Code Using LoggingHandler on a DBView
// test of failed SelValidate() when reading data
void TestBadSelValidate()
{
vector<Example> results;
// construct view
// DBView<Example> is actually DBView<Example,
// DefaultParamObj<Example> > thanks to the default
// argument to the DBView template
// use our bad BCA which references a nonexistent column name in DB_EXAMPLE
DBView<Example>
view("DB_EXAMPLE", BCAExampleObj(),
"WHERE INT_VALUE BETWEEN (?) AND (?) AND "
"STRING_VALUE = (?) OR EXAMPLE_DATE < (?) ORDER BY EXAMPLE_LONG",
BPAExampleObj(), BadSelValidate());
view.set_io_handler(LoggingHandler<Example>());
// loop through query results and add them to our vector
// in this loop, read_it.GetLastCount() records read from DB
DBView<Example>::select_iterator read_it = view.begin();
// set parameter values for the WHERE clause in our SQL query
read_it.Params().lowIntValue = 2;
read_it.Params().highIntValue = 8;
read_it.Params().strValue = "Example";
TIMESTAMP_STRUCT paramDate = {2000, 1, 1, 0, 0, 0, 0};
read_it.Params().dateValue = paramDate;
for ( ; read_it != view.end(); read_it++)
{
try
{
// note that the read_iterator::GetLastCount() is incremented in operator++()
// remember that the record is fetched and thus the count incremented
// before operator*() is applied to the read_iterator
cout << "Reading element #" << read_it.GetLastCount() << endl;
cout << "read_it->exampleInt = " << read_it->exampleInt << endl;
cout << "read_it->exampleStr = " << read_it->exampleStr << endl;
results.push_back(*read_it);
}
catch (RootException &ex)
{
cout << "Caught Exception!!!!" << endl;
cout << ex.what() << endl;
}
}
LoggingHandler<Example> handler =
read_it.get_io_handler((LoggingHandler<Example> *) NULL);
typedef LoggingHandler<Example>::LoggedTriple LoggedTriple;
vector<LoggedTriple> errors = handler.GetLog();
for (vector<LoggedTriple>::iterator log_it = errors.begin(); log_it != errors.end();
log_it++)
{
LoggedTriple error = *log_it;
cout << "Error msg = " << error.errmsg << endl;
cout << "Example = " << error.dataObj << endl;
}
}
// Let's Use our X-Ray Vision to Look at the Innards of our Hero
template<class DataObj, class ParamObj = DefaultParamObj<DataObj> > class OurHeroicHandler
{
private:
// ... some state data, but assume handler is default constructible
public:
dtl_ios_base::MeansOfRecovery
operator()(RootException &ex, dtl_ios_base &base,
DataObj &data, ParamObj ¶ms)
{
// example of what you might do in a handler
if (bad())
{
LogErrorToFile(ex);
return dtl_ios_base::THROW_EXCEPTION;
}
else if (fail())
{
// tries to make the DataObj valid and then reapplies previous operation
// to base on the good object ... may still fail
bool failed = WorkMagicOnDataObjAndTryAgain(...);
if (failed)
{
LogErrorToFile(ex);
return dtl_ios_base::THROW_EXCEPTION;
}
else
return dtl_ios_base::SUPPRESS_ERROR; // success ... our superhero
// has saved the day!
}
}
};
None.
Parameter | Description | Default |
---|---|---|
DataObj | The value type of objects in a DBView. | |
ParamObj | The type of object used to specify the postfix parameters to the DBView. | DefaultParamObj<DataObj> |
X | A type that is a model of IOHandler |
a | Object of type X |
Name | Expression | Precondition | Semantics | Postcondition |
---|---|---|---|---|
Default constructor | X a() |
Construct the function object. | ||
Copy constructor | X a(constX &b) |
Copy construct the IOHandler. | ||
UserHandler constructor | template<class UserHandler> a(const UserHandler hb) |
Construct the IOHandler using the user-defined handler ( it's type is bound to the UserHandler template parameter) passed in (the example classes above declare such handlers).. | ||
Assignment Operator | X operator=(const X &b) | Assign the IOHandler. | ||
Handle exception operator | dtl_ios_base::MeansOfRecovery operator()(RootException &ex, dtl_ios_base &base, DataObj &data, ParamObj ¶ms) |
This operator takes references to the thrown RootException object, the dtl_ios_base (iterator) which threw, and the DataObj and ParamObj relevant to the exception. Handles the exception and then returns whether the iterator should suppress the error (dtl_ios_base::SUPPRESS_ERROR) or whether to still throw the exception (dtl_ios_base::THROW_EXCEPTION). | ||
Get UserHandler | template<class UserHandler> const UserHandler & get(const UserHandler *dummy) const |
Returns the user-defined handler ( it's
type is bound to the UserHandler
template parameter). You must pass in a pointer to
your user-defined handler's type so the compiler knows
what type UserHandler should be as in: MyHandler my_handler = io_handler.get((MyHandler *) NULL); |
AlwaysThrowsHandler, LoggingHandler, DBView, IndexedDBView
Copyright © 2002, Michael Gradman and Corwin Joy.
Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appears in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Corwin Joy and Michael Gradman make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.