11 Defining Validation and Business Rules Declaratively

This chapter describes how to use ADF entity objects to write business rules that implement declarative validation in an Oracle ADF application.

This chapter includes the following sections:

11.1 About Declarative Validation

Use the overview editor of the ADF entity object to define declarative validation rules. These rules are stored in the entity object XML file. In addition to built-in declarative validation, you can write custom rules.

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 XML file. Declarative validation is different from programmatic validation (covered in 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 Implementing Custom Validation Rules. You can also base validation on a Groovy expression, as described in Using Groovy Expressions For Business Rules and Triggers.

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.

11.1.1 Declarative Validation Use Cases and Examples

In a Fusion web application containing ADF Business Components, 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 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, ADF Model layer validation can be more useful.

11.1.2 Additional Functionality for Declarative Validation

You may find it helpful to understand other Oracle 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.

11.2 Determining Where to Implement Validation

Oracle ADF follows the Model View Controller (MVC) architectural design pattern that allows validation implementation at each layer. Depending on business needs, implement validations at particular layers.

As explained in Oracle ADF Architecture, the model-view-controller (MVC) architecture of a Fusion web application has multiple layers that provide a clean separation of business logic, page navigation, and user interface. These layers also provide multiple options for implementing validation, and there are benefits and disadvantages to using validation at each layer. The place where you choose to implement validation is dependent on the given business need or use case. Generally, the validations that occur closer to the data source are more centralized and therefore easier to maintain, while those that occur closer to the user interface provide more immediate feedback at runtime.

Data services layer -- Whether it be a database or a web service or some other source of data, the data services layer typically resides outside the context of the application itself and employs constraints that define the nature of each field of data. Data services constraints are typically defined for every piece of data that is stored, and are very important to maintaining the integrity of that data. However, it is neither effective nor efficient to rely solely on these constraints, because they are not enforced until the data reaches the data source, typically when the application attempts to commit a transaction. This requires a round trip from the client UI to the data source and back, and a single error on a single record can cause the rollback of entire transaction.

Business services layer -- Business rules that you implement at the business service layer in ADF Business Components (such as entity objects and view objects) provide more efficiency than data services constraints because they don't require a round trip to the data source. They are also easier to maintain than validators implemented at the view layer because a business rule defined on an attribute for a given entity object is enforced on every page that uses that entity object. In addition to attribute-level validators, you can also implement entity-level validators when the validity of the value of one attribute is dependent on the value of another. For example, DateShipped must be greater than DateOrdered. This kind of business rule is explained in this chapter.

Model layer -- Although not used as commonly as the other kinds of business rules, model layer validation can also be useful. You can define business rules on a binding to a business service. This feature can be useful, for example, if you can't implement validation on the business service itself because your application consumes an external web service. See Using Validation in the ADF Model Layer .

View layer -- From the user's perspective, view layer validations are the most efficient. They provide immediate feedback when the user enters data and subsequently leaves (tabs out of) a given field, without requiring even a trip to the application server. However, view layer validations are implemented on the page, so every page that provides access to a given data field must define the validation for that field. See the "Validating and Converting Input" chapter in Developing Web User Interfaces with Oracle ADF Faces.

11.3 Understanding the Validation Cycle

You can enforce validation on an ADF entity row, either when a persistent entity row attribute is modified, or an entity row is created.

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.

11.3.1 Types of Entity Object Validation Rules

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

11.3.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 represent 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.

11.3.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 represent 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 Avoiding Infinite Validation Cycles.

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

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

11.3.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 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:

  1. In the Applications window, double-click the desired application module.
  2. In the overview editor, click the Configurations navigation tab, select the configuration hyperlink for which you want to adjust the validation threshold.
  3. In the overview editor for application module configurations (on the bc4j.xcfg file), click the Properties tab, and click Add Property.
  4. In the Add Property dialog, select the jbo.validation.threshold property and click OK.
  5. In the overview editor, in the Properties list, enter a new value for the jbo.validation.threshold property and save your changes.

You can also change the validation threshold programmatically by using the SetValidationThreshold() method as shown below. In this example, the new threshold is 12.

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

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

11.3.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 11-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 11-1 Diagram of Entity Row States and Transitions

Description of Figure 11-1 follows
Description of "Figure 11-1 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.

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

11.4 Adding Validation Rules to Entity Objects and Attributes

ADF Business Components allows you to declaratively add validations rules to an entity object.

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.

11.4.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 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 Additional Functionality for Declarative Validation.

To add a validation rule:

  1. In the Applications window, 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. In the Add Validation Rule dialog, select the desired type of validation rule from the Rule Type dropdown list.
  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 Using the Built-in Declarative Validation Rules.

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

    For more information, see 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 Creating Validation Error Messages.

  7. Click OK.

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

11.4.3 What Happens When You Add a Validation Rule

When you add a validation rule to an entity object, JDeveloper updates the entity object's XML document 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 the following example.

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

11.4.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 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, Triggering Validation Execution.

11.4.5 What You May Need to Know About List of Values and Attribute Validation Rules

Developers may define a List of Values (LOV) attribute on a view object to support displaying choice lists in the user interface. The view object's LOV attribute in turn relies on a data source view object to provide the values for display. Because the LOV feature assumes that the queried data source contains only valid values, any validation rules defined on data source view object attributes will be suppressed before the choice list displays in the user interface. Therefore, the developer who defines the LOV must ensure that the list of values returned by the data source view object contains only valid values, as describe in Working with List of Values (LOV) in View Object Attributes.

11.5 Using the Built-in Declarative Validation Rules

ADF Business Components provides numerous built-in declarative validation rules to achieve numerous validation use cases.

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

11.5.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 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 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 Additional Functionality for Declarative Validation.

To ensure that a key value is unique:

  1. In the Applications window, 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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see 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 Creating Validation Error Messages.

  7. Click OK.

11.5.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. The following example shows the XML for a Unique Key validator.

<validation:UniqueKeyValidationBean
  Name="CustomerEORule0"
  KeyName="SCustomerIdPk">
  <validation:OnAttributes>
    <validation:Item
      Value="Id"/>
  </validation:OnAttributes>
</validation:UniqueKeyValidationBean>

11.5.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 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 Using Groovy Expressions For Business Rules and Triggers.

  • 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 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 Additional Functionality for Declarative Validation.

To validate based on a comparison:

  1. In the Applications window, 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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see 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 Creating Validation Error Messages.

  8. Click OK.

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

Figure 11-2 Compare Validator Using an Entity Object Attribute

Description of Figure 11-2 follows
Description of "Figure 11-2 Compare Validator Using an Entity Object Attribute"

11.5.4 What Happens When You Validate Based on a Comparison

When you create a Compare validator, a <CompareValidationBean> tag is added to an entity object's XML file. The following example shows the XML code for an entity level validator in the OrdEO entity object.

<validation:CompareValidationBean
    Name="OrdEO_Rule_0"
    ResId="oracle.summit.model.entities.OrdEO_Rule_0"
    OnAttribute="DateShipped"
    OperandType="ATTR"
    Inverse="false"
    CompareType="GREATERTHANEQUALTO"
    CompareValue="DateOrdered">
    <validation:OnAttributes>
      <validation:Item
        Value="DateShipped"/>
      <validation:Item
        Value="DateOrdered"/>
    </validation:OnAttributes>
  </validation:CompareValidationBean>

11.5.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 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 Additional Functionality for Declarative Validation.

To validate using a list of values:

  1. In the Applications window, 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 or exclusive list.
  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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see 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 Creating Validation Error Messages.

  10. Click OK.

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

Figure 11-3 List Validator Using a View Object Attribute

Description of Figure 11-3 follows
Description of "Figure 11-3 List Validator Using a View Object Attribute"

11.5.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. The following example shows the CustomerEO.CountryId attribute, which uses a view object attribute for the List validator.

<validation:ListValidationBean
      Name="CountryIdRule0"
      OnAttribute="CountryId"
      OperandType="JBO"
      Inverse="false"
      ListValue="oracle.summit.model.views.CountryVO.Id"/>

11.5.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, 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 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.

11.5.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 What You May Need to Know About Referencing Business Components in Groovy Expressions and What You May Need to Know About 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 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 Additional Functionality for Declarative Validation.

To validate within a certain range:

  1. In the Applications window, 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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression.

    For more information, see 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 Creating Validation Error Messages.

  9. Click OK.

11.5.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. The following example shows the ItemEO.Quantity attribute with a minimum quantity of one and a maximum of 99.

<validation:RangeValidationBean
      Name="QuantityRule0"
      OnAttribute="Quantity"
      OperandType="LITERAL"
      Inverse="false"
      MinValue="1"
      MaxValue="99"/>

11.5.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 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 Additional Functionality for Declarative Validation.

To validate against a number of bytes or characters:

  1. In the Applications window, 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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see 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 Creating Validation Error Messages.
  9. Click OK.

11.5.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 the following example. 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.

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

11.5.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 Using Groovy Expressions For Business Rules and Triggers.

Before you begin:

It may be helpful to have a general understanding of the built-in validation rules. For more information, see 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 Additional Functionality for Declarative Validation.

To validate using a regular expression

  1. In the Applications window, 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, 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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see 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 Creating Validation Error Messages.
  8. Click OK.

Figure 11-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 11-4 Regular Expression Validator Matching Email Address

Description of Figure 11-4 follows
Description of "Figure 11-4 Regular Expression Validator Matching Email Address"

11.5.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. The following example shows an Email attribute that must match a regular expression.

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

11.5.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 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 Additional Functionality for Declarative Validation.

To validate using an aggregate calculation:

  1. In the Applications window, 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. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression. For more information, see 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 Creating Validation Error Messages.
  9. Click OK.

11.5.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 the following example.

<validation:CollectionValidationBean
    Name="OrdEORule01"
    Accessor="ItemEO"
    CollAttribute="Quantity"
    OperandType="LITERAL"
    Inverse="false"
    CompareType="GREATERTHAN"
    CompareValue="5"
    Operation="min"/>

11.5.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 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 Additional Functionality for Declarative Validation.

To determine whether a value exists:

  1. In the Applications window, 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 Key Exists.
  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 How to Define Alternate Key Values.

  6. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and the validation level (entity or transaction). For more information, see 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 Creating Validation Error Messages.
  8. Click OK.

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

Figure 11-5 Key Exists Validator on an Entity Attribute

This image is described in the surrounding text

11.5.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 the following example.

<validation:ExistsValidationBean
      Name="CustomerId_Rule_0"
      ResId="oracle.summit.model.entities.OrdEO.CustomerId_Rule_0"
      OperandType="EO"
      AssocName="oracle.summit.model.entities.assoc.SOrdCustomerIdFkAssoc"/>

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

11.6 Using Entity-Level Triggers

ADF Business Components allows you to apply triggers in an entity object’s lifecycle. Triggers execute at these set lifecycle events such as before a delete, after it, or before an insert operation.

Entity-level triggers enable you to implement expressions that are executed in response to trigger points in the entity object life cycle, such as before an insert operation or after a delete.

For example, you can evaluate or assert the value of an attribute prior to inserting an entity object or after updating an entity object. For a list of the available trigger points, see the online help.

11.6.1 How to Implement Business Rules Using Entity-Level Triggers

You can use Groovy script to implement business rules that are executed in response to entity-level triggers.

Before you begin:

It may be helpful to have an understanding of entity-level triggers. See Using Entity-Level Triggers.

You may also find it helpful to understand additional functionality that can be added using other validation features. See Additional Functionality for Declarative Validation.

To add a trigger:
  1. In the Applications window, double-click the entity object you want to add a trigger to.
  2. In the overview editor, click the Business Rules navigation tab.
  3. On the Business Rules page, select the Entity-Level Triggers node, and click the Create New Trigger icon.
  4. Select the appropriate trigger point from the Type dropdown list.
  5. Enter a Groovy expression.
  6. Click the Failure Handling tab and enter or select the error message that will be shown to the user if the expression fails.
See Creating Validation Error Messages to read more on creating validation error messages.
When a Groovy expression is evaluated at runtime, it is assumed to be untrusted. For more information, see What You May Need to Know About Untrusted Groovy Expressions.

11.6.2 What Happens When You Create an Entity-Level Trigger

When you create a trigger, a <Trigger> tag is added to the entity object’s XML file, as shown in the following example.

 <Trigger
    Name="BeforeUpdate">
    <validation:ExpressionValidationBean
      Name="BeforeUpdateExpression0"
      OperandType="EXPR"
      Inverse="false">
      <validation:TransientExpression
        Name="ValidationRuleScript"
        trustMode="untrusted"
        hasReturn="false"
        CodeSourceName="ItemEORow"/>
    </validation:ExpressionValidationBean>
 </Trigger>

11.7 Using View-Level Triggers

A view object level trigger is an expression, for example a Groovy expression, that executes in response to a given trigger point in the view object’s lifecycle. .

Triggers provide the ability to register the business logic implementation with view object’s lifecycle events.

BeforeExecute

The BeforeExecute trigger executes before the view object’s query executes. Use this trigger to:
  • Add or remove view criteria applied to the view object.

  • Set or change view criteria bind parameters.

  • Set or change WHERE clause bind parameters.

  • Change Order By criteria.

  • Perform validations, such as if the value of a criteria starts with “%” or “_”, then raise exceptions.

  • Prevent a blank query from executing.

Criteria

The Criteria trigger executes whenever a WHERE clause is constructed for a view criteria. This trigger can be used to take complete control of the clause generated for a view criteria instead of relying on the framework to generate a clause.

CriteriaItem

The CriteriaItem trigger executes whenever a WHERE clause is constructed for a view criteria item. This trigger is used to supply a custom clause for a view criteria item instead of relying on the framework to generate the clause.

BeforeCreate

The BeforeCreate trigger is used to add logic that executes before a new view object row is created. It can be used to control the view row creation operation based on conditions.

Modify

The Modify trigger executes whenever a view object attribute is modified. You can specify for which view object attribute this trigger executes.

11.7.1 How to Implement Business Rules Using View-Level Triggers

You can use the Groovy programming language to implement ADF Business Components view-level triggers that interact with the custom data source.

It may be helpful to understand declarative validation in ADF. For more information, see Additional Functionality for Declarative Validation. To add a view-level trigger:
  1. In the Applications window, double-click the view object you want to add a trigger.
  2. In the overview editor, click the Business Rules navigation tab.
  3. On the Business Rules page, select the view-level Triggers node, and click the Create New Trigger icon.
  4. From the Add Trigger dialog box, select the appropriate trigger point from the Type dropdown list.
  5. Enter a Groovy expression in the Trigger Definition tab.
  6. Click the Failure Handling tab and enter or select the error message that will be displayed to the user if the expression fails.
    See Creating Validation Error Messages for details about creating custom validation error messages. When a Groovy expression is evaluated at runtime, it is assumed to be untrusted. For more information, see What You May Need to Know About Untrusted Groovy Expressions.

11.7.2 What Happens When You Create a View-Level Trigger

When you a create an ADF Business Components view-level trigger, the application creates a <trigger> tag in the view object’s XML file.

The application creates a <trigger> tag in the metadata of the view object as well as populate the .bcs file associated with the view object.

<Trigger 
        Name="BeforeExecute">
        <validation:ExpressionValidationBean
        Name="BeforeExecute_Rule_0"
  OperandType="EXPR"
  Inverse="false">
        <validation:TransientExpression
        Name="ValidationRuleScript"
        trustMode="untrusted"
        hasReturn="false"
        CodeSourceName="DeptView"/>
        </validation:ExpressionValidationBean>
 </Trigger>

The application populates the .bcs file associated with the view object with the trigger expression.

package model
import oracle.jbo.script.annotation.TriggerExpression;
@TriggerExpression(triggerType="BeforeExecute", name="BeforeExecute_Rule_0")
def BeforeExecute_Rule_0_ValidationRuleScript_Trigger()
{
        test
}

11.8 Using Groovy Expressions For Business Rules and Triggers

You can use Groovy expressions to build business rules and triggers. These expressions are stored as part of the ADF entity object’s XML definition as well as the .bcs file associated with the entity object.

Groovy expressions are Java-like scripting code stored in the XML definition of an entity object and the .bcs file associated with the entity object. Because Groovy scripts are stored in the .bcs file, you can change the expression values in this file.

For more information about using Groovy script in your entity object business logic, see Using Groovy Scripting Language with Business Components.

11.8.1 How to Reference Entity Object Methods in Groovy 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.

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 the following example.

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 execute them all, one of them being executed twice, as shown in this example.

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 following diagnostic output in the log window:

## 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 third isNewRow() method takes an argument, then you must call them like methods using their complete name.

11.8.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 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 Using Groovy Expressions For Business Rules and Triggers.

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

To validate using a true/false expression:

  1. In the Applications window, 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 dropdown of the plus icon to select New Validator.
    • 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 Expression.
  4. Enter a validation expression in the Expression field.
  5. Optionally, click the Validation Execution tab to enter criteria for the execution of the rule, such as dependent attributes and a precondition expression in the Expression field. For more information, see 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 Creating Validation Error Messages.
  7. Click OK.

The following Groovy script example validates account numbers based on the Luhn algorithm, a checksum formula in widespread use.

@ValidatorExpression(name="PaymentOptionIdRule0", attributeName="PaymentOptionId")
def PaymentOptionId_PaymentOptionIdRule0_ValidationRuleScript_ValidationRule()
{
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;
}

11.8.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. The following example shows a DateOrdered attribute in an entity object. The Groovy expression is wrapped by a <validation:ExpressionValidationBean> tag. The Groovy script is enclosed in OrdEO.bcs file as indicated by CodeSourceName="OrdEORow” in the XML definition.

<Attribute
  Name="DateOrdered"
  ColumnName="DATE_ORDERED"
  SQLType="TIMESTAMP"
  Type="java.sql.Date"
  ColumnType="DATE"
  TableName="S_ORD">
  <DesignTime>
    <Attr Name="_DisplaySize" Value="7"/>
  </DesignTime>
  <validation:ExpressionValidationBean
    Name="DateOrderedRule0"
    OperandType="EXPR"
    Inverse="false">
    <validation:TransientExpression
      Name="ValidationRuleScript"
      trustMode="untrusted"
      CodeSourceName="OrdEORow"/>
  </validation:ExpressionValidationBean>
</Attribute>

Figure 11-6 shows the validation expression in the Edit Validation Rule dialog.

Figure 11-6 Validation Expression for Date Ordered Attribute



11.9 Triggering Validation Execution

ADF Business Components allows you to define attribute level validations, as well as entity-level validations.

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 How to Specify Which Attributes Fire Validation.

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

11.9.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 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 Additional Functionality for Declarative Validation.

To specify which attributes fire validation:

  1. In the Applications window, 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 SummitADF application workspace, the OrdEO entity object has an entity-level validator that requires the DateShipped attribute to be later than the DateOrdered attribute. As shown in Figure 11-7, this validator is set to be executed on the entity object only when either the DateShipped attribute or the DateOrdered attribute has been changed.

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

Description of Figure 11-7 follows
Description of "Figure 11-7 Triggering attributes on the Validation Execution tab of the Edit Validation Rule dialog"

11.9.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 a <validation:OnAttributes> tag to the validator definition in the entity object's XML file. The following example shows the XML code for the entity-level validator for the OrdEO entity object in the core Summit ADF sample application.

<validation:CompareValidationBean
   Name="OrdEO_Rule_0"
   ResId="oracle.summit.model.entities.OrdEO_Rule_0"
   OnAttribute="DateShipped"
   OperandType="ATTR"
   Inverse="false"
   CompareType="GREATERTHANEQUALTO"
   CompareValue="DateOrdered">
   <validation:OnAttributes>
     <validation:Item
       Value="DateShipped"/>
     <validation:Item
       Value="DateOrdered"/>
   </validation:OnAttributes>
</validation:CompareValidationBean>

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

11.9.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 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 Additional Functionality for Declarative Validation.

To specify entity-level or transaction-level validation:

  1. In the Applications window, 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.

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

11.10 Creating Validation Error Messages

ADF Business Components allows you to create validation error messages by entering text that provides self-explanatory information to the end-user on the problem and troubleshooting tips.

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

11.10.1 How to Create Error Messages for Validators and Triggers

When you create or edit a validation rule or trigger, you can 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 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 Additional Functionality for Declarative Validation.

To create error messages for validators or triggers:

  1. In the Applications window, double-click the desired entity object.
  2. In the overview editor, click the Business Rules navigation tab, select a validation rule or trigger, and click the Edit icon.
  3. In the Edit 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:

    Triggers and Script Expression validators allow 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 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 11-8 shows the failure message for a validation rule in the OrdEO entity object that contains message tokens. For more information on this feature, see How to Embed a Groovy Expression in an Error Message.

  6. Click OK.

11.10.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 document entry for the validator. For example, The following example shows a message bundle where the NAME_CANNOT_BEGIN_WITH_U key appears with the error message for the default locale.

Resource bundles can be created for your applications either as a list resource bundle (as shown in the sample below), as a properties bundle, or as an XLIFF resource bundle. For more information about using translatable strings in a resource bundle, see Working with Resource Bundles.

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

11.10.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 Setting the Severity Level for Validation Exceptions.

11.10.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 11-8 shows the failure message for a validation rule in the OrdEO entity object that contains message tokens.

Figure 11-8 Using Message Tokens in a Failure Message

This image is described in the surrounding text

The expressions shown in Figure 11-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. For example, you can use the Groovy expression newValue to return the entered value.

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 the following example, which shows an expression in the error message for the List validation rule for the PaymentTypeId attribute in the OrdEO entity object.

cr = CustomerEO.CreditRatingId
ratings = [1, 2]
if (cr  in ratings)
{return true}
else
{return false}

For more information about accessing business components objects using Groovy, see Using Groovy Scripting Language with Business Components.

11.11 Setting the Severity Level for Validation Exceptions

ADF Business Components allows you to set severity levels for validations exceptions as Informational Warning or Error. The latter level if set does not allow the end-user to proceed without fixing the issue.

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.

When the severity level is set to Informational Warning, the error message is presented with a warning icon rather than an error icon and after acknowledging the warning, you can proceed to save the changes.

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 Applications window, double-click the desired entity object.
  2. In the overview editor, click the Business Rules navigation tab.
  3. 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.
  4. In the Edit/Add Validation Rule dialog, click the Failure Handling tab and select the option for either Error or Informational Warning.
  5. Click OK.

11.12 Bulk Validation in SQL

ADF Business Components provides bulk validation facility to improve performance of batch-load applications. The validation is applied on primary keys, alternative keys and foreign keys.

To improve the performance of batch-load applications, such as data synchronization programs, Oracle ADF 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.