Thursday, April 05, 2007

Guice support in DWR

Guice is the hot new dependency injection framework from Bob Lee and others at Google. DWR is a system for remoting Java server-side objects as JavaScript client-side objects in a way that is natural on both the client and server sides.

I'd been using DWR with Spring to wire together all the components of the Seat Yourself on-line ticket sales web application for almost a year and I was pretty happy with the combination. Then a few weeks ago, just as I was considering how to make the webapp more easily configurable, to support rapid administration and self-configuration of many customers, Josh Bloch suggested I take a look at Guice, and I suddenly realized just how fragile and unmaintainable was all that XML I had written for DWR and Spring.

Of course I could use Guice without integrating it with DWR, but one of the things that had always bothered me about DWR (and many other tools, not just DWR) was that everything -- remoted objects, data transfer objects, extension classes -- has to be concrete and public, with a public parameterless constructor, and everything works through setter injection, which makes things difficult. I want to work in terms of interfaces, with implementation classes that have final fields for injected state.

Guice looked like a way to have it all: easy remoting with type-safe (pure Java) configuration. I wrote a Guice integration package for DWR, and Joe Walker signed me on as a DWR contributor so I can help maintain it as part of the DWR distribution. The package Javadoc describes how to use it along with a simple example.

I'm still in the early stages of applying it to the Seat Yourself web sales application, but already the power of Guice has made things simpler. Each customer (where a customer is ticket-selling entity, like a theater) is associated with a domain where all their data -- seat charts, performance information, pricing information, patrons and their reservations, and holds on seats -- is maintained. When a user visits the web store to buy tickets, the link contains a domain name, e.g., "t3" for Theatre Three. Before Guice support, I had devised a complicated system using reflection and proxying to route the user request to the appropriate service object. It was so involved that I had trouble explaining it to my partners, both smart people. Not being able to explain something is a bad code smell.

With Guice-injected remoted objects, I can define a new scope, domain scope, where the details of providing the appropriate domain-specific service object are neatly encapsulated and managed by Guice. All I have to do is write something like this in my binding code:

bindRemotedAs("Tix", WebstoreService.class) // interface
.to(WebstoreServiceImpl.class) // impl
.in(DomainScopes.DOMAIN); // scope

where the interface looks like this:

public interface WebstoreService {
PerformanceAvailability getPerformanceAvailability();

Only the methods of WebstoreService are exposed to the world, even though the implementation class might have other public methods. With the Guice support, I don't need to specify which methods to expose. As usual with DWR, on the JavaScript side I can write things like:

callback : function(availability) {
exceptionHandler : ...

Because Guice has Spring integration, I can migrate my existing Spring-based code smoothly. Because it has JNDI integration, I can rewrite the code that manages the domain-specific configuration to use whatever LDAP back-end I like, instead of having to maintain an assortment of XML files and registry settings. We've already had problems with syntax errors in the XML configuration files, so this will save us a lot of heartache.

Guice also has support for AOP Alliance method interceptors, which means that on most of the occasions when I would feel most tempted to use AspectJ, I can stick to pure Java. Not that I have anything against AspectJ, but it's a different language and one more thing to worry about. I want to save it for the occasions when I really need it (as was the case for another submodule of our project).


Aniesh said...

Its a good&great work you have made to DWR.Thumbs up.
I have been looking for a long time about how to convert an existing spring based web application to a guice configuation.I have doubts in the following areas can u pls clear me.

1. In spring during the start of the server the xml file is loaded which causes the dependency injection.How to bring this in Guice i,e loading the beans as spring in the startup of the web app(Correct me if i am wrong).

2. I have spring based transaction management.To migrate to guice can i use the same(declarative transation) or programatic transaction?

Tembrel said...

1. Have you looked at SpringModule in package org.directwebremoting.guice.spring? I install an instance of SpringModule in my DwrGuiceServletContextListener and use SpringIntegration.fromSpring (from package to provide those beans within Guice.

2. I haven't tried this. I suspect you'll need to keep Spring around unless you're willing to write your own transaction management with AOP Alliance interceptors. There may be some discussion of this in the Guice forum.


dhanji said...

Kind of a late comment, but hopefully someone finds this useful.

WebExtensions for Guice (Hibernate/JPA integration) supports declarative txn management built on guice's aopalliance interception.

It is annotation-based and analogous to spring txn support (with either JTA or local txns) with little config needed:

disclosure: I am its author.