Mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Denis Balazuc <de...@balazuc.net>
Subject Spring Roller
Date Sun, 03 Jun 2007 03:38:04 GMT
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



Mime
View raw message