Status

Proposal not ready for review

Target Release

4.0

Original Authors

Dave Johnson

Abstract

This is a proposal to use Guice to implement Dependency Injection (DI) in Roller.

Requirements

This proposal introduces DI in Roller in a pretty limited way. The idea is to get a DI framework into Roller so we can start rooting out our various factories and singletons, making the code easier to test, manage and providing more extension points.

As it stands today it's only benefits are that it 1) allows a customizer to easily switch out Roller manager classes and replace them with their own implementations and 2) make it possible for RollerFactory to instantiate other Roller-dependent classes created by folks who are customizing Roller.

These requirements are met by this proposal.

  • Introduce DI
    • Use DI to setup the Roller instance and managers, i.e. manager classes should no longer be hard-coded into the Roller implementation class, instead they should be injected.
    • Enforce singletons, i.e. singletons should have a private constructor.
    • Use constructor injection to ensure that immutable objects remain immutable.
  • Do not change Roller API
    • Do not change the was Roller back-end interfaces are accessed by front-end code
    • i.e. RollerFactory.getRoller() stays in place
  • Do not change way Roller is configured
    • Do not introduce any additional configuration files for those installing Roller, i.e. don't change the fact that the only customization file users should ever have to touch is roller-custom.properties.
    • Do not introduce any additional configuration files for developers, i.e. developers should not have to deal with any new XML or property files.
    • Maintain the same level of back-end pluggability, i.e. it should still be possible to switch back-end implemenations by setting a single property in the Roller configuration file.

Issues

These issues were raised and responded to during mailing list discussions of this proposal:

  • Issue raised: "I think it is most appropriate that any instance of the Roller interface should be treated
    as immutable. "
  • Response: We use constructor injection so that Roller implementations do not have to expose setters and can remain immutable.

  • Issue raised: "To truly enforce the singleton pattern we should only provide private constructors and the single instance of the class should be created statically and returned via a public static method."
  • Response: Guice can call private constructors, so we full enforce the singleton model.

  • Issue raised: "I hope we won't be asking users to modify distributed code in order, for example, to add plugins or to swap a rendering model implementation."
  • Response: We won't require that. If you want to extend Roller's back-end you simply provide your own module class that injects the classes you want. You'll have to override one property in your roller-custom.properties file, but you will not have to touch a line of Roller code.

  • Issue raised: "From my perspective Spring is more mature, well-documented and tested, has a more open contribution model, and is in wider use amongst a broader community. Plus we have at least two committers that are using it in other settings."
  • Responses
    • Guice documentation is excellent and Guice is "simple and easy. It took me no time at all to figure out – no books or extra docs necessary."
    • "Guice now powers Google Adwords. You'd be hard pressed to find a more massively distributed, scalable, etc. Java app out there. So, I'm not particularly worried about Guice maturity and testing."
    • "Spring does not accept external committers and has no plans to do so," that's hardly an open contribution model.

Design

List and describe new manager methods, Struts actions, JSP pages, macros, etc.

Changes to Roller Weblogger bootstrapping

To select a back-end implementation, you set the property 'guice.backend.module' in the Roller configuration file the the class name of a Guice module that specifies the Roller interfaces. The RollerFactory will instantiate that Guice module and will use it to create and inject the Roller implementation specified by that module.

Roller implementation and all manager implementations use constructor injection. The are all declared as singletons.

Changes to Roller Planet bootstrapping

Roller Planet uses the very same setup as Roller Weblogger. As you'd expect there is a PlanetFactory, which uses a PlanetModule to initialize Guice and create injected instances.

Planet implementation and all manager implementations use constructor injection. The are all declared as singletons.

Changes to Roller Weblogger's Planet integration

The PlanetFactory uses the Guice back-end specified in the planet.properties file. To use Planet in Roller we simply provide a different PlanetModule, one with a Planet implementation that reads database parameters from the Roller properties file instead of the Planet one.

This is accomplished by a special Planet persistence strategy that uses RollerConfig and is named HibernateRollerPlanetPersistenceStrategy. And we have a PlanetModule that specifies that strategy, which we call RollerPlanetModule.

Status

This proposal is implemented in the roller_guice branch and as of June 21, 2007 is completely in-sync with the code in the Roller trunk. It's ready to merge.

Guice DI is implemented in both Weblogger and Planet and for both the Hibernate and JPA implementations and passing 100% of tests. Both Weblogger and Planet apps start, run and pass sanity testing.

Comments

Please comment on the Roller dev list.

  • No labels