Tie

Java Method Interception

Introduction

Tie is a lightweight library for dynamic method interception. It makes use of the AOP Alliance interfaces to define interceptors, and provides a small set of utility classes for applying these interceptors to objects and methods.

Method Interception

Imagine we have the following Java interface:

public interface ConfigurationService
{
    public  String getConfigurationValue(String key);
}
We have different implementations of that service. The PropertiesConfigurationService reads the values from a properties file. The DatabaseConfigurationService uses JDBC to read the values from a database table.

Code that is written against the interface (ConfigurationService) does not know whether it is using the PropertiesConfigurationService or the DatabaseConfigurationService. There is a problem though - the implementation of the DatabaseConfigurationService needs to be given a JDBC database connection before it can access the database. Some piece of code needs to be responsible for setting that up.

We could pass the connection to the DatabaseConfigurationService when we construct it, but that means we have a single connection permanently tied up in this service. And it also makes it difficult to have this connection participate in a global transaction. We could make each class that uses the DatabaseConfigurationService configure it correctly before they use it, but that locks them into a specific implementation of ConfigurationService. Another solution would be to modify the DatabaseConfigurationService to pull in its database connection from somewhere, but that ties it whatever mechanism we use to load up those database connections. Such a tie in has a number of unfortunately consequences, not the least of which is that it makes it harder to unit test DatabaseConfigurationService in isolation.[1]

So what are our choices? One thing we could do create a wrapper around the DatabaseConfigurationService. Something like:

public class ConnectionManagedConfigurationService inplements ConfigurationService
{
    private DatabaseConfigurationService _delegate;

    public ConnectionManagedConfigurationService(DatabaseConfigurationService delegate)
    {
        _delegate = delegate;
    }

    public String getConfigurationValue(String key)
    {
        // WARNING: This class doesn't clean up the connection.
        java.sql.Connection connection = getConnection();
        _delegate.setConnection(connection);
        return _delegate.getConfigurationValue(key);
    }

    private java.sql.Connection getConnection() { /* ... */ }
}

This approach is often called the "decorator pattern", and it is a very useful pattern, but in this situation has some limitations.

  • The ConnectionManagedConfigurationService is now tied to the implementation of DatabaseConfigurationService. There are ways around that, but most of the solutions end up being overly complex if we want to apply them widely.
  • If we have another class (implementing a different interface) that needs to have a connection injected in the same way, then we need to write another proxy class. Our proxy class is tied to the specific interface that DatabaseConfigurationService implements.

Method interception is a solution to these (and other) problems. Using a method interception library we can write code that runs before, after, or around the invocation of a method, without being tied into the specific interface or implementation. The sample code shows how the DatabaseConfigurationService example looks using tie.

When we use method interception in a way that mimics the decorator pattern, we refer to it as the dynamic decorator pattern, or dynamic decoration.

The tie approach

There are a number of different tools available to do method interception. Many of them are part of larger "Aspect Oriented Programming" (AOP) toolkits. A lot of them are very good, and most of them are free and open source. You may already be using an AOP framework that supports method interception. Tie aims to differentiate itself by doing one thing (method interception) and doing it well. Tie does not offer any other AOP features. You won't find any references to mixins, or pointcuts. Tie doesn't even have a configuration format. Tie is a library for doing programmatic method interception. It aims to be incredibly easy to use, and be the quickest and simplest way to include method interception in your application.

Tie extensions

In keeping with the philosophy of doing one thing well, tie is broken into 2 packages. net.sf.tie contains the basic interception library. It does as little as it needs to in order to provide a robust, yet easy to use, toolkit for method interception.

net.sf.tie.ext contains extensions to tie to simplify some common use cases. It supports conditional interception - intercepting some methods on an interface, but not all and allows for rules to be declared that state which sets of interceptions should be applied to which interfaces or implementations.

Learning more

The quick start guide will show you how to get going with tie.

[1] If we were to take this approach then our best solution would be to create an interface ConnectionProvider and inject that into the DatabaseConfigurationService. That allows us to separate the service from the connection retrieval method. In a real scenario that might be an appropriate direction to take. Or course, you'd still have to work out how and where to inject the ConnectionProvider, but it would probably be safe to do that at construction. But let's not stretch this too far - it is, after all, only an example.