You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@roller.apache.org by Denis Balazuc <de...@balazuc.net> on 2007/06/03 05:38:04 UTC

Spring Roller

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



Re: Spring Roller

Posted by Anil Gangolli <an...@busybuddha.org>.
One of the valuable aspects I have found in adopting DI is that it 
encourages modularity and opening up the component model in such a way that 
extension and replacement of implementations in all areas of the code just 
becomes more natural and easier.

I'm interested in seeing us adopt enough of these practices and patterns 
that we get those benefits, whether with Guice or Spring.

I'm curious how the use of annotations provide for this kind of 
extensibility / pluggability without the need to rebuild, without limiting 
what can actually be plugged in or replaced without recoding existing code, 
and without the need to code our own configuration handling code.   These 
are things I know how to get with Spring and XML-based configuration. I 
think if we can get them with Guice, I'll be ok with it.

--a.


----- Original Message ----- 
From: "Dave" <sn...@gmail.com>
To: <de...@roller.apache.org>
Sent: Friday, June 08, 2007 7:00 AM
Subject: Re: Spring Roller


> On 6/7/07, Denis Balazuc <de...@balazuc.net> wrote:
>> 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!)
>
> I haven't had a chance yet, but I will once I'm ready for Roller Guice
> show and tell -- I'm getting very close to that point now.
>
> - Dave
> 


Re: Spring Roller

Posted by Dave <sn...@gmail.com>.
On 6/7/07, Denis Balazuc <de...@balazuc.net> wrote:
> 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!)

I haven't had a chance yet, but I will once I'm ready for Roller Guice
show and tell -- I'm getting very close to that point now.

- Dave

Re: Spring Roller

Posted by Denis Balazuc <de...@balazuc.net>.
Hi Allen

Thanks a lot for the feedback!
Allow me some more comments and attempts at being a little clearer :-)

 > I took a bit of a look at it and it looks fine, thanks for providing
 > this example.  It's a little hard to compare since it doesn't actually
 > run properly, but I was able to get the basic idea.

Sorry about that. I jumped in the middle of some major code changes for 
4.0 so I had troubles getting something stable to run, but yup, that 
wasn't really the goal.

 > As for my general
 > thoughts on Spring vs. Guice ...
 >
 > http://code.google.com/p/google-guice/wiki/SpringComparison
 >
 > Guice seems to be the smaller, lighter, and more focused DI option and I
 > strongly prefer their Module approach and their use of annotations over
 > config files.  The performance stuff sounds interesting as well although
 > I don't consider it a huge issue.  The benefit of Spring of course is
 > that it offers more options in terms of non-DI stuff such as the mail
 > sender and thread executor stuff.
 >

Yes, I've tried to show in my sample, there's a lot more in Spring than DI.
Generally speaking and performance-wise, the only hit with Spring is at 
application startup, so it's of very little concern in a web app world, 
or systems such as Roller.
Actually, I've heard a lot of claims about Spring slowliness that have 
been proven wrong with my past experiences, and honestly, the benchmark 
code 
(http://google-guice.googlecode.com/svn/trunk/test/com/google/inject/PerformanceComparison.java) 
looks a little silly to me: it goes down in the guts of the Spring API 
that no-one ever touches to benchmark some accesses or construction 
patterns that the Spring factories implementation classes optimize, 
bypassing that totally, which is the whole point of Spring providing 
such a vast API and set of objects. There are many areas where 
performance actually improves by using Spring since you can for example 
lazy-load any bean you choose and don't have to manage any synchronized 
access (or very few on implementation specific classes) or 
caching-related things in the code.

I don't have exact figures for Roller but I noticed a 12s delay vs 8s in 
Tomcat context loading using Spring.
Past that point, without using lazy-loading, I couldn't see any 
difference, even when adding interceptors to log DAO or business 
methods. You can "feel" beans being lazy-loaded (1/2s at worse?) when 
switching that on but again, that doesn't matter since it's done once.


 > * I definitely hate all the config files.  I don't know if you separated
 > them for example purposes, but you have like 7 config files and IMO that
 > is way confusing.  I would really only consider Spring if this was all
 > merged into a single file or at least just one or two files.


The mail and database provider are in separated files to make sure that 
modules that would only use the mail provider or database provider don't 
load any unwanted/unnecessary bean by using only one file (a common 
mistake with using Spring without lazy-loading, which I did when I 
started playing with the Roller code for mail util).

Now for all the rest (all the XML for the implementation beans), it 
really is just me and my coding style (I'm a "500 lines of functional 
code in a single java class is probably more than you'll ever need" kind 
of refactoring ayatohlah). It's very easy to have only 3 Spring files, 
or even only 1. However, separating the business impl also helped me 
switch from one back-end to another in one line while 
testing/experimenting.

Using config files is indeed a different approach than using 
annotations. I am personnally a fan of XML and I much prefer 
configuration files to instrumenting code with annotations or other 
comment tags that are tool-specific, requiring for example a build cycle 
to fix a setting (such as the hibernate tags). I also tend to dislike 
binding business objects to anything else than the API they belong to. 
However, that's a very philosophical debate that we'll keep for another 
time.


 > * The property file injection thing is interesting and seems powerful,
 > but i'm worried it's not entirely appropriate for us.  for one, it means
 > that there are now 2 ways to get properties out of those config files
 > (via Spring and RollerConfig) and that complicates things.  second, lots
 > of the the stuff in those configs doesn't apply to the backend, so it
 > seems weird to support duplicated config mechanisms for the backend
 > wired by Spring and for the rest of the code.  In your example you
 > didn't include the fact that a 3rd way to specify roller properties is
 > by supplying a path to a file via a jvm option, so you would need to
 > support that as well.

As I mentionned in my previous mail, I didn't went as far as I wanted to 
with property files.
Of course, RollerConfig and RollerRuntimeConfig should use the same 
mechanism and sources,
which can easily be done by modifying their implementation. Ideally, 
there should be few to no references to static methods in a code that is 
using DI as its core (each property a class needs should be injected, so 
as to help testing and re-use) but we can get around easily with that 
since RollerConfig is pretty much everywhere. I didn't provided a 
RollerConfig implementation that reads its configuration from Spring for 
lack of time, and fear to break too much stuff in the same batch.


 > In your example you
 > didn't include the fact that a 3rd way to specify roller properties is
 > by supplying a path to a file via a jvm option, so you would need to
 > support that as well.

I wasn't aware of that option, but that should be a breeze to add. That 
won't probably even require writing any code.

 > * The way you did the persistence stuff is probably what i liked least.
 >  I am not in favor of wiring up our backend in a Spring specific way
 > using things like Springs HibernateUtils, etc.  I already think that ORM
 > solutions provide enough of a challenge in terms of figuring out exactly
 > how a call to save an object turns into actual jdbc actions and tracing
 > that process becomes much more complicated when you mix in yet another
 > dependency like Spring.  So I am not a fan of introducing Spring in this
 > area and what we have now works fine so there is no reason to change it.
 >  All that being said, this stuff has nothing to do with using Spring DI
 > for the backend and is not required as far as I know so it's just
 > something I would cut out.

Indeed, there is no reason to change the existing and the "hibernate2" 
package is a scary, ugly and bad attempt at showing how transaction can 
be moved to yet-more-XML-headaches and replace home-grown "strategies".

Ideally, it is best to use Spring's HibernateCallback(s) and 
HibernateTemplate, which is one area where you want to tie an 
implementation layer with Spring. But with those, you usually never have 
to manage any transaction aspect, unless you do very complicated and/or 
unlawful things with your SQL/Hibernate code, or need to support 
transactions other multiple datasources. It also allows for using JTA by 
just switching it on.
The business impl layer of this project
http://denis.balazuc.net/roller/blug-project-demo.zip
is probably  a much better example of a simple DAO layer using Spring 
with Hibernate.

Basically, HibernateXXXImpl  (or HibernateRollerImpl - see below) can be 
taken as is, have its strategy configured and injected through Spring, 
and off we go.


 > * You suggested getting rid of the XXXRollerImpl classes and just using
 > a generic RollerImpl class but that sounds like a bad idea in my mind.
 > The purpose of having those classes is to force a persistence strategy
 > as a whole meaning that a JPARollerImpl should only allow injection of
 > JPAXXXManagerImpl classes.  From an api point of view it would be very
 > silly to be mixing JPA and Hibernate code together at runtime.

You could go either or both ways actually.
Injecting a XXXRollerImpl in RollerFactory, or get rid all along of the 
XXXRollerImpl really is a design-decision. My only reason was to remove 
classes that do some wiring by code, managing their own singletons to 
show how it gets simplified. It surely makes little sense in the 
existing implementation. However, using Spring, it's a matter of 
defining a "prototype" (or "abstract" or "template") bean and moving 
configuration around, as long as you have the proper setters and getters.


 > Like the
 > last point, I think this is not something that really has a bearing on
 > whether or not Spring DI could be used, but it's something that I am not
 > a fan of in your particular design.  Also related to this one is that I
 > am 100% against allowing for public setter methods in the Roller
 > interface or it's implementations.  I mentioned this before, but the
 > Roller instance should be immutable as far as the api goes and I think
 > we need to enforce that when we do this DI work.
 >

I could not agree more that setters have nothing to do in the Roller 
interface. However, If you're using setter injection, you need public 
setter (getters aren't necessary if not part of the implemented 
interface) in interface implementors. I am usually against public 
setters when it's not needed, but once you have DI in mind while 
designing/coding, there's rarely any misuse of it. You can opt for 
constructor injection, but unless the whole design is 100% 
interface-driven, it makes it harder to integrate interceptors, use 
dynamic proxies or reflection without a default constructor.

When I started working using DI, having public setters and getters used 
to itch me a lot (maybe less than protected member variables though), 
but since the "javabean-like" approach gets on everything, from Struts 
action forms to Spring beans, it's now became the usual pattern and at 
the end of the day is much cleaner than using protected members which 
access can't be traced  to avoid getters/setters (even protected), and 
allows for a lot more fun such as mocks/stubs/etc.

 > * The thread manager stuff is probably the most interesting piece in my
 > mind and I wouldn't mind making use of Spring's built-in executor
 > service stuff.  The problem though is that we don't really have much
 > need to do this 'cuz our code is fine as it is, and the other problem is
 > that translating our config file properties into Spring has proven
 > challenging with the Acegi stuff and I am hesitant to try.

The ExecutorService is actually a java.util.concurrent implementation 
that got switched in Roller between two updates I did of the code IIRC. 
All I did is add a constructor to inject the service, as I did for all 
other XXXimpl, comment out my current Spring conf, switch it to 
injecting an ExecutorService using the parameters I gathered - that's 
all....Yup, that easy - and that was fun to do! :-)

It's actually a good example where Spring can really make a difference 
with its possibilites. You can inject anything from a flat static 
implementation of an interface, to an EJB, and this totally 
transparently at a switch of a config. With Spring's use of interceptors 
and dynamic proxies, you can go extremely far.
I'm currently working on a well-known brand of J2EE 1.4 app servers IRL 
and with current threadmanager and scheduling implementation, I am not 
sure I would not get barked at and asked to use a WorkManager if I were 
to run Roller tasks on them. Being able to not touch the Roller code 
(maybe provide my own external package) and change one bean using a 
config file to make use of those server's built-in TaskScheduler(s) 
would be a very good thing.


Aside from the rich set of services that Spring offers, one of my main 
argument in favor of Spring for Roller is actually that it's already 
used in Roller with Acegi, which makes the config changes in the webapps 
and build files quite minimal. Also Struts/Struts2 modules already could 
benefit from it: actions that want mail senders, or filters, or 
renderers, all this may be injected through Spring extremely easily with 
the Struts plugin. I was actually surprised that it wasn't already that 
way and that they were still hard-wired dependencies on various services.

As for translating configuration files, I'm looking for something I 
could help on, show me where to look ;-)
It is true that the learning curve with the Spring config is steep at 
first but after the getting-used-to phase, it's easy to navigate between 
the Spring API and the XML to change pretty much any aspect of an 
application at a glance.


 > So overall my basic feeling is that Guice provides the nicer option
 > specifically for DI and I love that it's all done via java code and
 > annotations and that the way you define Modules provides some compile
 > time checking.  Spring would work fine for DI, but I am still just luke
 > warm on the config file wiring, so if I was making a decision now I
 > would go with Guice.
 >

As I mentionned earlier, I much prefer configuration files to 
instrumenting code with annotations but it all boils down to design 
decisions. Spring makes sense since it's already in Roller and allows 
for all those neat services and helpers that it comes with on top of the 
DI way that Roller is taking. It's worth the XML headaches IMO (I can't 
legally ship aspirin from here...). In the end, a good Spring 
deployement should hide the complexity of its configuration to end-users 
or users of the API but may go as far as one wants in decoupling code.

If you want more Spring magic to be shown (I haven't covered Struts2 
yet!) or someone to do any config macarena you hate, I'd be happy to do 
more. If you give the go on Guice I'll just read more on and get my 
hands deeper on it, but in both cases I'd love to help.

Thanks again for the great feedback.

Denis Balazuc
"A good Spring implementation is indistinguishable from magic."
No...Wait...That doesn't sound right...


Allen Gilliland wrote:
> I took a bit of a look at it and it looks fine, thanks for providing 
> this example.  It's a little hard to compare since it doesn't actually 
> run properly, but I was able to get the basic idea.  As for my general 
> thoughts on Spring vs. Guice ...
> 
>  From what I have seen from Spring and Guice so far I would basically 
> agree with what this article says ...
> 
> http://code.google.com/p/google-guice/wiki/SpringComparison
> 
> Guice seems to be the smaller, lighter, and more focused DI option and I 
> strongly prefer their Module approach and their use of annotations over 
> config files.  The performance stuff sounds interesting as well although 
> I don't consider it a huge issue.  The benefit of Spring of course is 
> that it offers more options in terms of non-DI stuff such as the mail 
> sender and thread executor stuff.
> 
> As for some of my thoughts on what I looked at in your code ...
> 
> * I definitely hate all the config files.  I don't know if you separated 
> them for example purposes, but you have like 7 config files and IMO that 
> is way confusing.  I would really only consider Spring if this was all 
> merged into a single file or at least just one or two files.
> 
> * The way you build and configure the mail and db providers is 
> interesting and could be useful, but I don't think it's a significant 
> improvement over what we already have.
> 
> * The property file injection thing is interesting and seems powerful, 
> but i'm worried it's not entirely appropriate for us.  for one, it means 
> that there are now 2 ways to get properties out of those config files 
> (via Spring and RollerConfig) and that complicates things.  second, lots 
> of the the stuff in those configs doesn't apply to the backend, so it 
> seems weird to support duplicated config mechanisms for the backend 
> wired by Spring and for the rest of the code.  In your example you 
> didn't include the fact that a 3rd way to specify roller properties is 
> by supplying a path to a file via a jvm option, so you would need to 
> support that as well.
> 
> * The way you did the persistence stuff is probably what i liked least. 
>  I am not in favor of wiring up our backend in a Spring specific way 
> using things like Springs HibernateUtils, etc.  I already think that ORM 
> solutions provide enough of a challenge in terms of figuring out exactly 
> how a call to save an object turns into actual jdbc actions and tracing 
> that process becomes much more complicated when you mix in yet another 
> dependency like Spring.  So I am not a fan of introducing Spring in this 
> area and what we have now works fine so there is no reason to change it. 
>  All that being said, this stuff has nothing to do with using Spring DI 
> for the backend and is not required as far as I know so it's just 
> something I would cut out.
> 
> * You suggested getting rid of the XXXRollerImpl classes and just using 
> a generic RollerImpl class but that sounds like a bad idea in my mind. 
> The purpose of having those classes is to force a persistence strategy 
> as a whole meaning that a JPARollerImpl should only allow injection of 
> JPAXXXManagerImpl classes.  From an api point of view it would be very 
> silly to be mixing JPA and Hibernate code together at runtime.  Like the 
> last point, I think this is not something that really has a bearing on 
> whether or not Spring DI could be used, but it's something that I am not 
> a fan of in your particular design.  Also related to this one is that I 
> am 100% against allowing for public setter methods in the Roller 
> interface or it's implementations.  I mentioned this before, but the 
> Roller instance should be immutable as far as the api goes and I think 
> we need to enforce that when we do this DI work.
> 
> * The thread manager stuff is probably the most interesting piece in my 
> mind and I wouldn't mind making use of Spring's built-in executor 
> service stuff.  The problem though is that we don't really have much 
> need to do this 'cuz our code is fine as it is, and the other problem is 
> that translating our config file properties into Spring has proven 
> challenging with the Acegi stuff and I am hesitant to try.
> 
> 
> So overall my basic feeling is that Guice provides the nicer option 
> specifically for DI and I love that it's all done via java code and 
> annotations and that the way you define Modules provides some compile 
> time checking.  Spring would work fine for DI, but I am still just luke 
> warm on the config file wiring, so if I was making a decision now I 
> would go with Guice.
> 
> Thanks again to Denis for providing the Spring example, it's much easier 
> to do a comparison when we can see both options :)
> 
> -- Allen
> 

Re: Spring Roller

Posted by Allen Gilliland <al...@sun.com>.
I took a bit of a look at it and it looks fine, thanks for providing 
this example.  It's a little hard to compare since it doesn't actually 
run properly, but I was able to get the basic idea.  As for my general 
thoughts on Spring vs. Guice ...

 From what I have seen from Spring and Guice so far I would basically 
agree with what this article says ...

http://code.google.com/p/google-guice/wiki/SpringComparison

Guice seems to be the smaller, lighter, and more focused DI option and I 
strongly prefer their Module approach and their use of annotations over 
config files.  The performance stuff sounds interesting as well although 
I don't consider it a huge issue.  The benefit of Spring of course is 
that it offers more options in terms of non-DI stuff such as the mail 
sender and thread executor stuff.

As for some of my thoughts on what I looked at in your code ...

* I definitely hate all the config files.  I don't know if you separated 
them for example purposes, but you have like 7 config files and IMO that 
is way confusing.  I would really only consider Spring if this was all 
merged into a single file or at least just one or two files.

* The way you build and configure the mail and db providers is 
interesting and could be useful, but I don't think it's a significant 
improvement over what we already have.

* The property file injection thing is interesting and seems powerful, 
but i'm worried it's not entirely appropriate for us.  for one, it means 
that there are now 2 ways to get properties out of those config files 
(via Spring and RollerConfig) and that complicates things.  second, lots 
of the the stuff in those configs doesn't apply to the backend, so it 
seems weird to support duplicated config mechanisms for the backend 
wired by Spring and for the rest of the code.  In your example you 
didn't include the fact that a 3rd way to specify roller properties is 
by supplying a path to a file via a jvm option, so you would need to 
support that as well.

* The way you did the persistence stuff is probably what i liked least. 
  I am not in favor of wiring up our backend in a Spring specific way 
using things like Springs HibernateUtils, etc.  I already think that ORM 
solutions provide enough of a challenge in terms of figuring out exactly 
how a call to save an object turns into actual jdbc actions and tracing 
that process becomes much more complicated when you mix in yet another 
dependency like Spring.  So I am not a fan of introducing Spring in this 
area and what we have now works fine so there is no reason to change it. 
  All that being said, this stuff has nothing to do with using Spring DI 
for the backend and is not required as far as I know so it's just 
something I would cut out.

* You suggested getting rid of the XXXRollerImpl classes and just using 
a generic RollerImpl class but that sounds like a bad idea in my mind. 
The purpose of having those classes is to force a persistence strategy 
as a whole meaning that a JPARollerImpl should only allow injection of 
JPAXXXManagerImpl classes.  From an api point of view it would be very 
silly to be mixing JPA and Hibernate code together at runtime.  Like the 
last point, I think this is not something that really has a bearing on 
whether or not Spring DI could be used, but it's something that I am not 
a fan of in your particular design.  Also related to this one is that I 
am 100% against allowing for public setter methods in the Roller 
interface or it's implementations.  I mentioned this before, but the 
Roller instance should be immutable as far as the api goes and I think 
we need to enforce that when we do this DI work.

* The thread manager stuff is probably the most interesting piece in my 
mind and I wouldn't mind making use of Spring's built-in executor 
service stuff.  The problem though is that we don't really have much 
need to do this 'cuz our code is fine as it is, and the other problem is 
that translating our config file properties into Spring has proven 
challenging with the Acegi stuff and I am hesitant to try.


So overall my basic feeling is that Guice provides the nicer option 
specifically for DI and I love that it's all done via java code and 
annotations and that the way you define Modules provides some compile 
time checking.  Spring would work fine for DI, but I am still just luke 
warm on the config file wiring, so if I was making a decision now I 
would go with Guice.

Thanks again to Denis for providing the Spring example, it's much easier 
to do a comparison when we can see both options :)

-- Allen


Denis Balazuc wrote:
> 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
>>

Re: Spring Roller

Posted by Denis Balazuc <de...@balazuc.net>.
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
>