ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Learning Servlet Filters

by Satya Komatineni
08/29/2001

The implementation of filters is a new mechanism being introduced into the Servlets 2.3 standard. This article explores the implications of filters to the Servlet architecture.

It has been a pet peeve of mine that one should not buy into an entire EJB solution just to gain the transparent (container-managed) transactional support for Java objects dealing with relational databases. One could inquire, what is the cost of implementing such a solution in the servlet tier itself? Because transactional support is valuable, whether the solution is distributed or not.

Typically, this transparent transactional support is accomplished by enrolling the active thread with a connection pool manager that the application relies upon for connections. The filtering mechanism is positioned to intercept the calls to an eventual servlet by registering the current thread with a connection pool manager in order to accomplish this. As one can see, the filtering mechanism is ideally suited for interposition, similar in concept to the EJB interposition of remote object calls from the EJB object to the bean instance.

Using the same interposition trick, one could also enroll a logging mechanism with the current thread as well and thereby provide applications with server-side logging that delineates at the thread level, as opposed to interlacing the log messages.

For those types of filters that do not interfere with the request or response, interposition could be adapted even in the current releases of servlets, and can provide an invaluable service to the developers that are currently bogged down by managing their own transactions programmatically. When this is combined with higher level data-access mechanisms (paralleling ADO from Microsoft or TDP(Transparent Data Pipeline) architecture that I have proposed in some previous articles), programmers can be completely oblivious to database connections altogether. This is the stage where developers can write business logic with the same ease that the database developers enjoy today with stored procedures; native and quick. I intend to demonstrate here the ease and simplicity of this process with some concrete code examples.

Developers' View of the Facilities

Related Reading

Java Servlet Programming, 2nd EditionJava Servlet Programming, 2nd Edition
By Jason Hunter with William Crawford
Table of Contents
Index
Sample Chapter
Full Description

The best way to gauge the usefulness of a facility (or framework) is by looking at some sample code that actually uses that facility. As suggested, filters and transactional support are implemented by the framework, and the developer code has no reference to those objects. The servlet programming model is a request/response model, so a developer typically interprets and executes a request by dividing his work into a series of tasks. These tasks could include database queries and updates, and perhaps multiple updates requiring transactional integrity.

The ITask interface is introduced here to represent the concept of a task. Given a task name and arguments, it will perform an abstract task and return an object and throw an exception to indicate exceptional failures. Many tasks can be derived from this task, and this gives us a mechanism to treat and manage all tasks as ITasks. Please keep in mind that these concepts are introduced here just to explain transactional support. In your own program, you are free to have your own class hierarchies and methodology and to never ever refer to ITask.

Interface ITask {
  Object executeTask( String taskName, Object Arguments ) throws TaskExecutionException;
}

Let us write a task that allows us to add an employee to a company:

class AddEmployeeTask implements ITask
{
  Object executeTask(String taskName, Object args) throws
TaskExecutionException
  {
    try
    {
      // Get a connection pool manager
      IConnectionPoolManager icpm = Factory.getInstance().getObject(IConnectionPoolManager.NAME);

      // From the connection pool manager
      // obtain a connection
      SQLConnection con = icpm.getConnection("data_source_1");

      .. use the connection to store the data in the
database
      .. return any required object
    }
    finally
    {
      // return the connection back to the pool
      icpm.putConnection(con);
    }
  }
}

Now let us write another task that would allow us to update an employee:

class UpdateEmployeeTask implements ITask
{
  Object executeTask(String taskName, Object args) throws
TaskExecutionException
  {
    try
    {
      IConnectionPoolManager icpm = Factory.getInstance().getObject(IConnectionPoolManager.NAME);
      SQLConnection con = icpm.getConnection("data_source_1");
      .. use the connection to store the data in the database
      .. return any required object
    }
    finally
    {
      icpm.putConnection(con);
    }
  }
}

Now assume, for some reason, we need to add a collection of employees:

class AddEmployeesTask implements ITask
{
  Object executeTask(String taskName, Object args) throws TaskExecutionException
  {
    // No need to get the connection manager here
    // We also assume the enumeration of employees is passed through the args
    Enumeration e = (Enumeration)args;

    AddEmployeeTask addEmployeeTask = new AddEmployeeTask();
    for(;e.hasMoreElements();)
    {
      addEmployeeTask.executeTask(AddEmployeeTask.NAME, e.nextElement());
    }

  }
}

If you have noticed, the individual AddEmployeeTask that independently acquires and returns the connection can now work well even, when it is used in a compositional context. This paradigm allows developers to organize their work as independent units and test them while allowing them for future compositions. So each task, whether composed or individual, will always get executed in a transactional context. That means the transactional filter we are talking about will automatically commit or roll back these tasks, depending on the exceptions that were raised. Although I prefer exceptions as the main channel for these automatic commit/rollbacks, one could imagine a different scheme (either via return codes or http response attributes) that could be implemented. Now it remains to be seen how the transactions are actually commited and rolled back.

Pages: 1, 2, 3

Next Pagearrow