Tuesday, September 30, 2008

Struts 2 Validator on Forwards


As I had to add some complex features to our working Struts 2 application, I had to deal with already built in validator functionality in Struts2 that could be complex. Specifically, when dealing with conversations-like scenarios, this problem can really be a big one if the validation associated with the forward request is applied via annotations, xml or the validate method. I thought to share some snippets that hopefully will someone. Consider the following:


package sample;

public class MyValidatorInterceptor1
extends AnnotationValidationInterceptor {
/**
* Method that is triggered in prior to calling
* the intercept() method. This method allows
* to control whether the intercept is disabled
* in certain condition.
*/
@Override
protected boolean applyInterceptor
(ActionInvocation invocation) {
boolean certainCondition = true
if (certainCondition) {
return false;
}
return super.applyInterceptor(invocation);
}
}

This interceptor implementation as described above enhances the provided AnnotationValidationInterceptor from Struts 2 to disable the interceptor on demand (based on some condition). It's important to mention that the code above extends the class AnnotationValidationInterceptor as base class so as to not take away current functionality offered in Struts 2 (validation annotation). Additionally, the doIntercept() method may be overridable to perform additional validation that can be applied per class. Consider the scenario where you define your want to add validation complex validation per method and disable all required validations in XML. This certainly introduces many possibilities. Now, it will be worth to mention that struts.xml will need to have this as well to be useful.


<struts>
<interceptors>
<interceptor name="dynamicValidator"
class="sample.MyValidatorInterceptor1"/>

<interceptor-stack name="myInteceptorStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="dynamicValidator">
<param name="excludeMethods">
input,back,cancel
</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">
input,back,cancel
</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>

<default-interceptor-ref name="myInteceptorStack"/>
</struts>

Note that the configuration now uses almost all interceptors defined in the paramsPrepareParamsStack except the validator one. This is one architectural part of Struts 2 which I find it very compelling. You can grab any part of the interceptors, swapped with your custom ones and provide meaningful processing according to your needs.

Now, the validator code above deserves further explanation. Consider the case when an action forwards control (with the result type redirect-action). The forwarder action may not necessarily know whether the forwarded action is really validated or not, and hence the validation process will still be applied. In such case, one may need to allow some processing to decline validation on the subsequent action handling (such as placing a token on request/session/valueStack for starters).

Friday, September 26, 2008

The Domain Model and Struts 2.x

A couple of months ago I had a new requirement where I had to display the look (ui) of only a few of my components in my Struts 2.x application. Specifically, I had to display some dates as date-time while others had to remain the same. I started to hold down for a minute and decided to think how best to tackle the problem. I hate to touch a lot of code for no reason and as many know, changing the domain model code is typically not a good idea.

Struts2 MVC and Converters

In the good old days of Struts 1.x, one would have to register a special Converter object and register it so that BeanUtils can use it when ActionForms are populate via the ActionServlet (wao, I can't believe I had to learn all that). This was a good way to provide good conversion across all your application, however this approach forces the Converter to be applied in all objects of the same type.

As an MVC implementation, the controller should be able to have a way to know what conversion process to use in each action mapping processing session. Struts 2.x provides a way to do this in a clean way with the use of the StrutsTypeConverter class. After creating your own converter class, you can register your converter globally (in a file that must be named xwork-conversion.properties). Alternatively, you can create a -conversion.properties file at the same package level where your model object resides and now you can have custom conversion per property. The latter approach is a powerful feature as it allows you to define a properties file with key,value pair listings. Each key represents the name of the java property of the model object and its value is the fully qualified converter class name. This approach for conversion is very appealing for the following reasons:

  1. Does not mix Struts2 code with Domain Object model code (not even annotations), thus offering a non-intrusive approach to the rendering of the object.

  2. It encourages a development environment where this file can be generated, overriden or even replaced at build time. This scenario is very appealing for companies that do customizations of a product thus encouraging a "configuration management" approach in the presentation tier.

  3. It allows you to provide a different converter per property, leaving the model type unchanged.

I was able to successfully display each property as needed and progressively move each component that was required.

Wednesday, September 24, 2008

Powered by Struts 2.x

After working with Struts 2.x for some months now, I feel more comfortable in commenting on some of the features that I feel have been helping me as well as some others that I feel needs some attention. In writing these, I hope that I may be able to learn some from those who may wish to attempt correcting me.

Overall Configuration
The basic file needed is one named "struts.xml". Properties (constants) can be overridden using a struts.properties files. This file takes priority and this is an interesting approach and this seems to mixed well with Maven environments (as well as Ant, of course). You can modularize your application including files of the same type (same DTD) as struts.xml. The one thing I don't understand is the use of DTD over XSD. Not exactly sure why they haven't adopted XSD as the latter are simply more powerful.

Rendering Engine
The fact that you don't need to JSP for your views has been a significant change for me. I know that you can avoid using JSPs using Struts 1.x but the amount of code (and configuration) could be very tedious. With Struts 2.x support for Velocity and Freemarker are already built-in. I've been using the latter for sometime now and I simply love it.

Now, if you consider the "hype" that OSGI is bringing to the JEE world, a templating engine technology (e.g. Velocity, Freemarker) over JSP technology is more appealing as this will allow OSGI environments to resolve proper templates based on the OSGI headers (within each jar). Struts 2.x comes with bundled with a set of predefined templates that the classloader picks from, thus encouraging this pattern (but not demanding it). I see this as a strategic architectural choice which ought to be observed when considering OSGI powered applications.

Servlet Technology and Controllers
Struts 2.x uses Servlet filters (instead of Servlets) as the driving force of the application. This can be good and bad for several reasons. I have found it to be good thus far. Filters can give you the feeling that "intercepting" a controller is simpler (filtering the request). Struts 2.x has default interceptors for different things such as those that parses the parameters and placed them into the value stack, double token submissions, etc. You can always implement your own.

You have a clear option of which interceptors to use and their ordering. This is a powerful feature that if misused can prove a big problem. I recently found a bug on the way I had configured our interceptors. You can do nesting of interceptors so I was repeating the same interceptor multiple times thus doubling my round-trips to the database. Implementing your own is very trivial.

Additionally, Struts 2.x advertise thread-safety POJOs as your actions (Struts 1.x should remember that this issue can make you rely heavily on request/session attributes). I have found that the nature of making this action objects thread-safe are by virtue of having a "request" scope. Since you have an option to use Spring for dependency injection, you configure/annotated your POJOs with scope "session" and block this behavior. I've found this a problem in some cases. I'm still investigating this issue, but does bring something to the table. You can effectively perform IoC in the way Action (controllers) are used as part of your MVC.

IDE Tooling - The good, the bad and the ugly!
As most fairly new frameworks tooling is what helps the adoption of a framework. Struts 2.x lacks this component very much as there are not that many IDEs with out-of-the-box support for Struts 2.x. As of the today, there are few who show some promise, none of which I would recommend investing (yet!). I am a fan of Eclipse, and I have to say that the WTP project works just fine with Struts 2.x and developing with it has been a breeze. Configuring struts 2.x within eclipse is somewhat trivial and I expect IDE plugins to simply help with XML editing.

I have spent a lot of time reading the struts-core source code and I simply like it. I think its a good practice for any developer trying to understand the framework and I'm sure you'll find it very readable, well commented with few problems (although I'm sure there are some). Overall, my experience with Struts 2.x has been very pleasant and I have good reasons to recommend it as a choice for development of new enterprise applications.