Hi all !

Anyone had time to have a quick look at this?
I'd love to get some feedback, see if I should carry on in that direction (I'd be more than happy to!)

Thanks a lot
Denis Balazuc


Denis Balazuc wrote:
Hello all

I've finally found some time to tidy up a Spring demo for Roller. I've tried to include various different aspects of what Spring can bring into a project such as Roller (depency injection, interceptors and transaction management mostly) and focused on easy back-end switch and simple configuration for the mail and the main datasource. There are many areas that I didnt address but where I can see some benefits from it.

#Journey onward with Spring!

Before going further, I would like to mention that, with ACEGI already at the source of the security model of the Roller webapp, it was easy to convince myself that introducing Spring in the business layer was just a natural continuation of the work that's already been done there and a good goal to pursue. Besides only addressing the back-end, there is a lot that can be done on the webapp side too. So...Spring's already there, temperature's getting good....let's go!

A few first things

* File(s) URL are at the end of this mail. For the impatients, it's better to read from the bottom to the top.

* When mentionning classnames or other code details, I will be referring to version 541334 of the trunk, which is before refactoring of the pojos and right in the middle of the creation of the /component directory. Classnames and details discussed hereunder may be slighty out of date. I also did not consider Planet as I reckoned that most of what is involved applies to Planet the exact same way, and RollerConfig (which should be trivial to Springify) to avoid getting in the midst of too-much-changes-at-once.

* version 541334 has a few problems with creating new entries or categories
If you ever happen to want to try to run my build, expect a few things to not work correctly, including things I've probably destroyed along the way. Having everything pristine is not the goal of this demo and code has moved since so it really did not really matter.

* I haven't tested all of everything, some bits hereunder are also theory only, but those are not rocket science to implement despite my hidden kid desire to be a rocket scientist.

#Mail and DataSource

First thing, I wanted to address the problem of switching the mail session and the datasource, from JNDI to plain good auld java code or others. Spring allows you to switch those implementations without code that will fetch a property, check which of JNDI or plain mail session (or jdbc datasource) to use, and so forth. Surely it requires injecting a bean or some lookup code. For that, I have modified MailUtil.java and re-implemented DataProvider.java to use a Spring bean. In the case of MailUtil.java, a Spring interface, JavaMailSender is being used internally in place of a javax.mail.Session instance. In the case of DataProvider.java, Spring actually makes it obsolete as it can provide a datasource bean from configuration so its implementation looks up for a datasource bean. An interesting note is that the roller(-custom).property switch (depending on the "database.configurationType" property) is implemented within the Spring configuration, removing the need for the various service providers or factories within the code. This also shows how it's possible to move a lot of configuration logic out of the code and into XML files that usually never change.

See
src/applicationContext-rollerMail.xml
src/applicationContext-rollerDatasource.xml

#"Back-end" implementation
I got caught in the middle of JPA changes while doing this work, so....switching back-end sounded like a good target for dependency injection. We have interfaces, we have implementation classes, ideal conditions for a lift-off! RollerImpl.java has been modified and merged from HibernateRollerImpl.java so it contains ALL the Roller manager implementations. Those are injected through src/org/apache/roller/business/applicationContext-business.xml using either common beans for the managers that do not have links to the database, either back-end implementation specific beans (Hibernate, JPA, all you can invent). Of course, the singleton nature of those implementations is preserved where required.

See src/org/apache/roller/business/applicationContext-business-hibernate.xml

This allows for

-- Switching back-end implementations such as Hibernate, JPA or unit test mocks/stubs easily.

-- Adding declarative transaction management and remove the need for the code to worry about that aspect which in Roller impersonates as the "HibernatePersistenceStrategy". In that particular matter, there would be a lot to discuss about the current implementation of the Hibernate layer using the HibernatePersistenceStrategy and the different approach that is, somewhat unfortunately, required to take when going the Spring way. For instance, the usage of Spring's HibernateTemplate or HibernateCallback(s) are encouraged, effectively tying the DAO code to Spring, but also moving the transaction headaches to configuration. As a developer, I tend to favor the fact that I do not have to worry about transactions or such horrible things, and leave those headaches to those who integrate with various systems. Being able to do it by configuration is a good plus.

-- Ungluing the implementation code and allowing the removal of HibernateRollerImpl and friends, since each single manager is a different Spring bean, maybe sharing common attributes (such as the HibernatePersistenceStrategy). Those beans are injected in the RollerImpl facade, which allows for easy switching when, for example, unit test comes in the loop.

-- In the very interesting case of the ThreadManager, and more generally the scheduling of tasks, my first thought went about what's going to happen to application managed thread pools or schedulers in a strict J2EE environment. If you intend to run Roller in a J2EE 1.4 containers, you may want to use container-managed thread pools, or WorkManager(s) or other Websphere-like WorkArea(s) and Scheduler(s). Since you can, transparently to the code, lookup an EJB or provide a home-grown implementation of a ThreadFactory/ExecutorService/etc, Spring is very much welcomed here. As an example. the switch from ThreadFactory to ExecutionService(s) in the branches after the one I was working one can be performed from configuration, with a small changes in the ThreadManagerImpl code to allow injection.

#Property loading
As mentionned above, Spring makes it easy to load various property sources. Spring configuration files may also reference property values using the usual ${value} syntax, which is what is used to populate properties among the various manager beans and, among many, provide the datasource parameters depending on the roller.properties and roller-custom.properties. Again, RollerConfig wasn't taken into consideration but it's easy to adapt its implementation to fetch its properties from Spring.

see src/applicationContext-rollerProperties.xml

#Conclusion
I'm not great a concluding so here's some more concrete material

#Files and reference

I've packed some demo code within the following files. I decided against providing a really functional patch to submit to JIRA since my code baseline is already old compared to the recent changes for 4.0 and this whole thing is just a proof of concept.


*
http://denis.balazuc.net/roller/roller_541344-spring-stable.zip
(1) That's the Roller code my build is based on (from version 541344 of the trunk). Much too big (150Mb) to download and messed up since it's my working copy, but well...

*
http://denis.balazuc.net/roller/roller_541344-spring-stable-webapp.zip
My current test web app only (Roller - no Planet) with all JAR files but exploded roller-*.jar for reference (25Mb)


*
http://denis.balazuc.net/roller/roller_541344-spring-stable-webapp-nojars.zip My current test web app only (Roller - no Planet) without any JAR file and exploded roller-*.jar for reference (6.7 Mb)


*
http://denis.balazuc.net/roller/roller-trunk-541344-spring-patch.txt
Patch made from (1) from trunk version #541344. You will still need the JAR files listed above. I"m not very familiar with patching so it might not be reliable.


First things you may want to look at are the Spring configuration files
(it's not XML hell, honest)

/src/applicationContext-rollerProperties.xml
/src/applicationContext-rollerMail.xml (used in MailUtil.java)
/src/applicationContext-rollerDatasource.xml

/src/applicationContext-roller.xml
/src/org/apache/roller/business/applicationContext-business.xml
/src/org/apache/roller/business/applicationContext-business-hibernate.xml


#Build considerations
I had to replace a few JAR files with new ones and created
/tools/spring-2.0.5
/tools/spring-2.0.5/acegi-security-1.0.3.jar
/tools/spring-2.0.5/ehcache-1.2.4.jar
/tools/spring-2.0.5/spring.jar


#More files for the curious

* There is a
/src/org/apache/roller/business/applicationContext-business-hibernate2.xml
along with its own hibernate2 implementation package, which uses a Hibernate SessionFactory provided by Spring and delegating transaction management to the configuration, rather than implementing a specific "strategy". This setting is not currently working as it would require a different approach on DAOs. The provided example shows how transaction management could be done, but ideally, Spring's HibernateTemplate and HibernateCallback(s) should be used to perform simple unit of (database) work within a transaction into the Hibernate implementation layer if Spring is to be exploited with its full potential.

* The file /src/org/apache/roller/business/applicationContext-business-jpa.xml is not functional at all but exists for the sole purpose of demonstrating how painlessly implementations can be switched if required.


**
http://denis.balazuc.net/roller/blug-project-demo.zip
This is a personal project I had started after Struts-ifying Pebble (http://pebble.sourceforge.net/), which still serves my wife's blog nicely but needs replacement, and before meeting Roller. Most of the Spring ideas exposed here come from there. I've tried to separate the DAO and business layers in various projects, which helps leveraging Spring's benefits.

Cheers
Denis Balazuc

Reply via email to