Humanizing OSGI III: Automated, all-pass Filters

2008-05-25

Just to capture your buzz interest, this is DSL-related! Read on …

OSGi filters are under-modelled, because they’re strings. Strings are great per se, they’re portable and very expressive – after all, source code is strings. So, strings – great, love’em. Write’em every day myself, for money, donchaknow.

But OSGi filters represent a shift of responsibility. With specifications, there’s always a specifier, a vendor, and a user. Specifications can come with reference implementations and library support, to help vendors and users. (OSGi is pretty well off in this regard, compared to e.g. Corba in its day.) But the responsibility for filter representation has been passed through the chain and squarely onto the user. The specifier and the vendor have told the user: Just give us back a string, and we’ll look at it and possibly give you an InvalidFilterException back. And yes, it’s checked, because you should be prepared being a gal (or guy) who can’t append strings together correctly.

Fortunately for the users, they’re programmers. They will say: OK then, I’ll have a computer make sure this string is right every time, OK? Just watch me catch that checked exception of yours, and rethrow it as a ThisNeverHappensError.

(I may have forgotten the precise name of the actual exception, InvalidFilterException. That’s because I rarely ever think about it anymore.)

So we should make filter classes, build instances with code, and hang them in trees. Make them print themselves to a well-formed string. Yes, this is the good old shape-draw-yourself thing that we old-hand object modellers thought was a silly example of polymorphism.

I have a small OSGi library brewing, name of vanadis. I will be referring to that from now on. The Filter interface there looks like this, in a condensed version – look up the code for the whole shebang:

interface Filter {
    Filter and(Filter... exprs);
    Filter or(Filter... exprs);
    Filter not();
    String toFilterString();
}

Then there is the Filters factory class, a classic static factory with static methods all over it. But if it had an interface, it would be:

public interface Filters {
    Filter eq(String attribute, Object... values);
    Filter approx(String attribute, Object... values);
    Filter gt(String attribute, Object... values);
    Filter lt(String attribute, Object... values);
    Filter present(String attribute);
    Filter substring(String attribute, String substring);
    Filter objectClasses(Class... objectClasses);
}

So, to create a simple filter that works well for a WerewolfKiller service:

    Filters.objectClasses(SilverBullet.class).and(Filters.isTrue("fullMoon"));

Of course, the Filter interface can host methods that move us closer to DSL land, allowing us to express things with less typing:

   objectClasses(SilverBullet.class).and("fullMoon");

The HelplessFarmer service might want to query for an experienced, yet reasonably stable WerewolfKiller service:

   objectClasses(WerewolfKillerService.class).andGt("killCount", 5).unless("psychotic");

And so on. You might have noticed I pass class objects to the factory methods, not class names. Again, this is an attempt to keep myself DRY – calling getName() on class objects should also be done only once. In this case, the Filter object does it at construction time, so the class object never “hangs” on the tree. However, if making a large, distributed application, you might need some filter creation happening in an infrastructural capacity, which is likely to be in a context where the classes aren’t visible. In that case, using strings to create filters might be the only way to go. But my experience tells me that you will, more often than not, be constructing filters in the context where the classes are known.

Building filter classes and putting them in trees is really quite simple. In my last project, I made a support class that allowed us to build strings correctly and incrementally: Each filter object would hold a legal filter string, and appending stuff like e.g. this.and(that) would simply create a new filter object, with “&(” at the head, then the strings from this and that, ended by “)” at the tail. This might be perfect for your purposes, and very simple.

In vanadis, I have the whole structure represented as a tree. Not only does this save on string garbage, the resulting structure is more pick-apart-able, one can do automated analysis etc. This can be golden if you find that filter matching is becoming a bottleneck.

These are all just ideas, and a work in progress that I hope to make use of in my current job. I’m happy to take comments and feedback if you have any, especially on making the base classes more generally usable.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: