Cleaning up Resources with Guice

Building on my last post about implementing a custom Scope in Guice I’d like to go a little further with that and extend it so it handles automatic releasing of resources as well. For this we first define an interface for everything the must be disposed at the end of usage, which is congruously called Disposable:

/**
 * An interface for objects that need to be disposed after usage. This
 * somehow adds a life cycle to objects which are created, in use and after
 * usage must be "disposed" (and should not be used beyond this point).
 *
 * @author Matthias Treydte <waldheinz at gmail.com>
 */
public interface Disposable {

    /**
     * Disposes this object. The general contract is that no instance methods
     * should be invoked on this object after disposal, unless stated otherwise
     * in the method's description.
     */
    public void dispose();
}

The idea is that every Object that has some cleaning up to be done after usage implements this interface and does the clean up in its dispose implementation. With this, we can just roll an AttributeHolder implementation which itself has an defined end-of-life (implements Disposable) and disposes all its contained attributes when this method is called. An straight-forward implementation might look like this:

/**
 * An abstract base class for implementing the {@link AttributeHolder}
 * interface which has a implementations of the attribute related methods and
 * forwards calls to its {@link #dispose()} method to all contained
 * {@link Disposable} instances.
 *
 * @author Matthias Treydte <waldheinz at gmail.com>
 */
public abstract class AbstractAttributeHolder
        implements AttributeHolder, Disposable {

    private final Object lock = new Object();
    private transient Map<Object, Object> attributes;

    public AbstractAttributeHolder() {
        this.attributes = new HashMap<Object, Object>();
    }

    public void replaceAttributes(Map<Object, Object> newAttr) {
        synchronized (getAttributeLock()){
            this.attributes = newAttr;
        }
    }

    @Override
    public Object getAttributeLock() {
        return this.lock;
    }

    @Override
    public final void putAttribute(Object key, Object value) {
        synchronized (getAttributeLock()) {
            attributes.put(key, value);
        }
    }

    @Override
    public final boolean hasAttribute(Object key) {
        synchronized (getAttributeLock()) {
            return attributes.containsKey(key);
        }
    }

    @Override
    public final Object getAttribute(Object key) {
        synchronized (getAttributeLock()) {
            return attributes.get(key);
        }
    }

    @Override
    public final Set<Object> getAttributes() {
        synchronized (getAttributeLock()) {
            return Collections.unmodifiableSet(
                    new HashSet<Object>(this.attributes.values()));
        }
    }

    @Override
    public void dispose() {
        synchronized (this.getAttributeLock()) {
            for (Object o : this.attributes.values()) {
                if (o instanceof Disposable) {
                    final Disposable d = (Disposable) o;
                    d.dispose();
                }
            }

            this.attributes.clear();
        }
    }
}

The interesting stuff happens in the dispose method where the contained map is scanned for instances of Disposable whose dispose method is then called in turn. This way concrete subclasses of AbstractAttributeHolder can be nested and when the outer scope is dispose, so are all nested scope and all the contained Disposable attributes.

Synchronization

The solution proposed in here is suitable for use in an multi-threaded environment, and like to elaborate on why I think it is so. The AttributeHolderScope basically binds some AttributeHolder to the current thread by the means of a ThreadLocal variable. But there is nothing that prevents any given AttributeHolder instance from being used by multiple threads concurrently. This is where the attributeLock() enters the stage. It is used to establish synchronization for modifying the HashMap which is the working horse of the AbstractAttributeHolder. Similarly, it also ensures the happens-before relation when reading from the map in the AttributeHolderScope.scope(..) method in case the map was modified by some other thread while the current thread is in the scope. Honestly, there is still some investigation needed here because I’m not entirely sure that this synchronization is sufficient when Guice has to build objects with a dependency tree with a depth > 1. So far it behaves nicely, though…


About this entry