Java By Exception for Business Rules in ADF BC

Oracle ADF Business Components 11g has many new features for declarative
business rules, allowing a “Java By Exception” approach. When can and should you use these declarative features,
and when and how should you use Java to implement business rules in ADF
BC?

 

What are Business Rules?

Let me first explain what I mean by business rules in this context.

Business rules are used to preserve data integrity, to prevent inconsistent data from being entered into the database. They are checks and/or data corrections you want to perform in your entity
objects, triggered by an insert, update or delete of certain data.

The most common ones are validation rules or constraints: if the
data changes do not satisfy a certain integrity rule, you return an
error. For example: the End Date may not be before the Start Date. Another category of business rules is change event rules:
if a certain change is made, you automatically want another change
in the data to be made as well. For example: automatically converting a Code to uppercase (so that the integrity rule that a Code must be uppercase is implicitly maintained).

The white paper
Business
Rules
in
ADF
BC

defines business rules as follows (in the intro of section 6,
"Business Rule Classification Scheme"):


A business rule is either

  • a restriction that applies to the state of the system, the
    change of the system state or the authorized use of the system,

  • or an automatic action that is triggered by a change to the
    system state
Photo credit: Naval Safety Center

My Preferred ADF BC 11g techniques for Business Rules

In Oracle JDeveloper 11g, ADF BC offers several new features for
declarative validation rules support (see also the
JDeveloper
11g
New
Features
list
):

  • Control when a validation rule is executed by specifying a conditional
    execution expression or triggering attributes (or by deferring the execution to transaction level)
    New!
  • Create parameterized error messages and warnings saved in external
    resource bundles
    New!
  • New validation rule types (in the below lists they are tagged with
    New!
    )

Let me describe the ADF BC techniques (with links to relevant sections in the
Fusion
Developer’s
Guide
for
ADF
or to paragraphs below)
that
I
refer
to
later
in
this
post,
in
order
of
preference.
In
fact,
I
have
two
lists
of
preferred
techniques,
depending
on
the
question:
Should the rule be implemented for more than one entity?

Preferred Techniques for Rules that apply to Multiple Entities

If the answer is
Yes, the rule should be implemented in more than one entity, then
my preferred techniques are:

  1. Domain, see
    Section
    34.1
    Creating
    Custom,
    Validated
    Data
    Types
    Using
    Domains
    .
  2. Custom Validator, also known as Registered Rule, where you code a new validator type in Java, which you can then
    declaratively assign to an entity (or entity attribute). See How to create a Custom Validator.
  3. Overriding superclass method
    in the EntityImpl java class at the base class level (see
    Section
    33.2
    Creating
    a
    Layer
    of
    Framework
    Extensions
    ,
    which you should do before creating any individual Entity Objects),
    using separate classes and interfaces for the actual business logic (see
    How to apply OO principles in EntityImpl).

Preferred Techniques for Rules that apply to Individual Entities

If the answer is
No, the rule should be implemented in only one entity, then my
preferred techniques are:

  1. Entity, Attribute, or Association Property, for example the Mandatory property of an attribute, or the History Column feature for tracking creation / last update info. You can even create your own History Type.
  2. Declarative Validation Rule that doesn’t require any Groovy or Java
    coding (for more information see
    Section 7.3,
    Adding Validation Rules to Entity Objects and Attributes
    ). If you need to postpone the calling of the rule to commit time,
    set “Defer execution to transaction level” when adding the rule to an entity or attribute.

    • Collection
      New!
      (validates based on aggregate values in a collection)
    • Compare
      (performs a logical comparison between the attribute and a value)
    • Key Exists
      New!
      (checks cache and database to see if value exists as a key in a
      certain entity, useful for logical Foreign Keys that are not checked in the database)
    • Length
      (compares the character or byte length of an attribute value to the
      specified size)
    • List
      (compares an attribute against a list of values that can be
      specified in several ways)
    • Range
      (tests for attribute values within specified minimum and maximum
      values)
    • Regular Expression
      (compares an attribute value against an expression mask)
    • UniqueKey
      New!
      (business-logic tier equivalent of a unique constraint in the
      database)
  3. Script Expression
    New!
    (declarative validation rule used for creating Groovy validation
    expressions). Applicable if
    the Groovy syntax and constructs, see
    Section
    3.6
    Overview
    of
    Groovy
    Support
    ,
    are powerful enough to implement the rule, and the expression is
    limited in length.
  4. Method
    (declarative validation rule used to call any method defined by the
    entity object that accepts a parameter of the appropriate type and
    returns a boolean value, see
    Section
    8.2
    Implementing
    Validation
    and
    Business
    Rules
    Programmatically
    ). If the method for this rule is more than a few lines of Java code,
    I prefer to implement the rule as a Custom Validator, so it can be implemented in a separate class
    with several methods.
  5. Custom Validator, also known as Registered Rule, where you code a new validator type in Java, which you can then
    declaratively assign to an entity (or entity attribute). See How to create a Custom Validator.
  6. Overriding superclass method
    in EntityImpl java class, at the level of an individual entity
    object (see
    Section
    8.2
    Implementing
    Validation
    and
    Business
    Rules
    Programmatically
    ), using separate classes and interfaces for the actual business logic
    (see
    How to apply OO principles in EntityImpl).

Now these lists need a little explanation. Why do I prefer these,
and when can or can’t you use one of these techniques?

Why
these
techniques?

My
preferences
for
certain
techniques
are
based
on
the
following
assumptions:

  • XML-based is preferred to code-based
    (be it Groovy or Java code). There are several reasons for this:

    1. One 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. (Quote from
      Section
      7.1
      Introduction
      to
      Declarative
      Validation
      .)
    2. Another benefit of declarative validation, is the traceability of
      the rules. It is easier to see which rules are implemented in a
      certain entity. Just open an entity definition, go to the
      Validations, and see which declarative rules are listed. Even if
      not all rules can be listed there, it is a good starting point.
    3. In a later version of JDeveloper 11g, when MDS (Meta Data Services)
      is fully enabled, it will be possible to customize these XML-based
      business rules without having to change the source files (see
      chapter 33 of the
      draft
      developer’s
      guide
      of
      a
      JDeveloper
      11g
      Preview
      release
      ).
    4. The recently started
      ADF
      Methodology
      Group

      discussed the term "Java By Exception" (see
      Extreme
      Reusability
      , an ADF development methodology proposed by Avrom Roy-Faderman).
      Applications are supposed to be entirely declarative,
      except
      for those few cases where declarative uses of the framework do not
      cover needed functionality. The idea is that you can harness the
      power of Java when you need it, and avoid the complexity at other
      times. At the ADF Methodology symposium, Steve Muench, very
      appropriately, pointed out that ADF, as well, is a "Java by
      exception" framework.
  • Generalize, Push Up, and Customize
    : Avrom’s
    Extreme
    Reusability

    describes this practice as: Rather than writing a piece of Java code
    tailored to a highly particular need, consider the possibility of
    generalizing
    the code and
    pushing it up
    the class hierarchy to a custom framework class, allowing declarative
    customization
    of specific cases.
    I agree with this practice: if you expect that the
    functionality of the Java code is probably going to be needed in another
    place as well, possibly with a small variation, generalize it. This principle also implies that even if
    you can implement a rule with a declarative validator, but it needs to be done in more than one entity,
    then you still should create a generalized implementation so you avoid repeatedly entering the same properties like error message code, validator subtype, etc.
    Repetitive work increases the probability of mistakes, and the result is hard to maintain.
  • Use Object Oriented Design Principles
    when coding business rule logic in Java (I took these from the
    first chapter of the excellent book Head
    First
    Design
    Patterns
    ):
    1. Encapsulate what varies, translated to: put the business
      rule logic in a separate class – see How to apply OO principles in
      EntityImpl
    2. Program to interfaces, not implementations, translated to:
      let the rule class implement an interface which you call
      from the EntityImpl – see How to apply OO principles in
      EntityImpl

    This avoids very large EntityImpl classes, in which it is hard
    to keep track of what was generated by ADF BC and what was added
    by you. If you follow these principles, there are only a few
    superclass methods that are likely to be customized (see
    Section
    8.1
    Introduction
    to
    Programmatic
    Business
    Rules
    ).

    Cover of Head First Design Patterns book

When to use what technique?

The preferred techniques mentioned above may or may not be possible,
depending on the type of business rule you need to implement. Besides the decision if the rule should
be implemented for more than one entity or not, what matters as well
is the
complexity
of the rule, and at which point in the ADF Entity Object’s
validation cycle
it needs to be triggered.

Triggering moment

What you need to remember is that all techniques, except coding directly
in the EntityImpl class, can only be called at the time a single Entity
row is
validated, or at the time all Entity rows are
committed
(the latter occurs if you defer the execution to transaction level, using
a setting in the Entity "Add Validation Rule" dialog). That is the equivalent of overriding the entity superclass methods
validateEntity or beforeCommit.

However, sometimes you need to trigger the rule from the superclass methods
doDML, remove, or some other method. The Rule Classification Scheme of the
Business
Rules
in
ADF
BC
white
paper

can help: for the rule types "Delete", "Collection, no
parent", "Collection within parent", "Change event
with DML", and "Change Event without DML", it might not be possible to trigger them at validate or commit time.

Complexity of the rule

Furthermore, validation rules are often not suitable for change event rules
(that trigger a data change in some other attribute or entity). It might
interfere with the Validation Cycle (see
Section
7.2
Understanding
the
Validation
Cycle
).

The complexity of the rule determines if it is possible to implement
it using one of the most preferred techniques, like a Compare
validator or a Range validator. If that is not possible, it might be
possible to implement it using a Groovy Script validator. If that is
not possible, it might be possible to implement it with a Method Validator with a small number of lines of Java code in the method,
etcetera.

Algorithm to determine Best Rule Technique

If you apply all of these guidelines, you have the following summary
algorithm for determining the best rule technique:

Algorithm for choosing ADF BC 11g Business Rule Technique


How to create a Custom Validator

See the Fusion
Developer’s Guide for Oracle Application Development Framework
Section
34.10:
Implementing
Custom
Validation
Rules
. Essentially you create a
new Java class that extends AbstractValidator and implements the JboValidatorInterface. This forces you to implement a method validate(JboValidatorContext). You can specify custom rule properties for the things that vary
if you need to implement this rule for more than one entity or attribute.

If the rule must be triggered at commit time as opposed to validate time, you must also
implement the
JboTransValidatorInterface. This forces you to implement a method validateMany in addition to validate, but in our test case it was never called, even if you set the “Defer execution to transaction level” when assigning the rule to an entity or attribute.
Still, a logical implementation of this method would be to loop over all JboValidatorContexts and call validate for each:

    public void validateMany(ArrayList valCtxs) {
        JboValidatorContext evObj;
        for (int i = 0; i < valCtxs.size(); i++)
        {
           evObj = (JboValidatorContext) valCtxs.get(i);
           validate(evObj);
        }
    }

When you have written the Java class, you must register it as a rule in your Model project, and then you can declaratively assign it to one or more entities, possibly setting some entity-specific properties for the rule. Those properties can be exposed simply by creating getters and setters for them in the Java class.

Note: if the rule should be applied to all Entity Objects, without any specific properties to configure for each individual entity, then it is easier to use the technique of Overriding a method in
EntityImpl
, so you don’t have to do any work in the individual entities.

Note 2: You could also use the JboValidatorInterface when the trigger time is not validateEntity or commit,
but it requires instantiating a JboValidatorContext like this:

        JboValidatorInterface businessRule = new MyCustomValidator();
        JboValidatorContext entityContext =
            new JboValidatorContext(JboValidatorContext.TYP_ENTITY_OBJECT,
                                    this, getEntityDef().getFullName(), null,
                                    null, this);
        businessRule.validate(entityContext);

I find this less intuitive then the technique described below, and you don’t have the added value that declarative rules have like traceability, bundling exceptions, and allowing changes through MDS. Besides, this codes gives a compiler warning, and it is not clear to me what the alternative for the deprecated constructor is:

   constructor JboValidatorContext(int, java.lang.Object, java.lang.String,
   oracle.jbo.AttributeDef, java.lang.Object, java.lang.Object) has been deprecated

It works fine, though, so if you like it you can use this approach instead of the one described in
How to apply OO Principles in EntityImpl
.

Thank you Steve Muench
and Jan Kettenis
for helping me to position this technique in 11g.


How to apply OO Principles in EntityImpl

This paragraph explains how I applied the Object Oriented Design
Principles "Encapsulate what varies" and "Program to
interfaces, not implementations", with the help of my colleague
Gaurav Malhotra. I found that it helps separate out the rule implementation code from
the Business Components classes, and clarifies the communication between
the classes by using interfaces for different types of rules, if you want to use the technique
of overriding a method in EntityImpl. In fact, the
Custom Validator technique (see How to create a Custom Validator) also applies these OO principles.

Note: if the rule applies to multiple entities but not exactly the same for each entity, you can use Custom Properties in the individual entities to configure your business rule.

Take the rule code out of the EntityImpl class

One of the most complex rules we had in a large project involved a
private helper class, several static final constants, and several
helper methods that need to be called several times. So you can
imagine that it is not a good idea to put all that code in the
EntityImpl class, mixed in with the code for other rules and/or the
ADF BC framework generated code.

Borrowing a phrase from
Antonio
García’s
description
of
the
Strategy
Pattern
,
it is much simpler to keep track of them if each behaviour
(in our case business rule)
is a separate class, and not buried in the body of some method.
That
is
how
I
interpreted
the
principle
"Encapsulate
what
varies".

Inject the Entity Row

Now, in the business rule logic we probably have to call several
EntityImpl methods for the row that triggered the rule, like the entity’s getters, or the superclass generic getAttribute method.
How do you do that if the rule logic is in a separate class?

The answer is:
inject the Entity row into the rule class, using a setEntity
method. The rule class can
then call entity
methods by coding
getEntity().someMethod(). This way you can also retrieve values of Custom Properties of Entities in case of generic rules that apply to multiple entities: getEntity().getEntityDef().getProperty(customPropertyName).

Define contract with caller using an Interface

Then, apply the "Program to Interfaces" principle by specifying
an
interface that defines which rule class methods should be callable
from the EntityImpl class and which not. If you have multiple rules that
have to be implemented in the EntityImpl, you can probably re-use the same
interface for several rules.

An example of such an interface is the general-purpose
EntityRule
interface (note the use of a Java 5
generic
method
):

public interface EntityRule<T> {
    public void setEntity(T entity);
    public void process();
}

An implementation of this interface might be:

public class MyComplexRuleImpl implements EntityRule<MyEntityImpl>

You call the rule by coding in the appropriate method of your
MyEntityImpl class:

     EntityRule myComplexRule = new MyComplexRuleImpl();
     myComplexRule.setEntity(this);
     myComplexRule.process();

Of course you can have multiple RuleImpl
classes each representing a different
Entity Rule, which can be called from
different places in the EntityImpl.

Benefits of this technique

Using
this
approach
you
can
give
complex
rules
their
own
class,
while
still
allowing
calls
to
framework
methods
like
the
Entity’s
getters.
In
the
rule
class
you
can
throw
an
exception
if
the
validation
fails.
The
use
of
an
interface
makes
it
clear
how
to
call
such
a
rule,
without
knowing
the
inner
workings
of
the
rule.

Link to the original site

Tags: , , , , , , , , , , , , , , , , , , , ,

Related posts

Leave a Reply