Struts

Name:
Location: Bangalore, India

Tuesday, March 17, 2009

Struts - Upload Files Functionality

This link helps us understand better about how hiding the browse button can be achieved through CSS styling.

Monday, May 26, 2008

Tiles

Struts-Config.XML

<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
</plug-in>

We need to include the below tiles tag library in the JSP page where we do all the tiles code.

<%@ taglib uri="/WEB-INF/tld/struts/struts-tiles.tld" prefix="tiles"%>

<head>
<title>
<tiles:getAsString name="title" ignore="true" />
</title>
</head>
<body>
<tiles:getAsString name="header" ignore="true" />

Tutorial link:
http://www.allapplabs.com/tiles/create_a_tile_layout.htm

As you can see the title (Key) is given in the above tiles tag and the value (GTEM Request Search Requests) will be fetched from tiles definitions. Same procedure for header as well.

<tiles:insert attribute="body" />

Insert the tiles in the correct regions of the layout using the tiles:insert tag. To insert the SearchRequest JSP, use the tiles:insert tag, which inserts any page or Web resource that the framework refers to as a tile. The tag effectively defines a region in the tile layout. Remember, the objective of the tile layout is to lay out the tiles into the layout.

Tiles-defs.xml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">

<tiles-definitions>

<definition name="simple_layout" path="/uicommon/Menu.jsp">
<put name="title" type="string" value="welcome" />
<put name="header" type="string" value="headerinformation" />
<put name="menu" type="string" value="menu" />
<put name="body" value=""/>
</definition>

<definition name="testPage" extends="simple_layout">
<put name="title" type="string" value="welcome" />
<put name="header" type="string" value="headerinformation" />
<put name="menu" type="string" value="Contact" />
<put name="body" value="/jsp/tiles/jsp/test.jsp"/>
</definition>


<definition name="searchRequestPage" extends="simple_layout">
<put name="title" type="string" value="GTEM Request Search Requests" />
<put name="header" type="string" value="Request : Search Requests" />
<put name="menu" type="string" value="Request" />
<put name="body" value="/jsp/request/jsp/SearchRequest.jsp"/>
</definition>

</tiles-definitions>

Struts-config_Request.xml

<action
path="/app/SearchRequest"
attribute="RequestForm"
name="RequestForm"
scope="request"
validate="false"
type="com.bofa.gcib.gtem.action.request.RequestSearchAction">
<!-- forward name="success" path="/jsp/request/jsp/SearchRequest.jsp"/-->
<forward name="success" path="searchRequestPage"/>

Tuesday, May 20, 2008

How to create Custom RequestProcessor

This link will help us to learn about custom request processor.

If we are using Tiles in our application then our Custom RequestProcessor need to extend TilesRequestProcessor.

Add these lines to your struts-config.xml file after the <action-mapping> element to inform Struts that CustomRequestProcessor should be used as the RequestProcessor class:

<controller>
<set-property property="processorClass"
value="com.sample.util.CustomRequestProcessor"/>
</controller>

Thursday, April 17, 2008

Success/Error Messages in Struts

How to set success/error message?

Have a property (SaveStatus) and set the value to 1(means true) at the end of the method in insert/update functionality (methods). Set the same property to 2 inside the catch block which means we caught an exception.

This method is part of DAO which interacts with the database

public RequestDTO updateRequest(RequestDTO objRequestDTO) {

try{

// code block

objRequestDTO.setSaveStatus(1);
}
catch (Exception ex) {
ABCLogger.ABCLog(CLASS_NAME,
"In updateRequestDetails()->Exception:" + ex.getMessage(),
ABCLogger.ERROR);
ex.printStackTrace();
objRequestDTO.setSaveStatus(2);
} finally {
DBUtility.releaseConnection(objConnection);
}
}

In action class based on the status set in DAO we generate the success/error message.

if (saveStatus != null && saveStatus != 0)
{
if(saveStatus.toString().equals(ABCApplicationConstants.ABCCONSTANTS_ABCSTATUS_ACTIVE)){
ActionMessages messages = getMessages(request);
if(messages == null) messages = new ActionMessages(); ActionMessage msg = new ActionMessage("request.msg.success",objRequestDTO.getRequestDetailsKey());
messages.add("message",msg);
saveMessages(request,messages);

}
else{
objRequestForm.setRequestDetailsKey(null);
throw new ABCExceptionBean("ABC_REQUEST_1000", "AE");
}
}
We got something called MessageResources.properties file where we usually store the name/value pairs.
Struts-config entry for MessageResources.properties:
<message-resources null="false" parameter="resources.MessageResources"/>

Entry in Message Resources.properties file:

# -- Struts Validator Error Messages
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.byte={0} must be a number.
errors.email={0} is an invalid e-mail address.
errors.currency=The '{0}' field should be a dollar amount.

# -- User defined Error Messages
request.msg.success={0} - Request is saved successfully
tbu.errors.tbuName=TBU Name

ActionMessage class’s constructor is overloaded to take multiple values. So if we pass 2 values the second value that we pass will come and sit in {0}. In our example we are passing the request key which will be shown to the user.
Output:
123753 - Request is saved successfully

If we don’t pass a second parameter to the ActionMessage constructor then the message shown to the user will be plain text that’s stored in the properties file.

request.msg.completed.success=Full Return Request is completed successfully

This is how we display the success message on page.

<html:messages id="message" message="true" property="message">
<tr>
<td class="rmt-passMsg">
<B><bean:write name="message" /></B>
</td>
</tr>
</html:messages>

Explanation:
ActionMessages messages = new ActionMessages();
messages.add("message",msg);

As you can see the message (key) we use the same key in the html:messages tag in id and property tags.

Error Messages:
Creating custom exceptions.
Xerces – API:
http://xerces.apache.org/xerces-j/apiDocs/index.html

All our custom exception messages that are shown to the user are stored in an XML file (ABCExceptions.XML).

<?xml version="1.0" encoding="UTF-8"?>
<EXCEPTION_ROOT>
<EXCEPTION CODE="ABC_BENEF_1000">
<EXCEPTION_MESSAGE>
Beneficiary is not saved
</EXCEPTION_MESSAGE>
</EXCEPTION>
<EXCEPTION CODE="ABC_BENEF_1001">
<EXCEPTION_MESSAGE>
No records found
</EXCEPTION_MESSAGE>
</EXCEPTION>
</EXCEPTION_ROOT>

public class ABCExceptionHandlerServlet extends HttpServlet{
public void init() throws ServletException{
new ABCExceptionHandler();
}
}
public class ABCExceptionHandler {
private static String strConfigFile = "ABCExceptions.XML";
private static Document objDocument = null;
private static DOMParser objDOMParser = null;
private static Node objRoot = null;

public ABCExceptionHandler() {
initialize(strConfigFile);
}
public void initialize(String strFileName) {
try {
InputStream is = this.getClass().getResourceAsStream(strConfigFile); org.xml.sax.InputSource isrc = new org.xml.sax.InputSource(is);
objDOMParser = new DOMParser();
objDOMParser.parse(isrc);
objDocument = objDOMParser.getDocument();
objRoot = objDocument.getDocumentElement();
} catch (Exception e) {
System.err.println(e);
}
}
}
We have an exception bean ABCExceptionBean where we have
private String exception_Code = null;
private String exception_Message = null;
private String exception_Type = null;

We pass the exception_Code and exception_Type to the constructor of ABCExceptionBean class from the action classes.

Example:
throw new ABCExceptionBean("ABC_BENEF_1000", "AE");

public class ABCExceptionBean extends Exception {

Constructor:
public ABCExceptionBean(String strExceptionCode,
String strExceptionType) {
super();
if (exception_Code == null exception_Type == null) {
this.exception_Code = strExceptionCode;
this.exception_Type = strExceptionType;
}
}

exception_Type -->The 2 different exception types are “AE” and “SE” meaning Application Exception and System Exception. System Exception is nothing but those coming from database like SQL exceptions.
In the action classes, inside the catch block we call the handleException() method of ABCExceptionHandler class by passing the ABCExceptionBean.

catch (ABCExceptionBean objABCExceptionBean) {
objABCExceptionBean = ABCExceptionHandler
.handleException(objABCExceptionBean);
request.setAttribute("errMsg", objGTEMExceptionBean);
}

Note:
As you can see we are setting the error bean object as a request attribute which will be used in the JSP page.
Implementation of ABCExceptionHandler’s handleException method.
public static ABCExceptionBean handleException(
ABCExceptionBean objABCExceptionBean) {

Node contextNode = null;
String strCodeValue = null;
String strExcType = null;

// Get the type of the exception
strExcType = objABCExceptionBean.getException_Type();
if (strExcType != null && !(strExcType.equals(""))) {
if (strExcType.equalsIgnoreCase("SE")) {

objABCExceptionBean
.setException_Message("Exception Occurred while saving, Please enter correct data and try again!");
}
}
strCodeValue = objGTEMExceptionBean.getException_Code();
if (strExcType != null && !(strExcType.equals(""))) {
if (strExcType.equalsIgnoreCase("AE")) {
objABCExceptionBean = getErrorMessage(strCodeValue, objABCExceptionBean);
}
}
return objABCExceptionBean;
}

public static ABCExceptionBean getErrorMessage(String queryName, ABCExceptionBean objABCExceptionBean) {
String errorMessage = null;
try{
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
String expression ="EXCEPTION_ROOT/EXCEPTION[@CODE='"+queryName+"']/EXCEPTION_MESSAGE/text()";
XPathExpression expr = xpath.compile(expression);
NodeList nodes = (NodeList) expr.evaluate(objDocument, XPathConstants.NODESET);
errorMessage = nodes.item(0).getNodeValue();
objABCExceptionBean.setException_Message(errorMessage);
System.out.println(errorMessage);
}
catch(Exception ex) {
ex.printStackTrace();
System.out.println("......Error while parsing.....");
}
return objABCExceptionBean;
}
}
This is how we set the exception bean in request attribute, in the catch block of action class.
request.setAttribute("errMsg", objGTEMExceptionBean);

Error.jsp

<logic:present name="errMsg" scope="request">
<tr>
<td class="rmt-errMsg">
<B> <bean:write name="errMsg" property="exception_Message" /> </B>
</td>
</tr>
</logic:present>

We are specifying the scope in the logic:present tag and the property which holds the error message in the bean:write tag.

How to display the validation.xml error messages.?

<td class="rmt-errMsg"><html:errors /></td>

Including <html:errors /> will display all the error messages from validation.xml to the jsp page.

How to set the right color for Success and Error messages?

Having different colors for success and error messages will help the user to differentiate the messages.

Green color for Success and
Red color for Error messages will be more appropriate.

How to display the desired color to the user?

We can make use of CSS styling to get the color effect.
<td class="rmt-errMsg"><html:errors /></td>

Here we are specifying the class attribute which is defined in a CSS file. We include the CSS file in the JSP page at the beginning of the page like,

<link rel="stylesheet" type="text/css" href="css/rmtPortal_styles.css" />

rmtPortal_styles.css:

.rmt-passMsg{
font-family:verdana,arial;
color:#008000;
font-size:12px;
font-weight:bold;
}

.rmt-errMsg{
font-family:verdana,arial;
font-size:12px;
color:#FF0000;
font-weight:bold;
}

Friday, April 11, 2008

Seven Lessons from the Trenches

Seven Lessons from the Trenches

Friday, April 04, 2008

Struts configuration (XML) file - DTD

Here is the link which helps us to learn more on struts-config.xml mandatory fields.

Wednesday, April 02, 2008

Struts Valdiation Framework

Struts-config.xml:
We need to include the below plug-in, in struts-config xml file to enable Validation framework in Struts.
<!-- Validator Configuration -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml, /WEB-INF/validation.xml"/>
</plug-in>

Form objects:
All our action form objects should extend ValidatorForm in order for the Validation Framework to pick up the properties from form objects.

Example:
public class ContactForm extends ValidatorForm { }
public class PricingForm extends ValidatorForm { }

Then we define Validation.xml with the corresponding form name like the one highlighted in red color.

Validation.xml:

<form-validation>
<formset>

<form name="ContactForm">
<field property="firstName" depends="required,maxlength">
<arg0 key="contact.errors.firstName" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>128</var-value>
</var>
</field>
</form>

<form name="PricingForm">
<field property="firstName" depends="required,maxlength">
<arg0 key="contact.errors.firstName" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>128</var-value>
</var>
</field>
</form>
</formset>
</form-validation>

If in case we use action path’s (Defined in struts config xml file) directly in form tags name attribute of validation.xml, then we should extend ValidatorActionForm
Example:
public class BankForm extends ValidatorActionForm { }

<form name="/app/submitBank">
<field property="bankName" depends="required,maxlength">
<arg0 key="bank.errors.bankName" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>128</var-value>
</var>
</field>
</form>

<form name="/app/saveBank">
<field property="bankName" depends="required,maxlength">
<arg0 key="bank.errors.bankName" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>128</var-value>
</var>
</field>
</form>

Note:
When to go for ValidatorActionForm:
One of our modules (i.e.) Request is having many screens, which means we have many action paths in struts-config for this module but the form name is same for every path (RequestForm). Each of the path which leads to a different screen with the same form bean demands a different set of validation. In this scenario we need to go for path based validation rather than form name based validation.

For form name based validation we use:
public class ContactForm extends ValidatorForm { }
In case of form name based validation all the related fields in all the paths of the same form will share the same validation procedure.
For path based validation we use:
public class BankForm extends ValidatorActionForm { }

What's the difference between ValidatorForm and ValidatorActionForm?
In addition to the two standard options for creating Form Beans, Validator provides an advanced feature for tying multiple validation definitions to one Form Bean definition. When you use validatorForm- or DynaValidatorForm-based Form Beans, Validator uses the logical name for the Form Bean from the struts-config.xml file to map the Form Bean to validation definitions in the validation.xml file. This mechanism is great in most cases, but in some scenarios, Form Beans are shared among multiple actions. One action may use all of the Form Bean's fields, and another action may use only a subset of the fields. Because validation definitions are tied to the Form Bean, the action that uses only a subset of the fields has no way of bypassing validations for the unused fields. When the Form Bean is validated, it generates error messages for the unused fields, because Validator has no way of knowing not to validate the unused fields; it simply sees them as missing or invalid.
To solve this problem, Validator provides two additional ActionForm subclasses that allow you to tie validations to actions instead of to Form Beans. That way you can specify which validations to apply to the Form Bean based on which action is using the Form Bean. For concrete Form Beans, you subclass org.apache.struts.validator.ValidatorActionForm, as follows:
public class AddressForm extends ValidatorActionForm { ... }

Struts-config.xml – setting validation ON:

<!-- When user clicks on Save button on the Request.jsp -->
<action
path="/app/saveRequest"
attribute="RequestForm"
name="RequestForm"
scope="session"
validate="true"
input="/jsp/request/jsp/Request.jsp"
type="abc.xyz.ijk.projectName.action.moduleName.SaveRequestAction">
<forward name="success" path="/jsp/request/jsp/Request.jsp" />
</action>

MessageResources.properties:
We define the properties file in the path
WEB-INF\ (or) WEB-INF\classes\resources

We can have
1. Struts provided default error messages,
2. Custom error messages,
3. Custom success messages.

Contents of the properties file includes

# Struts Validator Error Messages
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.

# -- Custom Error Messages

# -- Bank Related Error Messages
bank.errors.bankName=Bank Name
bank.errors.gciNumber=GCI Number

#---Pricing related ErrorMessages
pricing.errors.commentType = PricingCommentType

# Success Messages
benef.msg.success={0} - beneficiary is saved successfully
pricing.msg.success={0} - Pricing is saved successfully
request.msg.update.success={1} - Auto approval logic has successfully run and request status is {0}

Custom Validation:

Tutorial Link:

We go for custom validation whenever the validation goes complex or the ones that we cannot manage in validation.xml. For example to validate a field based on 2 fields and also iterating a list and comparing a field from the list of objects with one of the 2 fields, and the list of validation requirement continues to be complex. In such a case we need to handle the validation in java layer.

We have Validation-rules.xml file which comes as part of struts framework. Here we have a set of pre-defined rules. We can also add our own custom rules which can be implemented in Validation.xml.

Here is how we go about implementing custom validation

# Struts Validator routine

<validator name="double"
classname="org.apache.struts.validator.FieldChecks"
method="validateDouble"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
depends=""
msg="errors.double"/>

# Custom Validator routine

<validator name="validateRequest"
classname="abc.xyz.projectName.validator.RequestValidator"
method="validateRequest"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
msg=""
depends=""/>


Example:

Struts Mapping.

<action
path="/app/saveCoronaInfo"
attribute="BankForm"
name="BankForm"
scope="session"
validate="true"
input="/jsp/bank/jsp/CoronaInfo.jsp"
type="com.bofa.gcib.gtem.action.bank.SaveCoronaInfoAction">
<forward name="success" path="/jsp/bank/jsp/CoronaInfoCloseWindow.jsp" />
</action>

Validation.xml

<form name="/app/saveCoronaInfo">
<field property="tbuKey" depends="validateCoronaId"/>
</form>

Validator-rules.xml

<validator name="validateCoronaId"
classname="abc.xyz.projectName.validator.CommonValidator"
method="validateCoronaIdFromBank"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
depends=""
msg="">
</validator>

Now we will learn about writing custom validator class. The method name (validateCoronaIdFromBank) should be specified in the method attribute of validator tag (above in validator-rules.xml)

package abc.xyz.projectName.validator

public class CommonValidator {

public static boolean validateCoronaIdFromBank (
Object form,
ValidatorAction va,
Field field,
ActionMessages messages,
Validator validator,
HttpServletRequest request) {

try {
BankForm objBankForm =(BankForm) form;
List<CoronaBean> objCoronoList = objBankForm.getCoronaList();
Set objCoronoSet = new HashSet();

for(CoronaBean objCoronoBean: objCoronoList) {
boolean result = objCoronoSet.add(objCoronoBean.getTbuKey());
if (result == false) {
ActionMessage em = new ActionMessage("bank.errors.coronoID");
messages.add(field.getKey(),em);
return false;
}
}

}
catch(Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}
Creating custom Date validation.

Validation.xml:

<form name="/app/summaryRequestMaturityDate">

<field property="requestDetailsKey" depends="validateDates">
<arg0 key="request.errors.newMaxMaturityDate"/>
<arg1 key="request.errors.maxMaturityDate"/>
<var>
<var-name>defaultDate1</var-name>
<var-value>newMaxMaturityDateStr</var-value>
</var>
<var>
<var-name>defaultDate2</var-name>
<var-value>maxMaturityDateString</var-value>
</var>
</field>

Validator-rules.xml:

<validator name="validateDates"
classname="com.bofa.gcib.gtem.validator.RequestValidator"
method="validateDates"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator,
javax.servlet.http.HttpServletRequest"
depends=""
msg="">
</validator>

public class RequestValidator {
public static boolean validateDates (
Object form,
ValidatorAction va,
Field field,
ActionMessages messages,
Validator validator,
HttpServletRequest request) {

try {

String date1 = null;
String date2 = null;
Date utildate2=null;
Date utildate1=null;

if(field.getVarValue("defaultDate1")!=null && !(("").equals(field.getVarValue("defaultDate1")))){

date1 = field.getVarValue("defaultDate1");
utildate1= DateUtility.stringToUtilDate(ValidatorUtils.getValueAsString(form, date1));
}

Explanation:
date1 = field.getVarValue("defaultDate1");
defaultDate1 is the key and newMaxMaturityDateStr is the value specified in validation.xml. The above line of code will get the value.
ValidatorUtils.getValueAsString(form, date1)
By passing the form object, since the date1 property (newMaxMaturityDateStr) is part of the form object, the method getValueAsString() gets the real data from the form object, in this case the date is fetched and returned as a string.


Regex:

To restrict textbox values only to characters of both cases.
^[A-Za-z]*$
To restrict textbox values only to numbers, comma and dot.
^[0-9,.]*$
To restrict zero (0) in a textbox.
^[^0]*$

Validation.xml – Examples:

Case - 1: Have a textbox and user should not enter the value 0.
IF 0 THEN validation error message should be thrown.

Solution:
The field requestAbcKey is valid only when it is NOT 0. For example when user enters 0 for this textbox then a validation message should be thrown.

Validation.xml
<field property="requestAbcKey" depends="validwhen">

<arg0 key="request.errors.requestAbcKey"/>
<var>
<var-name>test</var-name>
<var-value>(requestAbcKey != 0)</var-value>
</var>

</field>

Case - 2: This particular field (importerName) is mandatory (required) only if the field tbuandtxnCode’s value is EQUAL to 2.

<field property="importerName" depends="requiredif">
<arg0 key="request.errors.importerName"/>
<var>
<var-name>field[0]</var-name>
<var-value>tbuandtxnCode</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[0]</var-name>
<var-value>2</var-value>
</var>
</field>

Instead of 2 in <var-value>2</var-value> we can also give strings like XYZ and char values like Y or N.

Case - 3: This particular field (requestAvailableKey) is mandatory (required) only if the field paymenttermsCheck’s value is EQUAL to 2 AND requestStatusKey is NOT EQUAL to 0

<field property="requestAvaiableKey" depends="requiredif">
<arg0 key="request.errors.requestAvaiableKey"/>
<var>
<var-name>field[0]</var-name>
<var-value>paymenttermsCheck</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[0]</var-name>
<var-value>2</var-value>
</var>
<var>
<var-name>field[1]</var-name>
<var-value>requestStatusKey</var-value>
</var>
<var>
<var-name>fieldTest[1]</var-name>
<var-value>NOTEQUAL</var-value>
</var>
<var>
<var-name>fieldValue[1]</var-name>
<var-value>0</var-value>
</var>
<var>
<var-name>fieldJoin</var-name>
<var-value>AND</var-value>
</var>
</field>


Case - 4: This particular field’s (otherAbc) length shouldn’t be greater than 4000 characters

<field property="otherAbc" depends="maxlength">
<arg0 key="request.errors.otherAbc"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>4000</var-value>
</var>
</field>

Case - 5: This particular field is a mandatory field.

If we say depends="required", then automatically is required. is added to the end of the error message.

Message Content:

tbu.errors.division = Division


<field property="division" depends="required">
<arg0 key="tbu.errors.division" />
</field>

Division is required.


Case - 6: In this particular field (textbox) user should enter only digits between 0 – 9 along with special characters comma and dot. If user enters anything else we need to get validation messages.


<field property="strAbcLimit" depends="mask">
<arg0 key="beneficiary.errors. strAbcLimit " />
<var>
<var-name>mask</var-name>
<var-value>^[0-9,.]*$</var-value>
</var>
</field>

Here this (^[]*$) is the standard syntax and what goes inside the square brackets forms the rule for validation.

Case - 7: This is a special case where we iterate a list which contains objects of a particular type (Class Bank) which contains few fields. Out of those fields I need to validate 2 fields.

Here systemStatusKey’s value should be equal to 3 and commentTypeKey should not be equal to 0.

<field property="commentTypeKey" indexedListProperty="tbuCommentList" depends="validwhen">
<arg0 key="tbu.errors.commentType" />
<var>
<var-name>test</var-name>
<var-value>
((tbuCommentList[].systemStatusKey == 3) or (tbuCommentList[].commentTypeKey != 0))
</var-value>
</var>
</field>

<field property="description" indexedListProperty="tbuCommentList" depends="validwhen">
<var>
<var-name>test</var-name>
<var-value>
((tbuCommentList[].description != null) or (tbuCommentList[].systemStatusKey == 3))
</var-value>
</var>
</field>



Case - 8: Mandatory check for date field. Have a textbox and an adjacent calendar icon. Date has to be mandatorily selected.

<form name="/app/summaryRequestMaturityDate">
<field property="newMaxMaturityDateStr" depends="required, date">
<arg0 key="request.errors.newMaxMaturityDate" />
<var><var-name>datePatternStrict</var-name>
<var-value>MM/dd/yyyy</var-value></var>
</field>
</form>

The date rule checks to see if the field is a valid date.

The datePatternStrict variable will ensure that 5-29-70 does not work; when the pattern MM-dd-yyyy is used, only 05-29-1970 works (notice the 0 before the 5)


Case - 9: Mandatory check for double field. Have a textbox which should accept only a int/double value and not a string.

To do a validation on double field we need to have the field as String and NOT as double.

<field property="stringDDPLmt" depends="double,maxlength">
<arg0 key="beneficiary.errors.benefDDPLmt" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>31</var-value>
</var>
</field>

Case - 10: This field is a property which is inside a List of objects and is a required field and a double field.

<field property="strFacilityLimitAmount" indexedListProperty="countryFacilityList" depends="required,double">
<arg0 key="country.errors.facilityLimitAmount" />
</field>


Case - 11: This field is a property which is inside a List of objects and we need to ensure this property contains only integer values and nothing else.

<field property="maxTenor" indexedListProperty="bankFacilityList" depends="integer" >
<arg0 key="bank.errors.maxTenor"/>
</field>

Case - 12: This field is valid only when it is not equal to null or systemstatuskey is equal to 3.

<field property="contactName" indexedListProperty="contactList" depends="validwhen">
<arg0 key="bank.errors.contactName" />
<var>
<var-name>test</var-name>
<var-value>
((contactList[].contactName != null)or(contactList[].systemStatusKey == 3))
</var-value>
</var>
</field>

<field property="countryDivisionKey" depends="validwhen">
<arg0 key="country.errors.countryDivisionKeyMap" />
<var>
<var-name>test</var-name>
<var-value>(countryDivisionKey != 0)</var-value>
</var>
</field>

Case 13:

When the user gives the gci number in a wrong format, we need to throw a validation message with the correct format.
In the below example if the user gives a number greater than 15 digits then we get the message
GCI Number cannot be greater than 15 characters.
Also if the user gives a wrong format, then we need to throw the message
GCI Number should be in the format XX-XXX-XXXX.

This is acheived through <msg> tag.

bank.errors.gciNumber=GCI Number
validation.error.phone.format={0} should be in the format XX-XXX-XXXX.

Error Message: GCI Number should be in the format XX-XXX-XXXX.

<field property="gciNumber" depends="maxlength,mask">
<arg0 key="bank.errors.gciNumber" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var><var-name>maxlength</var-name><var-value>15</var-value></var>
<msg name="mask" key="validation.error.phone.format"/>
<arg0 key="bank.errors.gciNumber"/>
<var>
<var-name>mask</var-name>
<var-value>^\d{2}[-]\d{3}[-]\d{4}$</var-value>
</var>
</field>

validation.error.phone.format={0} should be in the format XX-XXX-XXXX.
bank.errors.gciNumber=GCI Number

Why are we using <msg> in the below case. Why can't we use <arg0>.

Ans: Thats a good question. For
depends="required"
depends="validwhen"

we get a message "is required." at the end of the error message. But here we are having a custom message to be shown to the user.
Thats the reason we are using <msg> here

<field property="gtemReportingFlag" depends="validwhen">
<msg name="validwhen" key="request.errors.gtemReportingYes"/>
<var>
<var-name>test</var-name>
<var-value>(gtemReportingFlag == "Yes")</var-value>
</var>
</field>

Custom Currency Validation.

if(controlType.equals("CURRENCY")) {
try{
CurrencyValidator cv = new CurrencyValidator(true,true);
Object value = cv.validate(answer);
if(value == null) {
status2 = false;
ActionMessage em = new ActionMessage(requiredFormatMessage,false);
messages.add(field.getKey(),em);
}
else {
answer = ABCApplicationUtility.getUSFormat(((BigDecimal)value).longValue());
objQuestionnaireBean.setAnswer(answer);
}
}
catch(Exception ex) {
status2 = false;
ActionMessage em = new ActionMessage(requiredFormatMessage,false);
messages.add(field.getKey(),em);
}
}

import java.text.NumberFormat;

public static final NumberFormat usFormat = NumberFormat.getInstance(Locale.US);

public static String getUSFormat(Object obj) {
if(obj !=null ) {
return usFormat.format(obj);
}
return null;
}

Custom Date validation – Throwing error message.

Validation.xml

<field property="requestDetailsKey" depends="validateDates">
<arg0 key="request.errors.lcExpDate"/>
<arg1 key="request.errors.latestShipDate"/>
<var>
<var-name>defaultDate1</var-name>
<var-value>lcExpDateString</var-value>
</var>
<var>
<var-name>defaultDate2</var-name>
<var-value>latestShipDateString</var-value>
</var>
</field>

Custom Validation Class:

public static boolean validateDates (
Object form,
ValidatorAction va,
Field field,
ActionMessages messages,
Validator validator,
HttpServletRequest request) {
try {
String date1 = null;
String date2 = null;
Date utildate2=null;
Date utildate1=null;

if(field.getVarValue("defaultDate1")!=null && !(("").equals(field.getVarValue("defaultDate1")))){
date1 = field.getVarValue("defaultDate1");
utildate1= DateUtility.stringToUtilDate(ValidatorUtils.getValueAsString(form, date1));
}

if(field.getVarValue("defaultDate2")!=null && !(("").equals(field.getVarValue("defaultDate2")))){
date2 = field.getVarValue("defaultDate2");
utildate2= DateUtility.stringToUtilDate(ValidatorUtils.getValueAsString(form, date2));
}

if(utildate1.before(utildate2))
{
ActionMessage em = new ActionMessage("errors.compareDates",Resources.getMessage(request,field.getArg(0).getKey()),Resources.getMessage(request,field.getArg(1).getKey()));
messages.add(field.getKey(),em);
return false;
}

MessageResources.properties

errors.compareDates={0} can not be less than {1}

As you can see we have two inputs [ {0} and {1} ] which are to be replaced with values from ActionMessage class.

Resources.getMessage(request,field.getArg(0).getKey())

The above line will fetch request.errors.lcExpDate from validation.xml and will replace the [{0}] in the error message which will be shown to the user.

Excerpt from Validation.xml

<arg0 key="request.errors.lcExpDate"/>
<arg1 key="request.errors.latestShipDate"/>