7 Defining Validation and Business Rules Declaratively

This chapter explains how to use ADF entity object events and features to programmatically implement the most common kinds of business rules in an Oracle Application Development Framework (Oracle ADF) application. It also describes how to invoke custom validation code, for example, using setter methods to populate entity rows.

This chapter includes the following sections:

7.1 About Declarative Validation

The easiest way to create and manage validation rules is through declarative validation rules. Declarative validation rules are defined using the overview editor, and once created, are stored in the entity object's XML file. Declarative validation is different from programmatic validation (covered in Chapter 8, "Implementing Validation and Business Rules Programmatically"), which is stored in an entity object's Java file.

Oracle ADF provides built-in declarative validation rules that satisfy many of your business needs. If you have custom validation rules you want to reuse, you can code them and add them to the IDE, so that the rules are available directly from JDeveloper. Custom validation rules are an advanced topic and covered in Section 8.14, "Implementing Custom Validation Rules." You can also base validation on a Groovy expression, as described in Section 7.5, "Using Groovy Expressions For Validation and Business Rules."

When you add a validation rule, you supply an appropriate error message and can later translate it easily into other languages if needed. You can also define how validation is triggered and set the severity level.

7.1.1 Declarative Validation Use Cases and Examples

In an ADF Business Components application, most of your validation code is defined in your entity objects. Encapsulating the business logic in these shared, reusable components ensures that your business information is validated consistently in every view object or client that accesses it, and it simplifies maintenance by centralizing where the validation is stored.

Another benefit of using declarative validation (versus writing your own validation) is that the validation framework takes care of the complexities of batching validation exceptions, which frees you to concentrate on your application's specific validation rule logic.

In the model layer, ADF Model validation rules can be set for the attributes of a collection. Many of the declarative validation features available for entity objects are also available at the model layer, should your application warrant the use of model-layer validation in addition to business-layer validation. For more information, see Chapter 16, "Using Validation in the ADF Model Layer."

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. With other types of data controls, model-layer validation can be more useful.

7.1.2 Additional Functionality for Declarative Validation

You may find it helpful to understand other ADF features before you start using declarative validation. It is possible to go beyond the declarative behavior to implement more complex validation rules for your business domain layer when needed. Following are links to other functionality that may be of interest.

7.2 Understanding the Validation Cycle

Each entity row tracks whether or not its data is valid. When an existing entity row is retrieved from the database, the entity is assumed to be valid. When the first persistent attribute of an existing entity row is modified, or when a new entity row is created, the entity is marked invalid.

When an entity is in an invalid state, the declarative validation you have configured and the programmatic validation rules you have implemented are evaluated again before the entity can be considered valid again. You can determine whether a given entity row is valid at runtime by calling the isValid() method on it.

Note:

Because attributes can (by default) be left blank, validations are not triggered if the attribute contains no value. For example, if a user creates a new entity row and does not enter a value for a given attribute, the validation on that attribute is not run. To force the validation to execute in this situation, set the Mandatory flag on the attribute.

7.2.1 Types of Entity Object Validation Rules

Entity object validation rules fall into two basic categories: attribute-level and entity-level.

7.2.1.1 Attribute-Level Validation Rules

Attribute-level validation rules are triggered for a particular entity object attribute when either the end user or the program code attempts to modify the attribute's value. Since you cannot determine the order in which attributes will be set, attribute-level validation rules should be used only when the success or failure of the rule depends exclusively on the candidate value of that single attribute.

The following examples are attribute-level validations:

  • The value of the OrderDate of an order should not be a date in the past.

  • The ProductId attribute of a product should represent an existing product.

7.2.1.2 Entity-Level Validation Rules

All other kinds of validation rules are entity-level validation rules. These are rules whose implementation requires considering two or more entity attributes, or possibly composed children entity rows, in order to determine the success or failure of the rule.

The following examples are entity-level validations:

  • The value of the OrderShippedDate should be a date that comes after the OrderDate.

  • The ProductId attribute of an order should represent an existing product.

Entity-level validation rules are triggered by calling the validate() method on a Row. This occurs when:

  • You call the method explicitly on the entity object

  • You call the method explicitly on a view row with an entity row part that is invalid

  • A view object's iterator calls the method on the current row in the view object before allowing the current row to change

  • During transaction commit, processing validates an invalid entity (in the list of pending changes) before proceeding with posting the changes to the database

As part of transaction commit processing, entity-level validation rules can fire multiple times (up to a specified limit). For more information, see Section 7.2.4, "Avoiding Infinite Validation Cycles."

7.2.2 Understanding Commit Processing and Validation

Transaction commit processing happens in three basic phases:

  1. Ensure that any invalid entity rows on the pending changes list are valid.

  2. Post the pending changes to the database by performing appropriate DML operations.

  3. Commit the transaction.

If you have business validation logic in your entity objects that executes queries or stored procedures that depend on seeing the posted changes in the SELECT statements they execute, they should be coded in the beforeCommit() method described in Section 8.5.3, "What You May Need to Know About Row Set Access with View Accessors." This method fires after all DML statements have been applied so queries or stored procedures invoked from that method can "see" all of the pending changes that have been saved, but not yet committed.

Caution:

don't use the transaction-level postChanges() method in web applications unless you can guarantee that the transaction will definitely be committed or rolled-back during the same HTTP request. This method exists to force the transaction to post unvalidated changes without committing them. Failure to heed this advice can lead to strange results in an environment where both application modules and database connections can be pooled and shared serially by multiple different clients.

7.2.3 Understanding the Impact of Composition on Validation Order

Because a composed child entity row is considered an integral part of its composing parent entity object, any change to composed child entity rows causes the parent entity to be marked invalid. For example, if a line item on an order were to change, the entire order would now be considered to be changed, or invalid.

Therefore, when the composing entity is validated, it causes any currently invalid composed children entities to be validated first. This behavior is recursive, drilling into deeper levels of invalid composed children if they exist.

7.2.4 Avoiding Infinite Validation Cycles

If your validation rules contain code that updates attributes of the current entity or other entities, then the act of validating the entity can cause that or other entities to become invalid. As part of the transaction commit processing phase that attempts to validate all invalid entities in the pending changes list, the transaction performs multiple passes (up to a specified limit) on the pending changes list in an attempt to reach a state where all pending entity rows are valid.

The maximum number of validation passes is specified by the transaction-level validation threshold setting. The default value of this setting is 10. You can increase the threshold count to greater than one if the entities involved contain the appropriate logic to validate themselves in the subsequent passes.

If after 10 passes, there are still invalid entities in the list, you will see the following exception:

JBO-28200: Validation threshold limit reached. Invalid Entities still in cache

This is a sign that you need to debug your validation rule code to avoid inadvertently invalidating entities in a cyclic fashion.

To change the validation threshold, use the SetValidationThreshold() method as shown in Example 7-1. In this example, the new threshold is 12.

Example 7-1 Changing the Validation Threshold

oracle.jbo.server.DBTransaction::setValidationThreshold(12)

7.2.5 What Happens When Validations Fail

When an entity object's validation rules throw exceptions, the exceptions are bundled and returned to the client. If the validation failures are thrown by methods you've overridden to handle events during the transaction postChanges processing, then the validation failures cause the transaction to roll back any database INSERT, UPDATE, or DELETE statements that might have been performed already during the current postChanges cycle.

Note:

The bundling of exceptions is the default behavior for ADF Model-based web applications, but not for Oracle ADF Model Tester or Swing bindings. Additional configuration is required to bundle exceptions for the Oracle ADF Model Tester or Swing clients.

7.2.6 Understanding Entity Objects Row States

When an entity row is in memory, it has an entity state that reflects the logical state of the row. Figure 7-1 illustrates the different entity row states and how an entity row can transition from one state to another. When an entity row is first created, its status is New. You can use the setNewRowState() method to mark the entity as being Initialized, which removes it from the transaction's list of pending changes until the user sets at least one of its attributes, at which time it returns to the New state. This allows you to create more than one initialized row and post only those that the user modifies.

The Unmodified state reflects an entity that has been retrieved from the database and has not yet been modified. It is also the state that a New or Modified entity transitions to after the transaction successfully commits. During the transaction in which it is pending to be deleted, an Unmodified entity row transitions to the Deleted state. Finally, if a row that was New and then was removed before the transaction commits, or Unmodified and then successfully deleted, the row transitions to the Dead state.

Figure 7-1 Diagram of Entity Row States and Transitions

Image of diagram of entity row states and transitions

You can use the getEntityState() and getPostState() methods to access the current state of an entity row in your business logic code. The getEntityState() method returns the current state of an entity row with regard to the transaction, while the getPostState() method returns the current state of an entity row with regard to the database after using the postChanges() method to post pending changes without committing the transaction.

For example, if you start with a new row, both getEntityState() and getPostState() return STATUS_NEW. Then when you post the row (before commit or rollback), the row will have an entity state of STATUS_NEW and a post state of STATUS_UNMODIFIED. If you subsequently remove that row, the entity state will remain STATUS_NEW because for the transaction the row is still new. But the post state will be STATUS_DEAD.

7.2.7 Understanding Bundled Exception Mode

An application module provides a feature called bundled exception mode which allows web applications to easily present a maximal set of failed validation exceptions to the end user, instead of presenting only the first error that gets raised. By default, the ADF Business Components application module pool enables bundled exception mode for web applications.

You typically will not need to change this default setting. However it is important to understand that it is enabled by default since it effects how validation exceptions are thrown. Since the Java language and runtime only support throwing a single exception object, the way that bundled validation exceptions are implemented is by wrapping a set of exceptions as details of a new "parent" exception that contains them. For example, if multiple attributes in a single entity object fail attribute-level validation, then these multiple ValidationException objects will be wrapped in a RowValException. This wrapping exception contains the row key of the row that has failed validation. At transaction commit time, if multiple rows do not successfully pass the validation performed during commit, then all of the RowValException objects will get wrapped in an enclosing TxnValException object.

When writing custom error processing code, you can use the getDetails() method of the JboException base exception class to recursively process the bundled exceptions contained inside it.

Note:

All the exception classes mentioned here are in the oracle.jbo package.

7.3 Adding Validation Rules to Entity Objects and Attributes

The process for adding a validation rule to an entity object is similar for most of the validation rules, and is done using the Add Validation Rule dialog. You can open this dialog from the overview editor by clicking the Add icon on the Business Rules page.

It is important to note that when you define a rule declaratively using the Add Validation Rule dialog, the rule definition you provide specifies the valid condition for the attribute or entity object. At runtime, the entry provided by the user is evaluated against the rule definition and an error or warning is raised if the entry fails to satisfy the specified criteria. For example, if you specify a Length validator on an attribute that requires it to be Less Than or Equal To 12, the validation fails if the entry is more than 12 characters, and the error or warning is raised.

7.3.1 How to Add a Validation Rule to an Entity or Attribute

To add a declarative validation rule to an entity object, use the Business Rules page of the overview editor.

Before you begin:

It may be helpful to have an understanding of the use of validation rules in entity objects and attributes. For more information, see Section 7.3, "Adding Validation Rules to Entity Objects and Attributes."

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

To add a validation rule:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select the object for which you want to add a validation rule, and then click the Add icon.

    • To add a validation rule at the entity object level, select Entity.

    • To add a validation rule for an attribute, expand Attributes and select the desired attribute.

    When you add a new validation rule, the Add Validation Rule dialog appears.

  3. From the Rule Type dropdown list, select the desired type of validation rule.

  4. Use the dialog settings to configure the new rule.

    The controls will change depending on the kind of validation rule you select.

    For more information about the different validation rules, see Section 7.4, "Using the Built-in Declarative Validation Rules."

  5. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see Section 7.6, "Triggering Validation Execution."

    Note:

    For Key Exists and Method entity validators, you can also use the Validation Execution tab to specify the validation level.

  6. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails.

    For more information, see Section 7.7, "Creating Validation Error Messages."

  7. Click OK.

7.3.2 How to View and Edit a Validation Rule on an Entity Object or Attribute

The Business Rules page of the overview editor for entity objects displays the validation rules for an entity and its attributes in a tree control. To see the validation rules that apply to the entity as a whole, expand in the Entity node. To see the validation rules that apply to an attribute, expand the Attributes node and then expand the attribute.

The validation rules that are shown on the Business Rules page of the overview editor include those that you have defined as well as database constraints, such as mandatory or precision. To open a validation rule for editing, double-click the rule or select the rule and click the Edit icon.

7.3.3 What Happens When You Add a Validation Rule

When you add a validation rule to an entity object, JDeveloper updates its XML component definition to include an entry describing what rule you've used and what rule properties you've entered. For example, if you add a range validation rule to the DiscountAmount attribute, this results in a RangeValidationBean entry in the XML file, as shown in Example 7-2.

Example 7-2 Range Validation Bean

  <Attribute
    Name="DiscountAmount"
    IsNotNull="true"
    ColumnName="DISCOUNT_AMOUNT"
    . . . 
    <validation:RangeValidationBean
      xmlns="http://xmlns.oracle.com/adfm/validation"
      Name="DiscountAmount_Rule_0"
      ResId="DiscountAmount_RangeError_0"
      OnAttribute="DiscountAmount"
      OperandType="LITERAL"
      Inverse="false"
      MinValue="0"
      MaxValue="40"/>
    . . . 
  </Attribute>

At runtime, the rule is enforced by the entity object based on this declarative information.

7.3.4 What You May Need to Know About Entity and Attribute Validation Rules

Declarative validation enforces both entity-level and attribute-level validation, depending on where you place the rules. Entity-level validation rules are enforced when a user tries to commit pending changes or navigates between rows. Attribute-level validation rules are enforced when the user changes the value of the related attribute.

The Unique Key validator (described in Section 7.4.1, "How to Ensure That Key Values Are Unique") can be used only at the entity level. Internally the Unique Key validator behaves like an attribute-level validator. This means that users see the validation error when they tab out of the key attribute for the key that the validator is validating. This is done because the internal cache of entities can never contain a duplicate, so it is not allowed for an attribute value to be set that would violate that. This check needs to be performed when the attribute value is being set because the cache consistency check is done during the setting of the attribute value.

Best Practice:

If the validity of one attribute is dependent on one or more other attributes, enforce this rule using entity validation, not attribute validation. Examples of when you would want to do this include the following:

  • You have a Compare validator that compares one attribute to another.

  • You have an attribute with an expression validator that examines the value in another attribute to control branching in the expression to validate the attribute differently depending on the value in this other attribute.

  • You make use of conditional execution, and your precondition expression involves an attribute other than the one that you are validating.

Entity object validators are triggered whenever the entity, as a whole, is dirty. To improve performance, you can indicate which attributes play a role in your rule and thus the rule should be triggered only if one or more of these attributes are dirty. For more information on triggering attributes, see, Section 7.6, "Triggering Validation Execution."

7.4 Using the Built-in Declarative Validation Rules

The built-in declarative validation rules can satisfy many, if not all, of your business needs. These rules are easy to implement because you don't write any code. You use the user-interface tools to choose the type of validation and how it is used.

Built-in declarative validation rules can be used to:

  • Ensure that key values are unique (primary key or other unique keys)

  • Determine the existence of a key value

  • Make a comparison between an attribute and anything from a literal value to a SQL query

  • Validate against a list of values that might be a literal list, a SQL query, or a view attribute

  • Make sure that a value falls within a certain range, or that it is limited by a certain number of bytes or characters

  • Validate using a regular expression or evaluate a Groovy expression

  • Make sure that a value satisfies a relationship defined by an aggregate on a child entity available through an accessor

  • Validate using a validation condition defined in a Java method on the entity

7.4.1 How to Ensure That Key Values Are Unique

The Unique Key validator ensures that primary key values for an entity object are always unique. The Unique Key validator can also be used for a non-primary-key attribute, as long as the attribute is defined as an alternate key. For information on how to define alternate keys, see Section 4.10.15, "How to Define Alternate Key Values."

Whenever any of the key attribute values change, this rule validates that the new key does not belong to any other entity object instance of this entity object class. (It is the business-logic tier equivalent of a unique constraint in the database.) If the key is found in one of the entity objects, a TooManyObjectsException is thrown. The validation check is done both in the entity cache and in the database.

There is a slight possibility that unique key validation might not be sufficient to prevent duplicate rows in the database. It is possible for two application module sessions to simultaneously attempt to create records with the same key. To prevent this from happening, create a unique index in the database for any unique constraint that you want to enforce.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

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

To ensure that a key value is unique:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select the Entity node, and click the Add icon.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select UniqueKey.

  4. In the Keys box, select the primary or alternate key.

  5. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see Section 7.6, "Triggering Validation Execution."

    Best Practice:

    While it is possible to add a precondition for a Unique Key validator, it is not a best practice. If a Unique Key validator fails to fire, for whatever reason, the cache consistency check is still performed and an error will be returned. It is generally better to add the validator and a meaningful error message.

  6. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails.

    For more information, see Section 7.7, "Creating Validation Error Messages."

  7. Click OK.

7.4.2 What Happens When You Use a Unique Key Validator

When you use a Unique Key validator, a <UniqueKeyValidationBean> tag is added to the entity object's XML file. Example 7-3 shows the XML for a Unique Key validator.

Example 7-3 Unique Key Validator XML Code

  <validation:UniqueKeyValidationBean
    Name="PersonEO_Rule_1"
    KeyName="AltKey"
    ResId="PersonEO_Rule_1">
    <validation:OnAttributes>
      <validation:Item
        Value="Email"/>
    </validation:OnAttributes>
  </validation:UniqueKeyValidationBean>

7.4.3 How to Validate Based on a Comparison

The Compare validator performs a logical comparison between an entity attribute and a value. When you add a Compare validator, you specify an operator and something to compare with. You can compare the following:

  • Literal value

    When you use a Compare validator with a literal value, the value in the attribute is compared against the specified literal value. When using this kind of comparison, it is important to consider data types and formats. The literal value must conform to the format specified by the data type of the entity attribute to which you are applying the rule. In all cases, the type corresponds to the type mapping for the entity attribute.

    For example, an attribute of column type DATE maps to the oracle.jbo.domain.Date class, which accepts dates and times in the same format accepted by java.sql.TimeStamp and java.sql.Date. You can use format masks to ensure that the format of the value in the attribute matches that of the specified literal. For information about entity object attribute type mappings, see Section 4.10.1, "How to Set Database and Java Data Types for an Entity Object Attribute." For information about the expected format for a particular type, refer to the Javadoc for the type class.

  • Query result

    When you use this type of validator, the SQL query is executed each time the validator is executed. The validator retrieves the first row from the query result, and it uses the value of the first column in the query (of that first row) as the value to compare. Because this query cannot have any bind variables in it, this feature should be used only when selecting one column of one row of data that does not depend on the values in the current row.

  • View object attribute

    When you use this type of validator, the view object's SQL query is executed each time the validator is executed. The validator retrieves the first row from the query result, and it uses the value of the selected view object attribute from that row as the value to compare. Because you cannot associate values with the view object's named bind variables, those variables can only take on their default values. Therefore this feature should be used only for selecting an attribute of one row of data that does not depend on the values in the current row.

  • View accessor attribute

    When defining the view accessor, you can assign row-specific values to the validation view object's bind variables.

  • Expression

    For information on the expression option, see Section 7.5, "Using Groovy Expressions For Validation and Business Rules."

  • Entity attribute

    The entity attribute option is available only for entity-level Compare validators.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

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

To validate based on a comparison:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select Compare. Note that the subordinate fields change depending on your choices.

  4. Select the appropriate operator.

  5. Select an item in the Compare With list, and based on your selection provide the appropriate comparison value.

  6. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see Section 7.6, "Triggering Validation Execution."

  7. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails.

    For more information, see Section 7.7, "Creating Validation Error Messages."

  8. Click OK.

Figure 7-2 shows what the dialog looks like when you use an entity-level Compare validator with an entity object attribute.

Figure 7-2 Compare Validator Using an Entity Object Attribute

Image of compare validator using a view accessor attribute

7.4.4 What Happens When You Validate Based on a Comparison

When you use a Compare validator, a <CompareValidationBean> tag is added to an entity object's XML file. Example 7-4 shows the XML code for the Email attribute in the PersonEO entity object.

Example 7-4 Compare Validator XML Code

<validation:CompareValidationBean
  xmlns="http://xmlns.oracle.com/adfm/validation"
  Name="PersonEO_Rule_0"
  ResId="PersonEO_Rule_0"
  OnAttribute="Email"
  OperandType="ATTR"
  Inverse="false"
  CompareType="EQUALTO"
  CompareValue="ConfirmedEmail"/>

7.4.5 How to Validate Using a List of Values

The List validator compares an attribute against a list of values (LOV). When you add a List validator, you specify the type of list to choose from:

  • Literal values - The validator ensures that the entity attribute is in (or not in, if specified) the list of values.

  • Query result - The validator ensures that the entity attribute is in (or not in, if specified) the first column of the query's result set. The SQL query validator cannot use a bind variable, so it should be used only on a fixed, small list that you have to query from a table. All rows of the query are retrieved into memory.

  • View object attribute - The validator ensures that the entity attribute is in (or not in, if specified) the view attribute. The View attribute validator cannot use a bind variable, so it should be used only on a fixed, small list that you have to query from a table. All rows of the query are retrieved into memory.

  • View accessor attribute - The validator ensures that the entity attribute is in (or not in) the view accessor attribute. The view accessor is probably the most useful option, because it can take bind variables and after you've created the LOV on the user interface, a view accessor is required.

Best Practice:

When using a List validator, the view accessor is typically the most useful choice because you can define a view criteria on the view accessor to filter the view data when applicable; and when defining an LOV on a view attribute, you typically use a view accessor with a view criteria.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

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

To validate using a list of values:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select List.

  4. In the Attribute list, choose the appropriate attribute.

  5. In the Operator field, select In or NotIn, depending on whether you want an inclusive list or exclusive.

  6. In the List Type field, select the appropriate type of list.

  7. Depending on the type of list you selected, you can either enter a list of values (each value on a new line) or an SQL query, or select a view object attribute or view accessor attribute.

  8. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see Section 7.6, "Triggering Validation Execution."

  9. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails.

    For more information, see Section 7.7, "Creating Validation Error Messages."

  10. Click OK.

Figure 7-3 shows what the dialog looks like when you use a List validator with a view accessor attribute.

Figure 7-3 List Validator Using a View Accessor Attribute

Image of list validator using an SQL query

7.4.6 What Happens When You Validate Using a List of Values

When you validate using a list of values, a <ListValidationBean> tag is added to an entity object's XML file. Example 7-5 shows the PaymentOptionEO.PaymentTypeCode attribute, which uses a view accessor attribute for the List validator.

Example 7-5 List Validator XML Code

<validation:ListValidationBean
   xmlns="http://xmlns.oracle.com/adfm/validation"
   Name="PaymentTypeCode_Rule_0"
   ResId="PaymentTypeCode_Rule_0"
   OnAttribute="PaymentTypeCode"
   OperandType="VO_USAGE"
   Inverse="false"
   ViewAccAttrName="Value"
   ViewAccName="PaymentTypesVA"/>

7.4.7 What You May Need to Know About the List Validator

The List validator is designed for validating an attribute against a relatively small set of values. If you select the Query Result or View Object Attribute type of list validation, keep in mind that the validator retrieves all of the rows from the query before performing an in-memory scan to validate whether the attribute value in question matches an attribute in the list. The query performed by the validator's SQL or view object query does not reference the value being validated in the WHERE clause of the query.

It is inefficient to use a validation rule when you need to determine whether a user-entered product code exists in a table of a large number of products. Instead, Section 8.5, "Using View Objects for Validation" explains the technique you can use to efficiently perform SQL-based validations by using a view object to perform a targeted validation query against the database. See also Section 5.12.11.2, "Using Validators to Validate Attribute Values."

Also, if the attribute you're comparing to is a key, the Key Exists validator is more efficient than validating a list of values; and if these choices need to be translatable, you should use a static view object instead of the literal choice.

7.4.8 How to Make Sure a Value Falls Within a Certain Range

The Range validator performs a logical comparison between an entity attribute and a range of values. When you add a Range validator, you specify minimum and maximum literal values. The Range validator verifies that the value of the entity attribute falls within the range (or outside the range, if specified).

If you need to dynamically calculate the minimum and maximum values, or need to reference other attributes on the entity, use the Script Expression validator and provide a Groovy expression. For more information, see Section 3.6.1, "Referencing Business Components Objects in Groovy Expressions" and Section 3.6.3, "Manipulating Business Component Attribute Values in Groovy Expressions."

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To validate within a certain range:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select Range.

  4. In the Attribute list, select the appropriate attribute.

  5. In the Operator field, select Between or NotBetween.

  6. In the Minimum and Maximum fields, enter appropriate values.

  7. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see Section 7.6, "Triggering Validation Execution."

  8. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails.

    For more information, see Section 7.7, "Creating Validation Error Messages."

  9. Click OK.

7.4.9 What Happens When You Use a Range Validator

When you validate against a range, a <RangeValidationBean> tag is added to the entity object's XML file. Example 7-6 shows the PersonEO.CreditLimit attribute with a minimum credit limit of zero and a maximum of 10,000.

Example 7-6 Range Validator XML Code

<validation:RangeValidationBean
  Name="CreditLimit_Rule_0"
  ResId="CreditLimit_Rule_0"
  OnAttribute="CreditLimit"
  OperandType="LITERAL"
  Inverse="false"
  MinValue="0"
  MaxValue="10000"/>

7.4.10 How to Validate Against a Number of Bytes or Characters

The Length validator validates whether the string length (in characters or bytes) of an attribute's value is less than, equal to, or greater than a specified number, or whether it lies between a pair of numbers.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

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

To validate against a number of bytes or characters:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select Length.

  4. In the Attribute list, select the appropriate attribute.

  5. In the Operator field, select how to evaluate the value.

  6. In the Comparison Type field, select Byte or Character and enter a length.

  7. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see Section 7.6, "Triggering Validation Execution."

  8. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails. For more information, see Section 7.7, "Creating Validation Error Messages."

  9. Click OK.

7.4.11 What Happens When You Validate Against a Number of Bytes or Characters

When you validate using length, a <LengthValidationBean> tag is added to the entity object's XML file, as shown in Example 7-7. For example, you might have a field where the user enters a password or PIN and the application wants to validate that it is at least 6 characters long, but not longer than 10. You would use the Length validator with the Between operator and set the minimum and maximum values accordingly.

Example 7-7 Validating the Length Between Two Values

    <validation:LengthValidationBean
      OnAttribute="pin"
      CompareType="BETWEEN"
      DataType="CHARACTER"
      MinValue="6"
      MaxValue="10"
      Inverse="false"/>

7.4.12 How to Validate Using a Regular Expression

The Regular Expression validator compares attribute values against a mask specified by a Java regular expression.

If you want to create expressions that can be personalized in metadata, you can use the Script Expression validator. For more information, see Section 7.5, "Using Groovy Expressions For Validation and Business Rules."

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To validate using a regular expression

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select Regular Expression.

  4. In the Operator field, you can select Matches or Not Matches.

  5. To use a predefined expression (if available), you can select one from the dropdown list and click Use Pattern. Otherwise, write your own regular expression in the field provided.

    Note:

    You can add your own expressions to the list of predefined expressions. To add a predefined expression, add an entry in the PredefinedRegExp.properties file in the BC4J subdirectory of the JDeveloper system directory (for example, C:\Documents and Settings\username\Application Data\JDeveloper\system##\o.BC4J\PredefinedRegExp.properties).

  6. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see Section 7.6, "Triggering Validation Execution."

  7. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails. For more information, see Section 7.7, "Creating Validation Error Messages."

  8. Click OK.

Figure 7-4 shows what the dialog looks like when you select a Regular Expression validator and validate that the Email attribute matches a predefined Email Address expression.

Figure 7-4 Regular Expression Validator Matching Email Address

Image of regular expression validator matching email address

7.4.13 What Happens When You Validate Using a Regular Expression

When you validate using a regular expression, a <RegExpValidationBean> tag is added to the entity object's XML file. Example 7-8 shows an Email attribute that must match a regular expression.

Example 7-8 Regular Expression Validator XML Code

<validation:RegExpValidationBean
  Name="Email_Rule_0"
  OnAttribute="Email"
  Pattern="[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}"
  Flags="CaseInsensitive"
  Inverse="false"/>

7.4.14 How to Use the Average, Count, or Sum to Validate a Collection

You can use collection validation on the average, count, sum, min, or max of a collection. This validator is available only at the entity level. It is useful for validating the aggregate calculation over a collection of associated entities by way of an entity accessor to a child entity (on the many end of the association). You must select the association accessor to define the Collection validator.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

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

To validate using an aggregate calculation:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select the Entity node and click the Add icon.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select Collection.

  4. In the Operation field, specify the operation (sum, average, count, min, or max) to perform on the collection for comparison.

  5. Select the appropriate accessor and attribute for the validation.

    The accessor you choose must be a composition association accessor. Only accessors of this type are displayed in the dropdown list.

  6. Specify the operator and the comparison type and value.

  7. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see Section 7.6, "Triggering Validation Execution."

  8. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails. For more information, see Section 7.7, "Creating Validation Error Messages."

  9. Click OK.

7.4.15 What Happens When You Use Collection Validation

When you validate using a Collection validator, a <CollectionValidationBean> tag is added to the entity object's XML file, as in Example 7-9.

Example 7-9 Collection Validator XML Code

<validation:CollectionValidationBean
    Name="OrderEO_Rule_0"
    OnAttribute="OrderTotal"
    OperandType="LITERAL"
    Inverse="false"
    CompareType="LESSTHAN"
    CompareValue="5"
    Operation="sum"/>

7.4.16 How to Determine Whether a Key Exists

The Key Exists validator is used to determine whether a key value (primary, foreign, or alternate key) exists.

There are a couple of benefits to using the Key Exists validator:

  • The Key Exists validator has better performance because it first checks the cache and only goes to the database if necessary.

  • Since the Key Exists validator uses the cache, it will find a key value that has been added in the current transaction, but not yet committed to the database. For example, you add a new Department and then you want to link an Employee to that new department.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see Section 7.4, "Using the Built-in Declarative Validation Rules."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To determine whether a value exists:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, select Key Exists from the Rule Type list.

  4. Select the type of validation target (Entity Object, View Object, or View Accessor).

    If you want the Key Exists validator to be used for all view objects that use this entity attribute, select Entity Object.

  5. Depending on the validation target, you can choose either an association or a key value.

    If you are searching for an attribute that does not exist in the Validation Target Attributes list, it is probably not defined as a key value. To create alternate keys, see Section 4.10.15, "How to Define Alternate Key Values."

  6. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and the validation level (entity or transaction). For more information, see Section 7.6, "Triggering Validation Execution."

  7. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails. For more information, see Section 7.7, "Creating Validation Error Messages."

  8. Click OK.

Figure 7-5 shows a Key Exists validator that validates whether the MembershipId entered in the PersonEO entity object exists in the MembershipBaseEO entity object.

Figure 7-5 Key Exists Validator on an Entity Attribute

Image of key exists validator on an entity attribute

7.4.17 What Happens When You Use a Key Exists Validator

When you use a Key Exists validator, an <ExistsValidationBean> tag is created in the XML file for the entity object, as in Example 7-10.

Example 7-10 Using the Key Exists Validator With an Association

<validation:ExistsValidationBean
      Name="MembershipId_Rule_0"
      ResId="MembershipId_Rule_0"
      OperandType="EO"
      AssocName= "oracle.fodemo.storefront.entities.associations.PersonsMembershipsBaseFkAssoc"/>

7.4.18 What You May Need to Know About Declarative Validators and View Accessors

When using declarative validators you must consider how your validation will interact with expected input. The combination of declarative validators and view accessors provides a simple yet powerful alternative to coding. But, as powerful as the combination is, you still need to consider how data composition can impact performance.

Consider a scenario where you have the following:

  • A ServiceRequestEO entity object with Product and RequestType attributes, and a view accessor that allows it to access the RequestTypeVO view object

  • A RequestTypeVO view object with a query specifying the Product attribute as a bind parameter

The valid list of RequestTypes varies by Product. So, to validate the RequestType attribute, you use a List validator using the view accessor.

Now lets add a set of new service requests. For the first service request (row), the List validator binds the value of the Product attribute to the view accessor and executes it. For each subsequent service request the List validator compares the new value of the Product attribute to the currently bound value.

  • If the value of Product matches, the current RowSet object is retained.

  • If the value of Product has changed, the new value is bound and the view accessor re-executed.

Now consider the expected composition of input data. For example, the same products could appear in the input multiple times. If you simply validate the data in the order received, you might end up with the following:

  1. Dryer (initial query)

  2. Washing Machine (re-execute view accessor)

  3. Dish Washer (re-execute view accessor)

  4. Washing Machine (re-execute view accessor)

  5. Dryer (re-execute view accessor)

In this case, the validator will execute 5 queries to get 3 distinct row sets. As an alternative, you can add an ORDER BY clause to the RequestTypeVO to sort it by Product. In this case, the validator would execute the query only once each for Washing Machine and Dryer.

  1. Dish Washer (initial query)

  2. Dryer (re-execute view accessor)

  3. Dryer

  4. Washing Machine (re-execute view accessor)

  5. Washing Machine

A small difference on a data set this size, but multiplied over larger data sets and many users this could easily become an issue. An ORDER BY clause is not a solution to every issue, but this example illustrates how data composition can impact performance.

7.5 Using Groovy Expressions For Validation and Business Rules

Groovy expressions are Java-like scripting code stored in the XML definition of an entity object. Because Groovy expressions are stored in XML, you can change the expression values even if you don't have access to the entity object's Java file. You can even change or specify values at runtime.

For more information about using Groovy script in your entity object business logic, see Section 3.6, "Overview of Groovy Scripting Language Support."

7.5.1 How to Reference Entity Object Methods in Groovy Validation Expressions

You can call methods on the current entity instance using the source property of the current object. The source property allows you to access to the entity instance being validated.

If the method is a non-boolean type and the method name is getXyzAbc() with no arguments, then you access its value as if it were a property named XyzAbc. For a boolean-valued property, the same holds true but the JavaBean naming pattern for the getter method changes to recognize isXyzAbc() instead of getXyzAbc(). If the method on your entity object does not match the JavaBean getter method naming pattern, or if it takes one or more arguments, then you must call it like a method using its complete name.

For example, say you have an entity object with the four methods shown in Example 7-11.

Example 7-11 Sample Entity Object Methods

public boolean isNewRow() {
 System.out.println("## isNewRow() accessed ##"); 
 return true; 
} 
 
public boolean isNewRow(int n) {
 System.out.println("## isNewRow(int n) accessed ##");
 return true;
}
 
public boolean testWhetherRowIsNew() {
 System.out.println("## testWhetherRowIsNew() accessed ##"); 
 return true; 
}
 
public boolean testWhetherRowIsNew(int n) {
 System.out.println("## testWhetherRowIsNew(int n) accessed ##");
 return true;
} 

Then the following Groovy validation condition would trigger them all, one of them being triggered twice, as shown in Example 7-12.

Example 7-12 Groovy Script Calling Sample Methods

newRow && source.newRow && source.isNewRow(5) && source.testWhetherRowIsNew() && source.testWhetherRowIsNew(5)

By running this example and forcing entity validation to occur, you would see the diagnostic output shown in Example 7-13 in the log window:

Example 7-13 Output From Sample Groovy Script

## isNewRow() accessed ##
## isNewRow() accessed ##
## isNewRow(int n) accessed ##
## testWhetherRowIsNew() accessed ##
## testWhetherRowIsNew(int n) accessed ##

Notice the slightly different syntax for the reference to a method whose name matches the JavaBeans property getter method naming pattern. Both newRow and source.newRow work to access the boolean-valued, JavaBeans getter-style method that has no arguments. But because the testWhetherRowIsNew method does not match the JavaBeans getter method naming pattern, and the second isRowNew method takes an argument, then you must call them like methods using their complete name.

7.5.2 How to Validate Using a True/False Expression

You can use a Groovy expression to return a true/false statement. The Script Expression validator requires that the expression either return true or false, or that it calls the adf.error.raise/warn() method. A common use of this feature would be to validate an attribute value, for example, to make sure that an account number is valid.

Note:

Using the adf.error.raise/warn() method (rather than simply returning true or false) allows you to define the message text to show to the user, and to associate an entity-level validator with a specific attribute. For more information, see Section 7.7.3, "How to Conditionally Raise Error Messages Using Groovy."

Before you begin:

It may be helpful to have an understanding of the use of Groovy in validation rules. For more information, see Section 7.5, "Using Groovy Expressions For Validation and Business Rules."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To validate using a true/false expression:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select where you want to add the validator, and click the Add icon.

    • To add an entity-level validator, select the Entity node.

    • To add an attribute-level validator, expand the Attributes node and select the appropriate attribute.

  3. In the Add Validation Rule dialog, in the Rule Type dropdown list, select Script Expression.

  4. Enter a validation expression in the field provided.

  5. You can optionally click the Validation Execution tab and enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see Section 7.6, "Triggering Validation Execution."

  6. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the validation rule fails. For more information, see Section 7.7, "Creating Validation Error Messages."

  7. Click OK.

The sample code in Example 7-14 comes from the PaymentOptionEO entity object. The code validates account numbers based on the Luhn algorithm, a checksum formula in widespread use.

Example 7-14 Validating an Account Number Using an Expression

<validation:ExpressionValidationBean
  Name="AccountNumber_Rule_0"
  OperandType="EXPR"
  Inverse="false">
  <OnCondition>
    <![CDATA[PaymentTypeCode=='CC']]>
  </OnCondition>
  <MsgIds>
   <Item
    Value="PaymentOption_AccountNumber"/>
  </MsgIds>
  <TransientExpression>
   <![CDATA[
    String acctnumber = newValue;
     sumofdigits = 0;
     digit = 0;
     addend = 0;
     timesTwo = false;
     range = acctnumber.length()-1..0
      range.each {i ->
      digit = Integer.parseInt (acctnumber.substring (i, i + 1));
      if (timesTwo) {
       addend = digit * 2;
       if (addend > 9) {
        addend -= 9;
       }
      }
      else {
       addend = digit;
      }
      sumofdigits += addend;
      timesTwo = !timesTwo;
     }
     modulus = sumofdigits % 10;
     return modulus == 0;
   ]]>
  </TransientExpression>
</ExpressionValidationBean>

7.5.3 What Happens When You Add a Groovy Expression

When you create a Groovy expression, it is saved in the entity object's XML component. Example 7-15 shows the RegisteredDate attribute in the PersonEO.xml file. The Groovy expression is wrapped by a <TransientExpression> tag.

Example 7-15 XML Code for RegisteredDate Attribute on the PersonEO Entity Object

<Attribute
    Name="RegisteredDate"
    IsUpdateable="true"
    ColumnName="REGISTERED_DATE"
    Type="oracle.jbo.domain.Date"
    ColumnType="DATE"
    SQLType="DATE"
    TableName="PERSONS">
    <DesignTime>
      <Attr Name="_DisplaySize" Value="7"/>
    </DesignTime>
    <validation:ExpressionValidationBean
      Name="RegisteredDate_Rule_0"
      OperandType="EXPR"
      Inverse="false">
      <MsgIds>
        <Item
          Value="RegisteredDate_Rule_0"/>
      </MsgIds>
      <TransientExpression>
        <![CDATA[
newValue <= (new java.sql.Timestamp(System.currentTimeMillis()))
         ]]>
      </TransientExpression>
    </ExpressionValidationBean>
  </Attribute>

This tag can take one of several forms. For some Groovy expressions, the <TransientExpression> tag is wrapped by an <ExpressionValidationBean> tag as well. Figure 7-6 shows the validation expression in the Edit Validation Rule dialog.

Figure 7-6 Validation Expression for RegisteredDate Attribute on the PersonEO Entity Object

Image of Validation Expression in Validation Rule dialog

7.6 Triggering Validation Execution

JDeveloper allows you to select the attributes that trigger validation, so that validation execution happens only when one of the triggering attributes is dirty. In previous releases of JDeveloper, an entity-level validator would fire on an attribute whenever the entity as a whole was dirty. This feature is described in Section 7.6.1, "How to Specify Which Attributes Fire Validation."

JDeveloper also allows you to specify a precondition for the execution of a validator (as described in Section 7.6.3, "How to Set Preconditions for Validation") and set transaction-level validation (described in Section 7.6.4, "How to Set Transaction-Level Validation").

7.6.1 How to Specify Which Attributes Fire Validation

When defining a validator at the entity level, you have the option of selecting one or more attributes of the entity object that, when changed, trigger execution of the validator.

Note:

When the validity of one attribute is dependent on the value in another attribute, the validation should be performed as entity validation, not attribute validation. You can set validation execution order on the entity level or attribute level.

If you do not specify one or more dependent attributes, the validator will fire whenever the entity is dirty. Firing execution only when required makes your application more performant.

Before you begin:

It may be helpful to have an understanding of how validation rules are triggered. For more information, see Section 7.6, "Triggering Validation Execution."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To specify which attributes fire validation:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select the Entity node and click the Edit icon.

  3. In the Edit Validation Rule dialog, click the Validation Execution tab.

  4. Select the attributes that will fire validation.

  5. Click OK.

For example, in the StoreFront module of the Fusion Order Demo application, the OrderEO entity object has an entity-level validator that constrains the length of the GiftwrapMessage attribute. As shown in Figure 7-7, this validator is set to be executed on the entity object only when either the GiftwrapMessage attribute or the GiftwrapFlag attribute has been changed.

Figure 7-7 Triggering attributes on the Validation Execution tab of the Edit Validation Rule dialog

Image of Triggering Attributes in Validation Rule dialog

7.6.2 What Happens When You Constrain Validation Execution with Triggering Attributes

When you specify triggering attributes on the Validation Execution tab of the Edit Validation Rule dialog, JDeveloper adds an <OnAttributes> tag to the validator definition in the entity object's XML file. Example 7-16 shows the XML code for the entity-level validator for the OrderEO entity object in the StoreFront module of the Fusion Order Demo application.

Example 7-16 OnAttributes element in XML validation code

<LengthValidationBean
  xmlns="http://xmlns.oracle.com/adfm/validation"
  Name="OrderEO_Rule_0"
  OnAttribute="GiftwrapMessage"
  CompareType="GREATERTHANEQUALTO"
  DataType="CHARACTER"
  CompareLength="1"
  Inverse="false"
  ResId="GiftMessage_Required_Error_0">
  <OnAttributes>
    <Item Value="GiftwrapMessage"/>
    <Item Value="GiftwrapFlag"/>
  </OnAttributes>
  <OnCondition>
    <![CDATA[GiftwrapFlag == 'Y']]>
  </OnCondition>
</LengthValidationBean>

7.6.3 How to Set Preconditions for Validation

The Validation Execution tab (on the Add/Edit Validation Rule dialog) allows you to add a Groovy expression that serves as a precondition. If you enter an expression in the Conditional Execution Expression box, the validator is executed only if the condition evaluates True.

Best Practice:

While it is possible to add a precondition for a Unique Key validator, it is not a best practice. If a Unique Key validator fails to fire, for whatever reason, the cache consistency check is still performed and an error will be returned. It is generally better to add the validator and a meaningful error message.

7.6.4 How to Set Transaction-Level Validation

Performing a validation during the transaction level (rather than entity level) means that the validation will be performed after all entity-level validation is performed. For this reason, it may be useful if you want to ensure that a validator is performed at the end of the process.

In addition, the Key Exists validator is more performant with bulk transactions if it is run as a transaction level validator since it will be run only once for all entities in the transaction (of the same type), rather than once per entity. This will result in improved performance if the validator has to go to the database.

Note:

Transaction-level validation is only applicable to Key Exists and Method entity validators.

Before you begin:

It may be helpful to have an understanding of how validation rules are triggered. For more information, see Section 7.6, "Triggering Validation Execution."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To specify entity-level or transaction-level validation:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select an entity-level validation rule and click the Edit icon.

  3. In the Edit Validation Rule dialog, click the Validation Execution tab.

  4. Select Execute at Entity Level or Defer Execution to Transaction Level.

  5. Click OK.

7.6.5 What You May Need to Know About the Order of Validation Execution

You cannot control the order in which attributes are validated – they are always validated in the order they appear in the entity definition. You can order validations for a given attribute (or for the entity), but you cannot reorder the attributes themselves.

7.7 Creating Validation Error Messages

Validation error messages provide important information for the user: the message should convey what went wrong and how to fix it.

7.7.1 How to Create Validation Error Messages

When you create or edit a validation rule, enter text to help the user determine what caused the error.

Before you begin:

It may be helpful to have an understanding of error messages in validation rules. For more information, see Section 7.7, "Creating Validation Error Messages."

You may also find it useful to understand additional functionality that can be added using other validation features. For more information, see Section 7.1.2, "Additional Functionality for Declarative Validation."

To create validation error messages:

  1. In the Application Navigator, double-click the desired entity object.

  2. In the overview editor, click the Business Rules navigation tab, select a validation rule and click the Edit icon.

  3. In the Edit Validation Rule dialog, click the Failure Handling tab.

  4. In the Message Text field, enter your error message.

    You can also define error messages in a message bundle file. To select a previously defined error message or to define a new one in a message bundle file, click the Select Message icon.

    Note:

    The Script Expression validator allows you to enter more than one error message. This is useful if the validation script conditionally returns different error or warning messages. For more information, see Section 7.7.3, "How to Conditionally Raise Error Messages Using Groovy."

  5. You can optionally include message tokens in the body of the message, and define them in the Token Message Expressions list.

    Figure 7-8 shows the failure message for a validation rule in the PaymentOptionEO entity object that contains message tokens. For more information on this feature, see Section 7.7.4, "How to Embed a Groovy Expression in an Error Message."

  6. Click OK.

7.7.2 How to Localize Validation Messages

The error message is a translatable string and is managed in the same way as translatable UI control hints in an entity object message bundle class. To view the error message for the defined rule in the message bundle class, locate the String key in the message bundle that corresponds to the ResId property in the XML component definition entry for the validator. For example, Example 7-17 shows a message bundle where the NAME_CANNOT_BEGIN_WITH_U key appears with the error message for the default locale.

Example 7-17 Message Bundle Contains Validation Error Messages

package devguide.advanced.customerrors;
import java.util.ListResourceBundle;

public class CustomMessageBundle extends ListResourceBundle {
  private static final Object[][] sMessageStrings = new String[][] {
  // other strings here
  {"NAME_CANNOT_BEGIN_WITH_U", "The name cannot begin with the letter u!"},
  // other strings here
  };
  // etc.
}

Resource bundles can be created for your applications as a list resource bundle (as shown in Example 7-17), as a properties bundle, or as an XLIFF resource bundle. For more information about using translatable strings in a resource bundle, see Section 4.7, "Working with Resource Bundles."

7.7.3 How to Conditionally Raise Error Messages Using Groovy

You can use the adf.error.raise() and adf.error.warn() methods to conditionally raise one error message or another depending upon branching in the Groovy expression. For example, if an attribute value is x, then validate as follows, and if the validation fails, raise error messageA; whereas if the attribute value is y, then instead validate a different way and if validation fails, raise error messageB.

If the expression returns false (versus raising a specific error message using the raise() method), the validator calls the first error message associated with the validator.

The syntax of the raise() method takes one required parameter (the msgId to use from the message bundle), and optionally can take the attrName parameter. If you pass in the AttrName, the error is associated with that attribute even if the validation is assigned to the entity.

You can use either adf.error.raise() or adf.error.warn() methods, depending on whether you want to throw an exception, or whether you want processing to continue, as described in Section 7.8, "Setting the Severity Level for Validation Exceptions."

7.7.4 How to Embed a Groovy Expression in an Error Message

A validator's error message can contain embedded expressions that are resolved by the server at runtime. To access this feature, simply enter a named token delimited by curly braces (for example, {2} or {errorParam}) in the error message text where you want the result of the Groovy expression to appear.

After entering the token into the text of the error message (on the Failure Handling tab of the Edit Validation Rule dialog), the Token Message Expressions table at the bottom of the dialog displays a row that allows you to enter a Groovy expression for the token. Figure 7-8 shows the failure message for a validation rule in the PaymentOptionEO entity object that contains message tokens.

Figure 7-8 Using Message Tokens in a Failure Message

Image of Failure Handling tab showing a message with tokens

The expressions shown in Figure 7-8 are Groovy expressions that return the labels of the specified fields. You can also use Groovy expressions to access attribute values and other business components objects. You can use the Groovy expression newValue to return the entered value, as shown in the Rule validator for the RoutingIdentifier attribute of the PaymentOptionEO entity object in the StoreFront module of the Fusion Order Demo application.

The Groovy syntax to retrieve a value from a view accessor is accessorName.currentRow.AttributeName. For example, the Groovy expression MyEmpAccessor.currentRow.Job returns the value of the Job attribute in the current row of the MyEmpAccessor view accessor.

The Groovy expression can also be more complex, as in Example 7-18, which shows an expression in the error message for the List validation rule for the OwnerTypeCode attribute in the AddressUsageEO entity object.

Example 7-18 Groovy Script in the OwnerTypeCode Validation Error Message

def ownertypevalue = [] 
while ( AddressOwnerTypesVA.hasNext() ) { 
AddressOwnerTypesVA.next()
  ownertypevalue.add(AddressOwnerTypesVA.currentRow.Value) 
} 
return ownertypevalue

For more information about accessing business components objects using Groovy, see Section 3.6, "Overview of Groovy Scripting Language Support."

7.8 Setting the Severity Level for Validation Exceptions

You can set the severity level for validation exceptions to two levels, Informational Warning and Error. If you set the severity level to Informational Warning, an error message will display, but processing will continue. If you set the validation level to Error, the user will not be able to proceed until you have fixed the error.

Under most circumstances you will use the Error level for validation exceptions, so this is the default setting. However, you might want to implement a Informational Warning message if the user has a certain security clearance. For example, a store manager may want to be able to make changes that would surface as an error if a clerk tried to do the same thing.

To set the severity level for validation exceptions, use the Failure Handling tab of the Add Validation Rule dialog.

To set the severity level of a validation exception:

  1. In the Application Navigator, double-click the desired entity object.

  2. On the Business Rules page, select an existing validation rule and click the Edit icon, or click the Add icon to create a new rule.

  3. In the Edit/Add Validation Rule dialog, click the Failure Handling tab and select the option for either Error or Informational Warning.

  4. Click OK.

7.9 Bulk Validation in SQL

To improve the performance of batch-load applications, such as data synchronization programs, the ADF framework employs bulk validation for primary keys (including alternate keys) and foreign keys.

When the Key Exists validator is configured to defer validation until the transaction commits, or when the rows are being updated or inserted through the processXXX methods of the ADF business components service layer, the validation cache is preloaded. This behavior uses the normal row-by-row derivation and validation logic, but uses validation logic that checks a memory cache before making queries to the database. Performance is improved by preloading the memory cache using bulk SQL operations based on the inbound data.