Monday, April 23, 2012

A "Guicier" Apache XML-RPC

Call me old-school if you like... I guess I am. When everyone was raving about Guice, I was simply taking note of it. "Oh sure... another thing to pass other things around." However, something stuck, because the good programmer in me was referring me back to Guice when the bad programmer was whispering "static state singleton" in my ear. It did not take me long to start appreciating what Guice can do. Unfortunately, I found the Internet to be "not-so-good" for Guice examples, mainly for three reasons:
  1. The examples were too trivial to extend to real applications.
  2. The more complicated examples were doing really horrid things. (Like a singleton class that keeps the injector available for lazy and even not-so-lazy instantiations. Sorry, but why is this better? That's like taking an orange-overall crook, dressing him in a suit and calling him an honest politician. Uhh... wait... that's not what I mean...) 
  3. Guice does not lend itself well to already badly written code, hence the difficulty to find examples that deals with those situations. 
What made things a bit tricky was the Guice-rules I made for myself, either because it felt right or made understanding better (I am good with algorithm design, but find keeping a large complex system in my head a daunting task.)
  1. You have one injector and one injector only. Inject once and throw it away. The only exception I make to this is a cool trick in anonymous inner classes (more on this, later). 
  2. Keep the modules few, and put them in the same package as the program entry point. It is after-all the place where the module is used. 
  3. Do not go too far. You can easily over-guice and this DOES make matters worse. 
  4. Do not force Guice down the throat the people that will make use of your code (i.e. if you are writing a library). There is enough of that in the computer world. 
The really first challenging problem that had be baffled was Apache's immensely beautiful enigeering marvel that is XML-RPC. One of the big problems with this library is the way in which the handlers get created. Apache uses its own internal reflection approach to create the class, which cuts Guice out of the picture. Fortunately (?), in their infinite wisdom, they created a RequestProcessorFactoryFactory interface which allows you do do the creation yourself. (It sounds almost like the proverbial "I know that you know, that I know that you know I know, did you know that?)

Regardless, in order to get this working another injector needs to be passed to the servlet, violating my first rule. However... I found a workaround. I'll let the code speak for itself. Here goes:

First the main class where everything gets wired up. Simple and self-explanatory:


Secondly, the servlet. This merely redirects traffic to the handler and sets the factory. Note the injection. Also note the absense of an injector:


Thirdly the handler with some test injection (demonstrating that we can inject anything we want). It merely echoes the request:


...and lastly, the module. The magic happens in the getRequestProcessorFactoryFactory provider. Have you ever had the need to write an anonymous local inner class within yet another anonymous local inner class? Well, now you do. I call it the Russion-doll pattern (anti-pattern?) Guice has access to the injector so you can merely inject it here as well:


So, the order of creation. The main class gets an instance of the SimpleServer, which needs an instance of a ServletContextHandler, which needs a RequestProcessorFactoryFactory which needs an injector to inject an instance of a new handler. Basically boils down to lazy instantiation which is set up in the module.

No comments:

Post a Comment