ADF BC now provides integrated support for Groovy, a dynamic scripting language for the Java platform standardized in JSR 241. Groovy in ADF Business Components is dynamically compiled and evaluated at runtime. The JDeveloper/ADF 11.1.1.0.0 Technology Preview release is using the Groovy 1.0 release. The primary benefits of the ADF Business Components Groovy integration are:
- Customization - because it is dynamically compiled, Groovy script can be stored inline in our XML and is eligible for customization
- Simplification - Groovy supports object access via dot-separated notation
so we can support syntax like:
Salary * 0.10
instead of
((Number)getAttribute("Sal").multiply(new Number(0.10))
in Java in a calculated field expression, or syntax like:
PromotionDate > HireDate
instead of
((Date)getAttribute("PromotionDate")).compareTo((Date)getAttribute("HireDate")) > 0
in a validation rule.
You can use Groovy script expressions in the following different places in ADF Business Components:
- Validation - you can use a Groovy script (that returns true or false) for declarative validation.
- Validation Error Messages - you can use Groovy expressions to substitute the named tokens (e.g. "The value {val} is not legal."}) in the error message
- Bind Variables - you may define the value for a bind variable using a groovy script expression
- Default Values
- View Criteria
- View Accessor Bind Variable Values - you may supply bind variable values in a view accessor using Groovy script
- Attributes - you may base a transient attribute on a Groovy script
- Attribute Default Values - you may define a default value expression on an attribute using groovy script
Keywords and Available names
The current object is passed in into the script as the 'this' object so to reference any attributes inside the current object, simply use the attribute name. For example, in an attribute-level or entity-level Groovy Script Expression validator, to refer to an attribute named "Ename", the script may say simply reference Ename.
There is one top level reserved name adf to get to objects that the framework makes available to the groovy script. Currently these objects include:
- adf.context - to reference the ADFContext object
- adf.object - to reference the object on which the expression is being applied.
- adf.error - in validation rules, to access the error handler that allows the validation expression to generate exceptions or warnings
All the other accessible member names come from the context in which the script is applied:
- Bind Variable - the context is the variable object itself. You can reference the structureDef property to access other information as well as the viewObject property to access the view object in which the bind variable is defined.
- Transient Attribute - the context is the current entity or view row. You can reference all attributes by name in the entity or view row in which it appears, as well as any public method on that entity or view row. To access methods on the current object, you must use the object keyword to reference the current object like this object.yourMethodName(...) The object keyword is equivalent to the this keyword in java. Without it, in transient expressions, the method will be assumed to exist on the dynamically-compiled Groovy script object itself.
- Expression Validation Rule : the context is the validator object (JboValidatorContext) merged with the entity on which the validator is applied. You can reference keywords like:
- newValue - in an attribute-level validator, to access the attribute value being set
- oldValue - in an attribute-level validator, to access the current value of the attribute being set
- source - to access the entity on which the validator is applied in order to invoke methods on it (accessing simply accessing attribute values in the entity does not require using the source keyword)
Usage Notes
This scripting logic works like JSF Expression Language (EL) in the sense that you can use a dot-separated path to reference properties of an object and its nested objects. However one big difference is that if a Java object implements the java.util.Map interface, then only the map lookup is performed (instead of the bean style property lookup). For Maps that extend ADF's JboAbstractMap class however, you get the same EL-style behavior: map lookup first followed by bean lookup. Additional usage notes include:
- All Java methods, language constructs and groovy language constructs are available in the script.
- You can use built-in aggregate functions on ADF RowSet objects by referencing the functions:
sum(String attrName) -- e.g. sum("Salary") count(String attrName) avg(String attrName) on a RowSet object where expr can be any groovy expression that returns a numeric value (or number domain).
- Use the return keyword just like in Java to return a value, unless it's a one liner expression in which case the return is assumed to be the result of the expression itself (like "Sal + Comm" or "Sal > 0").
- Use the ternary operator to implement functionality like SQL's NVL() function. For example: Sal + (Comm != null ? Comm : 0)
- Do not use { } to surround the entire script. Groovy treats { as a beginning of a Closure object - See groovy documentation for more on Closures.
- Any object that implements oracle.jbo.Row, oracle.jbo.RowSet or oracle.jbo.ExprValueSupplier is automatically wrapped by the ADF runtime into a Groovy "Expando" object to extend the properties available for those objects beyond the bean properties (to enable easy reference to ADF row properties even if no Java class is generated, and as a way to avoid introspection for most used names).
Examples
This is a simple example of a view-object bind variable default expression that references the value of a key named FunctionalRole from the ADFBC Session's user data hashtable:
viewObject.DBTransaction.session.userData.FunctionalRole
This is a simple example of an entity-level Groovy script expression validator. The strings ExcGreaterThanApplicationLimit, WarnGreaterThan5000, and ExcTooLow are message bundle keys to error/warning messages.
if (Sal >= 5000){ /* * If Sal is greater than a property value set on the custom * properties map on the root AM raise a custom exception else * raise a custom warning */ if (EmpSal >= source.DBTransaction.rootApplicationModule.propertiesMap.salHigh) { adf.error.raise("ExcGreaterThanApplicationLimit") } else { adf.error.warn("WarnGreaterThan5000") } } else if (Sal <= 1000) { adf.error.raise("ExcTooLow") } return true
2:21:56 PM
|