Implementing Data Validation in ADF UIX application

Validation of business rules, of data oriented business logic, is one of my favorite recurring challenges. Around these rules, there are
always interesting discussions about how and especially where to implement the rules. From a robustness perspective, database
implementation is prefferable. From an end-user usability point of view, client side implementation should be provided – as well, in order
not to lose the robustness. Implementation of business logic in the -middle tier – Model, the tier in the middle between client side an
database, is heavily debated. Some validation is implicit, given the conversion from untyped String based Web-parameters to strong-typed Model parameters. Whether more complex business rules should be implemented in the middle tier, in the Model, depends on who you ask. It will slightly enhance performance and reduce the load on the database. In ADF Business Components it is fairly easy to implement, so let’s go for it. At least we will keep our database independence in tact. (tongue in cheek joke).

In this article we will discuss the ways we can use to trigger validation of business rules from UIX web-clients. The implementation of the business logic itself can still be done in several ways: server based (inside the database), in the Model – in our case ADF Business Components -, in the Webtier using Struts Validator or ADF Action validation-logic or in the Client itself.

  • UIX Client Side Validation
  • UIX triggered Model based Validation

UIX Client Side Validation

UIX provides us with some hooks for Client Side validators. The validator hooks we have are somewhat sober. However, UIX elements also have onBlur and onChange events linked with them. These can be used to invoke custom pieces of JavaScript that can be inserted into the UIX and in which we can add our own validation logic. See here (Oracle ADF UIX Developer’s Guide – Handling Errors) for an overview of UIX Client Side Validation Logic

The standard validators are:

  • Required – using the required attribute on the UIX elements
  • Decimal validation – A very common type of input data is a numeric field; the ><decimal> element support this behavior
  • Date validation – A second common type of input data is a date field;
  • Regular expressions – UIX also supports use of regular expressions for validation with the <regExp> element; it >supports the
    syntax for Regular Expressions used by Javascript.

 

Example:

  <messageTextInput prompt="Any number:" name="number">
    <onSubmitValidater>
       <decimal/>
     </onSubmitValidater>
   </messageTextInput>

 

The <decimal> element is simple enough – it doesn’t support any attributes. What’s of much more interest here is the <onSubmitValidater> element that wraps it.
This element defines what type of validator is used. There’s only two types: <onSubmitValidater> and <onBlurValidater>.  An “on-submit” validater executes when the user has completed the form
and hits a “submit” button, while an “on-blur” validater executes as soon as the user leaves the field.

  <messageTextInput prompt="Any number:" name="number">
     <onBlurValidater>
       <decimal/>
     </onBlurValidater>
   </messageTextInput>

In general, stick to on-submit validation unless you have a very specific reason. Forcing users to enter a correct value before they
can enter any other can be extremely irritating.

In our demo application, the result of this onBlur alidator:

      <messageTextInput id="${bindings.SalesteamEname.path}" model="${bindings.SalesteamEname}" promptAndAccessKey="&amp;Ename" rows="1" maximumLength="10" columns="10">
        <onBlurValidater><regExp pattern="^[A-P]{1,9}"/> </onBlurValidater>
      </messageTextInput>

is that whenever you leave the Ename field, UIX will validate that the ename value consists of up to 9 characters, all from the set A through P. Q through Z are NOT allowed. The message presented to the end user looks as follows:

Implementing Data Validation in ADF UIX application

OnSubmit validators are triggered when you submit the form. Note that an element can have onBlur and onSubmit validators:

      <messageTextInput id="${bindings.SalesteamSal.path}" model="${bindings.SalesteamSal}" promptAndAccessKey="&amp;Sal" rows="1" maximumLength="9" columns="7">
         <onBlurValidater>
           <regExp pattern="^[1-8]{3,9}"/>
         </onBlurValidater>
         <onSubmitValidater>
            <decimal/>
         </onSubmitValidater>
      </messageTextInput>
      <messageTextInput id="${bindings.SalesteamComm.path}" model="${bindings.SalesteamComm}" required="yes" promptAndAccessKey="&amp;Commission" rows="1" maximumLength="9" columns="7">
         <onSubmitValidater>
            <decimal/>
         </onSubmitValidater>
      </messageTextInput>

Multiple messages can be combined to present the end user with an overview of all his shortcomings:

Implementing Data Validation in ADF UIX application

 

The
limitations of these standard, client side UIX validators are obvious: the error messages are fixed, the mechanism for presenting the warnings is less than elegant – JavaScript alerts instead of for example the messageBox – and the validations can only refer to a single field! So while we can implement attribute level business rules, UIX Client SideValidators do not support tuple level rules or come even close to inter-record validations.

The ability to invoke server side validations in an asynchronous manner is therefore very appealing – as it provides more powerful validations, using the model validation that is implemented anyway, elegant messages and still timely feedback.

However, we still have another client side trick up our sleeves: using the onBlur and onChange attributes available for each UIX element. Using these attributes, we can have pieces of JavaScripts triggered when the events
occur. For example:

 

      <messageTextInput onBlur="if (this.value >6000) {alert('Salary should not be higher than 6000');return false;}"  id="${bindings.SalesteamSal.path}" model="${bindings.SalesteamSal}" promptAndAccessKey="&amp;Sal" rows="1" maximumLength="9" columns="7">

In theory, we can refer to other fields in the form in order to implement tuple-rules: logic that compares the values of two or more fields. However, finding the correct name can be somewhat tricky, as that name is largely composed by the UIX rendering engine at runtime, as you can see from the Page Source in the Browser when running a UIX powered webapplication.
Let’s try to impose the rule that the Commission should not exceed 50% of the Salary:

<messageTextInput id="${bindings.SalesteamComm.path}" onBlur="if (this.value > 0.5*document.getElementById(this.id.replace('Comm','Sal')).value ) {alert('Commission may not be more than 50% of the Salary!');return false;}" required="yes" promptAndAccessKey="&amp;Commission" rows="1" maximumLength="9" columns="7">
   <onSubmitValidater>
     <decimal/>
   </onSubmitValidater>
</messageTextInput>

When the user leaves the Commission item, the onBlur event is fired and the validation is done, possibly resulting in the following error:

 Implementing Data Validation in ADF UIX application

Note the slightly contrived way of finding the value of the Salary item. The good thing about this syntax is that it will stand up against changes in the structure of the UIX page, and even works in a multi-record layout.

      <contents>
         <messageTextInput id="${ui:concat('Salesmen1:Comm:',uix.current.tableIndex)}" 
                           onBlur="if (this.value > 0.5*document.getElementById(this.id.replace('Comm','Sal')).value ) 
                                   {alert('Commission may not be more than 50% of the Salary!');return false;}" 
                           model="${ui:cond(uix.current.isNewRow,null,uix.current.SalesteamComm)}" text="${uix.current.SalesteamComm}" name="Comm" promptAndAccessKey="&amp;Commission" rows="1" maximumLength="9" columns="7">
            <onSubmitValidater>
               <decimal/>
            </onSubmitValidater>
         </messageTextInput>
      </contents>

Resulting in the same error message:
Implementing Data Validation in ADF UIX application

UIX triggered Model based Validation

UIX
provides what is called primaryClientActions. Basically these give us hooks to specify that an AJAX-style asynchronous background request is made. This request can (and usually will) submit the form with all the user provided values, update the Bindings and underlying Model and return the resulting model/binding values to the client. With each Primary Client Action, we can specify which ‘targets’ there are; targets are HTML Form elements – or containers with multiple elements – that should be refreshed based on the response from the primaryClient-request.

In an earlier article, AJAX with UIX – PrimaryClientAction for instantaneous server-based client refresh 
I have discussed the use of the primaryClientAction mechanism to invoke derivations. They can just as easly be used to trigger validations, as wel will see in this article..

We use a classic example in this article: Employee-management in our EMP/DEPT based Human Resource Application:

Implementing Data Validation in ADF UIX application baseHRM

Underneath this simple application we have an ADF Business Components Model with Entity Objects Employee and Department on base tables EMP and DEPT. We will embark on the implementation of two very simple business rules:

  1. The Salary should not be lower than the Commission
  2. The Commission, if it exists, should be higher than 250 – otherwise do not bother

We will use two mechanisms in ADF BC to implement these rules. First we will create a Validation on the Employee Entity Object, a Comparator that states that Salary should be larger than Commission:

Implementing Data Validation in ADF UIX application HrmValidationOne

The second mechanism is far simpler: we have the ADF BC wizard generate the ViewObjectRowImpl class for the Employees ViewObject. Then we implement a little validation code in the setComm method:

  public void setComm(Number value) {
    if (value.intValue() < 400 && value.intValue() > 0) {
    
      throw new JboException("Commission should be more than that!","44044", null);
    }
    setAttributeInternal(COMM, value);
  }

Now when we Save the changes in our page, the ADF DataAction class will update the DataControlBindings and thereby update the Model. At that point, the Model validation is triggered. Any violations result in Exceptions and eventually error messages being added to the message stack. As a result, we may see these errors:

Implementing Data Validation in ADF UIX application HrmValidationErrors

However, it is somewhat disappointing for the end user to work his or her way through all the items on the page, save them and only then be informed of the fact that one of first changes made was in fact an incorrect one. Of course, with the HRM application, it is not an enormous problem, but I hope you get my drift. So it would be more helpful if the warning messages are displayed as soon as the application has the impression that the end user is perhaps violating a rule. However, the user should be hindered by this validation. He should be able to continue working while communication with the server takes place in the background. And that is of course where the primaryClientActions come in. These allow for asynchronous – i.e. Non-Blocking – interaction between Client (Browser) and Server. We can easily set up a primaryClientAction for the Comm item in our ADF UIX page. We add a primaryClient child element to the Comm messageTextInput:

<primaryClientAction>
  <firePartialAction event="onChangeCommission" formSubmitted="true" targets="messageBox"/>
</primaryClientAction>

This signifies that when the Comm value is changed, a background request should be send to the server. It must be processed, the results – the updated Model values – are returned and used to update all elements specified in the list of targets – or inside the elements
listed in the targets. In this case, only the element with ID=messageBox is specified. This element is the area that appears when warning, informative or errormessages are to be displayed. The result of this specification is that when the Commission has changed and the user tabs out of the Comm item, the client-server interaction is performed – without interference with what the user is doing – and when this exchange results in an error message, this will be displayed in the messageBox. Note: this is a DHTML operation, a DOM update that will
alter just a small section of the screen; no full blown page-refresh is done.

Implementing Data Validation in ADF UIX application

 

One Response

  1. satish asnani March 31, 2006