Last updated
on 02-01-2012
at 12:00 PM

Blog

Me, my housemates, and the house itself (housered.org — although we don’t actually have much of a site to date) are pretty tech-tastic. In addition to the 8 computers in the house, we recently bought a neat little linux server that’s now running the TV with XBMC and a cheeky couple of terabytes of RAID’d storage full of content (and doing all the routing on our over-complicated network; does a house need 3 VLANs?). We’re slowly adding more ways to fill the server with content, from polling RSS feeds for things we watch a lot, to a new little script Ed whipped up that listens for specific (n.b, firmly authenticated) emails, so you can quickly get the house to go find and start downloading something you think of from work, and then have it entirely ready by the time you get back.

Obviously the next step on this was to rewrite the quick and dirty solution for email listening into a full-fledged and quite-unnecessarily over-architected framework that we’re calling Dispatch, so we can add new transports (HTTP, VOIP, gesture recognition, etc), so we can tie in new clients (android app, texts), and so we can add new handlers for other types of request (Coffee on-demand? Remote access to house voicemails? Ability to check if we have X on the server already? A quick way to find out who’s at home at the mo?). Clearly, this required a vast and complex system that entirely decoupled everything from everything else in every way, so you can phone or text or JSON into any of the above, and vice versa. Clearly.

Solution: define message formats for interactions between these, and offer converters for them, hiding as many complications as possible to both ends, but allowing subclasses to offer unique message types/converters if they wanted to, for example, do special things in the handler depending on email headers, if available, or pull the phone details and phone the user back (we have free calls on the landline: you could text the house and have it phone you and play your voice over an internal intercom…). I’ll skip the full design, but to give you an idea, the basic flow for receiving an email message should be something like:

EmailTransport.emailReceived() Dispatch.process(RelevantHandlerName, EmailMessage, EmailResponseClass) Handler.getConverterFor(EmailMessage.getClass()) Dispatch.getDefaultConverterFor(EmailMessage.getClass(), DictMessage.class) ReturnedConverter.convert(EmailMessage) Handler.process(ConvertedMessage) Handler.getConverterFor(ReturnedHandlerResponseMessage.getClass(), EmailResponseClass) ReturnedConverter2.convert(ReturnedHandlerResponseMessage, EmailResponseClass) EmailServer.send(ConvertedHandlerResponse)

Nice. Well, ish. Josh hates this with a passion, but he’s wrong see. We’re still iterating over this to clean it up, but anything that makes it simpler and easier to add new handlers & transports so we actually continue with this in the distant future when we’ve grown to very bored of it seems well worth it in my book!

This whole structure has made for some interesting little challenges over the last few days, but is very nearly in built and ready to go now. There is one minor conceit compared to the above flow atm: you have to give the handler to the transport so that it can call the getConverter function from there, double-dispatch style. Java won’t dynamically dispatch the call without this, which still infuriates me, but I’m hopeful that I’ll have a cleaner structure for that together by the end of the week.

Regardless, in use this is clean and completely typesafe to extend, despite the arbitrary selection of messages at each step, and lovely: there’s one unchecked cast through-out, and no switching or instanceof-ing at all, either in normal use or when overloading getConverter to add custom converters for handlers. Adding a new transport requires just a transport class, a converter class to turn the transport’s messages into something the relevant handlers can use (DictMessage is our standard, it’s just a simple JSON-style structure), and a Dispatch.register(converter) call, then all the handlers ‘just work’ with the new input source. New handlers are even easier: put them in, register them with a name, and set them up to take a standard format. Magical.

Next post: the reason I can’t get rid of that damn unchecked cast floating around in the middle of all this, and my eventual solution to the double-dispatch mess. Grrr.