When you configure your XWork application (be-it WebWork or something else), you define your Action, Interceptors which intercept Action invocation, and Results, which get executed when an Action returns. You have complete control over the implementation of these classes – beyond the fact that you need to implement some basic interfaces (@Action@, @Interceptor@ and @Result@ respectively), however you have absolutely no control over how these classes get instantiated by XWork at runtime – internally XWork just gets your class, and calls @newInstance@. The limit of control you have over how Xwork sets these objects up is in the form of String/Value pairs defined in the configuration.
So why is this a problem? Well, lets take the example of my “Swing/XWork prototype(A GUI framework using XWork)”:http://www.magpiebrain.com/archives/000181.html I posted earlier. In it I created an Interceptor to monitor the progress of an Action. As the Action is invoked and completed, my Interceptor calls methods on a @ProgressRegister@ object. The problem is that I cannot pass references to my @ProgressRegister@ object into the interceptor when created – I am forced into creating a Singleton method accessor on @ProgressRegister@. In an ideal world, I would be able to define my @ProgressRegister@ object, and tell XWork that this object instance should be passed in whenever my interceptor is created:
...
This is of course exactly how IoC frameworks like Spring and Pico container work (the @bean@ definition from above is actually lifted straight from a Spring XML file). Ideally, XWork’s configuration could be overhauled to use Spring internally, but this is a big job. Instead I have a compromise.
Lets imagine an Interceptor class called @SpringInteceptorFactory@ which implements @Interceptor@. It takes a single string parameter which equates to the name of another Interceptor defined in a Spring config file. When invoked by XWork, @SpringInteceptorFactory@ creates an Interceptor of the relevant type (with properly wired dependencies) and executes it accordingly. This same solution could be used to create @Result@ or @Action@ objects. I can’t escape the feeling that adding yet another config file (in the shape of a Spring XML definition) is going to complicate things, however if you were already going to use Spring (Or Pico/NanoContainer) perhaps its not that much hassle after all.
5 Responses to “XWork: Actions, Interceptors, Results and IoC”
You could also populate the ActionContext ThreadLocal with the relevant objects your Interceptors can use. Your calling object could be set up using Spring to have the objects it needs, then put them in the extra context map that you pass to the ActionProxyFactory, and they will be available to your Interceptor via ActionContext.getContext().get(KEY);
I do want to make it easier to make these other objects be built by outside containers, but it’s going to have to wait till at least 1.1….
This of course also begs the question of whether a command pattern implementation on top of Spring would be an interesting addition to that framework, considering it already has AOP for interceptors and lightweight container for contexts.
I think that is what XWork would become if you integrated it with Spring. Much of XWork’s internals would vanish to be replaced by Spring. I’m actually starting to think that in such a situation there is very little XWork left…
I’m not sure that’s true… there’s value in a command pattern implementation that’s decoupled from direct method calls… Plus, XWork Interceptors give you access to XWork specific internals like the ActionInvocation.
Results, etc, are more things XWork would add… Don’t let AOP blind you to the power of normal OOP ways of doing things.
Using Spring for some of the XWork internals would still give you a command pattern decoupled from direct method calls – in fact it would be possible to configure yourself which method got called on an Action to execute it for example, giving an even more abstract framework (the need for interfaces vanishes).
Certainly XWork has value – it is a framework with a specific task that works well at what it does. Sure, someone could implement something similar using Spring on its own, but they would still have to supply the higher level mappings to make it as easy to use as XWork. I still think that by using Spring internally, you would be left with a system with the same API as now, but with more flexibility. Spring can handle Action and Result invocation, and handle interceptors, and to get the full benifit out of integrating with Spring this would make sense. The question is, is this added flexibility worth coupling XWork to another framework (be it Spring or Pico or…), or is it worth the reimplementation work.