Universal custom Scope for Guice

Guice is a dependency injection (DI) framework by Google I’ve been using for some time now and I’m starting to get a grasp on recently. Compared to Spring it is very lightweight and most importantly comes without that XML bloat, so I can recommend using it even for the smallest projects. I won’t talk about DI in general here, besides mentioning that in my experience it makes life a whole lot easier when it comes to code maintenance and refactoring and that I don’t want to go without it any more.

The Attribute Holder Scope

In Guice, a Scope acts as some kind of “memory” for created instances. Surprisingly, Guice (sans the Servlet extension) ships with only one implementation of the Scope interface, which is the Singleton scope. Given that, we are left with two choices for our bindings:

  • either we do not scope them at all (meaning the objects will be created again every time you require an instance)
  • or they are singletons (which live forever within an given Injector).

For some time I was trying to get along with these, discerning a custom Scope as something deeply magical that I’m not willing to deal with. This was largely due to the fact that I could not dig a non-trivial example for a Scope implementation. I’m trying to improve on that situation here. :-)

After some days (weeks?) of pain and sorrow, working around the lack of proper scopes with obscure “Manager” classes and lengthy Provider implementations, I finally found my happiness by decoupling the actual “memory” from the Scope implementation. The memory part is defined by the AttributeHolder interface which is pretty much an stripped-down Map<Object, Object>, as given below:

/**
 * Implementors of this interface can serve as the backing store for
 * Objects that are scoped within an (subclass of) {@link AttributeHolderScope}.
 *
 * @author Matthias Treydte <waldheinz at gmail.com>
 */
public interface AttributeHolder {

    /**
     * Extracts the {@code Object} memorized for the specified key from this
     * {@code AttributeHolder}.
     *
     * @param key the identifier for the attribute to extract
     * @return the {@code Object} stored for the specified key, or {@code null}
     *      if either the {@code null} value was stored for this key or there
     *      is no attribute stored for the key
     * @see #hasAttribute(java.lang.Object) to discriminate the two reasons
     *      this method may return {@code null}
     */
    public Object getAttribute(Object key);

    /**
     * Decides if this {@code AttributeHolder} has an association for the
     * specified key.
     *
     * @param key the key to check if it's known to this {@code AttributeHolder}
     * @return if this key is known
     */
    public boolean hasAttribute(Object key);

    /**
     * Stores a new value in this {@code AttributeHolder}.
     *
     * @param key the key to identify the new attribute
     * @param value the new attribute
     */
    public void putAttribute(Object key, Object value);

    /**
     * Returns all values currently stored in this {@code AttributeHolder}. The
     * returned set can not be modified.
     *
     * @return all attributes of this holder
     */
    public Set<Object> getAttributes();

    /**
     * Returns an object on which to lock when access to multiple methods of
     * the {@code AttributeHolder} are to be made atomic.
     *
     * @return the {@code Object} to synchronize on
     */
    public Object getAttributeLock();

}

All this interface does is to allow to associate objects with objects (plus some synchronization semantics). I suppose it is as general as it can get… The general rule is that (some of) your business objects (or entities; the stuff you read from a database or create because of user interaction) implement this interface. If you do, they can be used by Guice as a container to hold the scoped objects of the application logic. The only missing piece is the actual Scope implementation that allows Guice to make use of the attributes, which is the AttributeHolderScope:

/**
 * A {@code Scope} that uses an {@link AttributeHolder} as the backing store
 * for it's scoped objects.
 *
 * @author Matthias Treydte <waldheinz at gmail.com>
 */
public class AttributeHolderScope<AHT extends AttributeHolder>
        implements Scope, Provider<AHT> {

    private final ThreadLocal<AHT> holder;

    /**
     * Creates a new instance of {@code AttributeHolderScope}.
     */
    public AttributeHolderScope() {
        this.holder = new ThreadLocal<AHT>();
    }

    /**
     * Lets the current {@code Thread} enter this {@code Scope}.
     *
     * @param holder the {@link AttributeHolder} instance for the {@code Scope}
     * @throws IllegalStateException if the current {@code Thread} is already
     *      in this {@code Scope}
     */
    public void enter(AHT holder) throws IllegalStateException {
        if (holder == null)
            throw new NullPointerException();

        if (this.holder.get() != null)
            throw new IllegalStateException(
                    "already in " + getClass().getSimpleName() + " scope");

        this.holder.set(holder);
    }

    /**
     * Lets the current {@code Thread} leave this {@code Scope}.
     *
     * @throws OutOfScopeException if the current thread is not in
     *      this {@code Scope}
     */
    public void exit() throws OutOfScopeException {
        assertInScope();
        this.holder.remove();
    }

    /**
     * {@inheritDoc}
     *
     * @return {@docRoot}
     * @throws OutOfScopeException if the current thread is not in
     *      this {@code Scope}
     */
    @Override
    public AHT get() throws OutOfScopeException {
        assertInScope();
        return this.holder.get();
    }

    @Override
    public final <T> Provider<T> scope(
            final Key<T> key, final Provider<T> outer) {

        return new Provider<T>() {

            @Override
            public T get() {
                assertInScope();

                final AttributeHolder ah = holder.get();

                synchronized (ah.getAttributeLock()) {
                    T current = (T) ah.getAttribute(key);

                    if ((current == null) && !ah.hasAttribute(key)) {
                        current = outer.get();
                        ah.putAttribute(key, current);
                    }

                    return current;
                }
            }

            @Override
            public String toString() {
                return "Provider [scope=" + //NOI18N
                        AttributeHolderScope.this.getClass().getSimpleName() +
                        ", outer=" + outer.toString() + "]"; //NOI18N
            }

        };
    }

    private void assertInScope() throws OutOfScopeException {
        if (holder.get() == null) {
            throw new OutOfScopeException(
                    "not in " + getClass().getSimpleName()); //NOI18N
        }
    }
}

In addition to the obvious Scope interface, the AttributeHolderScope also acts as an Provider for the AttributeHolder class it is working on. This way the holder can act as some kind of “root” for the Objects we are about to put into it’s Scope.

How to use it

Let’s assume we’re writing a feed reader application (a very 2006 example, by the way). We would need some means to store the feeds that the user has subscribed to. Therefore the Feed is our first entity, along with it’s accompanying FeedScoped annotation and finally the FeedScope itself:

public final class Feed implements AttributeHolder {
    private final URL feedUrl;
    private final Map<Object, Object> attributes;

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

    public URL getFeedUrl() {
        return this.feedUrl;
    }

    public Object getAttributeLock() {
        return this.attributes;
    }

    /* the rest of the AttributeHolder implementation delegates
     * to this.attributes and is omitted
     */
}

@Target({ TYPE, METHOD }) @Retention(RUNTIME) @ScopeAnnotation
public @interface FeedScoped {
    /* nothing */
}

public final class FeedScope extends AttributeHolderScope<Feed> {
    /* nothing */
}

Because we don’t want to fetch the feeds from the net over and over again as the user wants to read a post, we have a cache for the posts we have already retrieved for a feed (the details of the Post class are omitted for brevity):

public interface PostCache {
    public List<Post> getPosts();
    public void putPost(Post newPost);
}

public class TransientPostCache implements PostCache {
    private final List<Post> posts;
    /* implement the PostCache methods using this.posts */
}

The beauty of programming against the PostCache interface is that you stay focused and it’s easy to swap in a more advanced implementation later (which stores the fetched articles in some form of persistent storage and does other fancy stuff).

Now we can start to profit from our work and implement the first code that actually gets something from our scope injected:

public class FeedFetcher {
    @Inject
    public FeedFetcher(URL feedUrl, PostCache cache) {
        /* remember the parameters, ... */
    }

    public void doFetch() throws IOException {
        /* fetch the feed and add the posts to the cache */
    }
}

And deep down in the plumbing layer we have a timer that occasionally kicks in and fetches the posts for the feed we have subscribed to:

Injector inj = ...;
FeedScope fs = ...;

for (Feed feed : feedList) {
    fs.enter(feed);
    try {
        final FeedFetcher ff = inj.getInstance(FeedFetcher.class);
        ff.doFetch();
    } catch (IOException ex) {
        /* log the error, try again, whatever... */
    } finally {
        fs.exit();
    }
}

This assumes we have the list of feeds and the Injector at hand. Then it iterates over the feeds we know of, entering the FeedScope for each of them. Inside the scope we ask the Injector for an FeedFetcher instance which will get the correct URL and PostCache injected and is ready to do it’s best to fetch the new posts from the feed. It is important to make sure that every time we enter the FeedScope we have a matching exit(), so we put that into a finally block. All there is left to do is to wire everything up in a Module:

public final class FeedModule extends AbstractModule {
    protected void configure() {
        /* initialize the Feed scope */
        final FeedScope fScope = new FeedScope();
        bindScope(FeedScoped.class, fScope);
        bind(Feed.class).toProvider(fScope);
        bind(FeedScope.class).toInstance(fScope);

        bind(PostCache.class).
            to(TransientPostCache.class).
            in(FeedScoped.class);

        bind(FeedFetcher.class);
    }

    @Provides
    @FeedScoped
    URL provideUrl(Feed feed) {
        return feed.getFeedUrl();
    }
}

So this would be the outline of a feed reader application that makes use of a custom scope, which is the AttributeHolderScope in this case.

Was it worth all the trouble?

For what we have seen in this example, surely not. But in a real-world application, this is just the beginning (its always just the beginning…). And there’s interesting stuff to come! After having these classes up and running you would strive for a more advanced PostCache implementation very soon. Possibly a FilePostCache which stores the posts in files in some directory. But which directory on the file system is the right one? Or a DatabasePostCache which uses some JPA implementation to store the posts. But that would need access to some persistence manager or Database connection. And which is the right Database?

It’s surely preferable to get these dependencies magically injected by Guice than to wire everything up by hand, and this is where I see strength of the Guice.


About this entry