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).

No comments: