16 Using Validation in the ADF Model Layer

This chapter explains how to create validation rules in the ADF model layer of your Oracle Application Development Framework (Oracle ADF) application so that data enter in the user interface is validated in the page instead of the business service layer.

This chapter contains the following sections:

16.1 About ADF Model Layer Validation

In the model layer, ADF Model validation rules can be set for a binding's attribute on a particular page. When a user edits or enters data in a field and submits the form, the bound data is validated against any set rules and conditions. If validation fails, the application displays an error message.

Note that you don't need to add additional ADF Model validation if you have already set validation rules in the business domain layer of your entity objects. In an ADF Business Components-based Fusion web application, you won't need to use ADF Model validation unless you use data controls other than your application module data controls.

16.1.1 ADF Model Layer Validation Use Cases and Examples

If your application uses data controls that are not based on ADF Business Components, you can use ADF Model layer validation to ensure the quality of user-entered data.

Best Practice:

Use business layer validation whenever possible. However, the following are examples of when you might need to use model layer validation:

  • When your business layer does not support declarative validation.

  • When you want to validate before an expensive roundtrip begins (for example, for a binding to a web service).

  • When you need to validate a form created using parameters (for example, using the executeWithParams operation).

You can also use client-side validation for cases where you want to validate before a roundtrip to the server. For more information, see the "Adding Validation" section in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

Many of the declarative validation features available for ADF Business Components objects are also available at the model layer, should your application warrant the use of model-layer validation in addition to business-layer validation.

16.1.2 Additional Functionality for ADF Model Layer Validation

You may find it helpful to understand other ADF validation features before you use model layer validation. Following are links to other functionality that may be of interest.

  • When you use the ADF Business Components application module data control, you do not need to use model-layer validation. Consider defining all or most of your validation rules in the centralized, reusable, and easier to maintain entity objects of your business layer. For more information, see Chapter 7, "Defining Validation and Business Rules Declaratively."

  • Many of the declarative validation features available at the page level are also available at the bean level, which you would implement on the data control structure file. This can be very useful, because validation rules on the data control structure file apply to all usages of the data control. For information about implementing validation rules on the data control structure file, see the "Adding Business Logic to Data Controls" chapter in the Oracle Fusion Middleware Java EE Developer's Guide for Oracle Application Development Framework.

16.2 Defining Validation Rules in the ADF Model Layer

You can configure ADF Model validation for a binding's attributes on the page definition file. Validation rules in the model layer are executed for a binding's attribute on a particular page when the containing form is submitted.

You can optionally set the skipValidation property to true to bypass the ADF Model validation. You can set skipValidation to skipDataControls to validate the bound objects without validating the transaction. For example, set skipValidation to skipDataControls if you have a table action that opens a popup window to accept data entries and you want to allow the view layer to validate those entries before the commit on the table. The skipValidation property can be found in the Property Inspector after you have selected the root node of the page definition file in the Structure window.

16.2.1 How to Add Validation

You set ADF Model validation on the page definition file. You define the validation rule, and set an error message to display when the rule is broken.

Table 16-1 describes the ADF Model validation rules that you can configure for a binding's attributes.

Table 16-1 ADF Model Validation Rules

Validator Rule Name Description

Compare

Compares the attribute's value with a literal value

List

Validates whether or not the value is in a list of values

Range

Validates whether or not the value is within a range of values

Length

Validates the value's character or byte size against a size and operand (such as greater than or equal to)

Regular Expression

Validates the data using Java regular expression syntax

Required

Validates whether or not a value exists for the attribute


Before you begin:

It may be helpful to have an understanding of the use of validation rules in the model layer. For more information, see Section 16.2, "Defining Validation Rules in the ADF Model Layer."

You may also find it helpful to understand additional functionality that can be added using other validation features. For more information, see Section 16.1.2, "Additional Functionality for ADF Model Layer Validation."

You will need to complete this task:

  • Create a component on the page. The component must have binding attributes.

To create an ADF Model validation rule:

  1. Open the page definition that contains the binding for which you want to create a rule.

  2. In the Structure window, select the attribute, list, or table binding.

  3. In the Property Inspector, select More and then Edit Validation Rule.

  4. In the Edit Validation Rules dialog, expand the binding node, select the attribute name, and click New.

  5. In the Add Validation Rule dialog, select a validation rule and configure the rule as needed.

  6. Select the Failure Handling tab and configure the message to display when the rule is broken.

16.2.2 What Happens at Runtime: Model Validation Rules

When a user submits data, as long as the submitted value is a non-null value or a string value of at least one character, then all validators on a component are called one at a time. Because the f:validator tag on the component is bound to the validator property on the binding, any validation routines set on the model are accessed and executed.

The process then continues to the next component. If all validations are successful, the Update Model Values phase starts and a local value is used to update the model. If any validation fails, the current page is redisplayed along with an error message.

16.3 Customizing Error Handling

You can report errors using a custom error handler that extends the default DCErrorHandlerImpl class. You are not required to write any code to register your custom exception handler class. Instead, you select the root node of the DataBindings.cpx file in the Structure window, and then use the Property Inspector to set the ErrorHandlerClass property to the fully qualified name of the error handler you want it to use.

Your custom error handler can contain the following overridable methods:

  • reportException(): Called to report any exception that occurs. It can be overridden to analyze reported exceptions.

  • getDisplayMessage(): Returns the message that will be reported to JSF for each error that occurs. Returning null is the way your custom error handler signals that a given exception should not be reported to the client.

  • getDetailedDisplayMessage(): Returns the detail portion of the message as a String object or HTML that will be reported to JSF for each error that occurs. Returning null is the way your custom error handler signals that a given exception should not be reported to the client.

  • skipException(): Returns a boolean depending on whether you want to display each item from the nested exception in the final error list displayed to the user. This method override lets you implement logic to check for specifics exception types and, based on the business scenario, determine whether to display it in the list.

Example 16-1 illustrates a custom error handler that extends the DCErrorHandlerImpl class and shows the override for the skipException() method that is needed to skip exceptions that should not appear in the list displayed to the user.

Example 16-1 Custom Error Handler

package view.controller.fwkext;

import java.sql.SQLIntegrityConstraintViolationException;

import java.util.ArrayList;
import java.util.List;

import oracle.adf.model.binding.DCBindingContainer; 
import oracle.adf.model.binding.DCErrorHandlerImpl;

import oracle.jbo.CSMessageBundle; 
import oracle.jbo.DMLConstraintException; 
import oracle.jbo.JboException;

public class CustomErrorHandler extends DCErrorHandlerImpl {

   List<ExceptionMapper> exceptionMapperList = new ArrayList<ExceptionMapper>();
   public CustomErrorHandler() {
     this(true);
   }

   public CustomErrorHandler(boolean setToThrow) {
     super(setToThrow); 
     exceptionMapperList.add(new DisableJboExceptionCodesMapper());
   }

   public void reportException(DCBindingContainer bc, Exception ex) { 
     for (ExceptionMapper mapper : exceptionMapperList) {
       if (mapper.canMapException(ex)) { 
         ex = mapper.mapException(ex);
       } 
     }
     super.reportException(bc, ex);
   }

   /**
    * If an exception is a RowValException or a TxnValException and they
    * have nested exceptions, then do not display it. This example shows
    * an implementation that skips the SQLIntegrityConstraintViolationException
    * from displaying in the error final list displayed to the user.
    */
   @Override
   protected boolean skipException(Exception ex) {

      if (ex instanceof DMLConstraintException) {
            return false;
        } else if (ex instanceof SQLIntegrityConstraintViolationException) {
            return true;
        }
        return super.skipException(ex);
    }

}

You must change the constructor to MyErrorHandler(). The exception error handler must have a default constructor, as shown in Example 16-2.

Example 16-2 Default Constructor

ErrorHandlerClass="viewcontroller.MyErrorHandler" public MyErrorHandler() {   super(true); }

16.3.1 How to Customize the Detail Portion of a Message

If you plan to customize and use the detail portion of a message, you can create a custom error handler and implement the getDetailedDisplayMessage method to retrieve and process that message. The finalized message will be passed to the view layer to be integrated with other messages.

To customize the detail portion of a message:

  1. Create a custom error handler class that extends the default DCErrorHandlerImpl class.

  2. In that class, override the getDetailedDisplayMessage method that returns a DCErrorMessage object.

    Example 16-3 shows an implementation of the getDetailedDisplayMessage method in the custom error handler class.

    Example 16-3 Custom Error Handler Class with getDetailDisplayMessage Method

    public final class MyErrorMessageHandler extends DCErrorHandlerImpl {
        public MyErrorMessageHandler (){
            super(false);
        }
        public DCErrorMessage getDetailedDisplayMessage(BindingContext ctx,
                                                        RegionBinding ctr,
                                                        Exception ex) {
            ...
            return new MyDCErrorMesssage(ctr, ex);
        }
    }
    
  3. Create a custom class that implements the DCErrorMessage interface. The class must implement the getHTMLText method and the getText method.

    You will add code to the getHTMLText method to perform the actual processing, but you must also implement getText to satisfy the interface requirements.

  4. In the getHTMLText implementation, add code to create and process the error message.

    getHTMLText of getDetailedDisplayMessage should return the finalized version of the error message as an HTML fragment that will be inserted into the HTML code of the page. For this reason, you should perform all necessary preprocessing on the text message before the message is returned by getDetailedDisplayMessage. For instance, you may want to retrieve the localized version of the message or change the right-to-left ordering of the message before it is returned.

    Example 16-4 shows an implementation of this interface.

    Example 16-4 Implementing the DCErrorMessage Interface

    public final class MyDCErrorMesssage implements DCErrorMessage {
        RegionBinding m_regionBinding;
        Exception m_ex;
           public MyDCErrorMesssage(RegionBinding ctr, Exception ex) {
            super();
            this.m_regionBinding = ctr;
            this.m_ex = ex;
        }
        public String getText() {
            ...
            return "Message String";
        }
        public String getHTMLText() {
            ...
            /* Add code to process the message, including localization */
            /* and right-to-left directional requirements. */
            /* Return the message as the finalized HTML fragment.*/
            return "<b>error</b> message details";
        }
    }
    

16.3.2 How to Write an Error Handler to Deal with Multiple Threads

Oracle ADF constructs an instance of the custom error handler for each BindingContext object that is created. Because Oracle ADF serializes simultaneous web requests from the same logical end-user session, multiple threads generally will not use the same error handler at the same time. However, to guarantee a thread-safe custom error handler, use the setProperty() API on JboException. This method stores in the exception objects themselves any hints you might need later during the phase when exceptions are translated to JSF FacesMessage objects for display.