You are on page 1of 4

How to log all errors to the

database

Sometimes users have the requirement that all application errors


are logged to a table. In traditional Oracle development tools like
Oracle Forms this was easy, simply override the ON-ERROR trigger
and write PL/SQL code to call your favourite database logging code,
or simply issue the insert statement to the associated logging table
yourself.

In JDeveloper's ADF framework it is just as easy and is achieved in


the following steps. Please note this post is written against JDev
11gTP4 so your mileage may vary in whatever version you're using:

In the JDev ADF 11g Guide section 27.8 "Customizing Error


Handler", it describes you can override the ADF binding layer
DCErrorHandlerImpl by creating your own custom handler. Simple
create a class that is a subtype of DCErrorHandlerImpl, and override
the chokepoint method reportException to capture all exceptions
raised by the ADF stack. It may look something like this:

public class ErrorHandlerImpl extends DCErrorHandlerImpl {

public ErrorHandlerImpl() { super(true); }

@Override
public void reportException(DCBindingContainer
dCBindingContainer, Exception exception) {
super.reportException(dCBindingContainer, exception);
}
}
Then in the associated DataBindings.cpx file set the
ErrorHandlerClass property to specify your new class and package
name: eg. view.controller.frameworkExtension.ErrorHandlerImpl.

If you receive an error in this step, the following post may resolve
your issues.

Unlike Oracle Forms where the programmer needs to override the


ON-ERROR trigger in every form, essentially here we're doing it for
the entire ADF application, saving us a fair amount of work.

Next we create a custom client interface method in our application


module that (for example – we can do anything we want here) calls
a database error logging package/procedure called
error_pkg.log_error via JDBC:
public void logError(String message) {
CallableStatement statement = null;
try {
String plsql = "BEGIN error_pkg.log_error(?); END;";
DBTransaction transaction = getDBTransaction();
statement = transaction.createCallableStatement(plsql, 1);
statement.setString(1, message);
int rows = statement.executeUpdate();
} catch (SQLException e) {
throw new JboException(e);
} finally {
try {
} catch (SQLException e) {
/* ignore */
}
}
}

In Oracle Forms the above code would simple be a PL/SQL call


within an ON-ERROR PL/SQL trigger. In JDev obviously we work with
Java code, and JDBC is used to make the associated database
PL/SQL calls.
Once we create the client interface method and expose it in the
ApplicationModule, we then need to create a binding to allow the
method to be called via our custom error handler reportException()
method from previous. We could create a binding in each page's
pageDef bindings file to call the custom logging method, but this
would be painful in a large application with many pages and the
developer could easily forget to add the binding. Instead in 11g we
can create an ADF Faces RC page template with an associated page
definitions file, ensure to create (all!) our pages based on the page
template (which any good application will do of course! ;), and
create the methodBinding to call our AM log method from above:

<bindings>
<methodaction id="logError"
instancename="AppModuleDataControl.dataProvider"
datacontrol="AppModuleDataControl.dataProvider"
requiresupdatemodel="true" action="invokeAction"
methodname="logExceptionToDatabase"
isviewobjectmethod="false">
<nameddata ndname="message" ndtype="java.lang.String"/>
... and so on ...
</methodaction>
</bindings>

Of course we don't need to type the above in by hand, it can be


easily created via the structure window Add bindings facilities in the
JDev IDE.

Finally we return to our custom error handler class


ErrorHandlerImpl, and change the reportException() method to use
the binding to indirectly call the AM client interface method as
follows:

public void reportException(DCBindingContainer


dCBindingContainer, Exception exception) {
BindingContext bindingContext =
dCBindingContainer.getBindingContext();
DCBindingContainer templateBindingContainer =
bindingContext.findBindingContainer("view_templatePageDef");

String error =
getDisplayMessage(dCBindingContainer.getBindingContext(),
exception);

OperationBinding operationBinding =
templateBindingContainer.getOperationBinding("logError");
Map params = ob.getParamsMap();
params.put("message", error);
ob.execute();

super.reportException(dCBindingContainer, exception);
}

The caveat to this approach is if the developer chooses to bypass


the ADF frameworks error handling mechanisms by raising their
own exceptions that don't raise a JboException, or error handling is
written into JavaScript, this will bypass the ADF custom error
handler.

If you're interested in other posts above JDeveloper, check out


the JDev pages on wiki.oracle.com.

You might also like