[ Team LiB ] Previous Section Next Section

Context

A database driver is a middleware entity that mediates interactions between an application and its physical data. Database drivers that implement a standard interface like ODBC or JDBC make it possible for an application to avoid hardwiring references to a specific database platform. Applications invoke generic operations defined by the interface, and database drivers implement that interface in conjunction with a specific database product. Standard driver interfaces enable simple applications to support a wide range of database products that can be effectively plugged in at runtime. Figure 5.1 illustrates how this relationship decouples a Java application from its supporting JDBC drivers:

Figure 5.1. Applications interact with JDBC drivers via JDBC interfaces. This enables you to plug in any new JDBC driver at runtime without updating or recompiling application code.

graphics/05fig01.gif

Suppose that you want to extend the behavior of an existing database driver. For example, most driver implementations provide a logging facility, but the messages they issue are geared toward debugging internal driver problems and are usually not helpful to application developers. Rather than poring over the underlying byte data flowing between the client and server, application developers are usually interested in things like the SQL statements being executed and their corresponding parameter values. You can enable your own logging dynamically by attaching customized behavior to existing database drivers. This is a convenient way to debug your application's SQL statements, even within a customer's environment.

The database drivers that your application uses are normally commercial products that are tuned for communication with particular database platforms. With a few exceptions, you do not have source code for database drivers, so adding your own logging implementation directly to them is rarely a feasible solution.

A database driver is usually made up of several related classes. You can extend its behavior by creating subclasses for each class. The problem with this idea is that to build a comprehensive solution, you need to provide a similar set of subclasses for every database driver you support.

The Resource Decorator pattern is an elegant solution that avoids creating subclasses for each supported database driver. It is an instance of the Decorator pattern [Gamma 1995] and applies directly to database resources. Resource Decorator allows you to attach additional behavior to any existing driver implementation with a single set of classes and minimal disruption to application code.

Consider the problem of identifying resource leaks. In JDBC terms, common resources are represented by the Connection, Statement, and ResultSet interfaces. If an application neglects to close any of these resources when it is finished using them, they continue to consume both client and server storage. ResultSets left open sometimes leave database locks in place, which prevents other applications from accessing the same data. To make matters worse, JDBC drivers tend to maintain internal references to these resources, preventing the Java Virtual Machine (JVM) from garbage collecting them effectively.

You can use Resource Decorator to implement a solution that tracks certain operations and ensures that applications close all resources in a timely manner. You can define a "leak detection" decorator that attaches to any JDBC driver and continuously reports facts about how applications are utilizing resources. A key concept of this solution is that neither the JDBC driver nor the main application code need to change to make use of the leak detection decorator. This works because the decorator implements the same JDBC interfaces as the driver. The application invokes the decorator's operations as if it was any other JDBC driver and the decorator dispatches those operations to the physical JDBC driver in turn. Figure 5.2 shows how resource decorators fit between a Java application and its supported JDBC drivers:

Figure 5.2. An application interacts with a Resource Decorator like any another JDBC driver. You can plug it in at runtime without updating or recompiling application or JDBC driver code.

graphics/05fig02.gif

Resource decorators are useful primarily as debugging and logging aids, but they can also provide other functions such as tweaking SQL statements, enforcing application-level security, preventing write operations, caching result set data, and adding result set scrolling support when it is not available from a driver.

    [ Team LiB ] Previous Section Next Section