Oracle® Fusion Applications Developer's Guide 11g Release 7 (11.1.7) Part Number E15524-08 |
|
|
PDF · Mobi · ePub |
This chapter describes how to define your defaulting and derivation logic, how to use Groovy (a Java-like scripting language), and how to use Oracle Application Development Framework (Oracle ADF) validators and convertor hints instead of using messages.
This chapter includes the following sections:
Section 6.1, "Understanding Entity Object Defaulting and Derivation Logic"
Section 6.3, "Using Oracle ADF Validators and Convertor Hints"
Defaulting logic means assigning attribute values when a row or entity object is first created or refreshed. (The logic is not re-applied when the entity object is changed.) Defaulting is achieved either declaratively in the default field of the attribute or programmatically by adding code to the EOImpl
.
Derivation logic means assigning attribute values when some other attributes have changed. Derivation is achieved either declaratively in the default field of the transient attribute or by using a validator, or programmatically by adding code to the EOImpl
.
Figure 6-1, illustrates what you need to consider when determining whether to implement defaulting or derivation logic.
When implementing defaulting or derivation logic, you should also consider the following factors:
Always assign a valid value to an attribute.
You should know what the valid values are and there is no reason why you would want to assign invalid values. The end users do not set these values and would have no idea why they would be invalid.
Always use initDefaultExpressionAttribute
for calculations that cross containerships. Use initDefault
for literal or statically computed values.
Instead of writing code in one of the triggering points during validation or the posting cycle to achieve derivation logic, you can use a method validator or an expression validator.
When you want the derivation logic to be customizable, the validator approach is preferable. When using this approach the validation result should always be true because this is not really a validation logic. You should also make sure that the attribute avoids an infinite loop due to validation.
You can call either setAttribute(setter)
or populateAttribute
to assign the default or derived value to an attribute.
When you call setAttribute(setter)
, the logic in the setter is fired and the validation logic is also executed. This does not happen when you call populateAttribute
.
In most cases, using populateAttribute
is sufficient because you should always assign a valid value and therefore do not need to fire validation logic. However, you may want to call the setter if there is additional logic such as cascading derivation in the setter.
Tip:
When you call setAttribute(setter)
make sure that you do not cause an infinite loop. This may happen due to the attribute and the entity becoming invalid and causing the validation logic to refire.
You can call beforeCommit
as well as setAttribute(setter)
, validateEntity
, and prepareForDML
if your derivation logic involves multiple entities that are not composite.
For composite object, you can just put your logic either in validateEntity
or prepareForDML
of the parent EOImpl
.
Oracle ADF handles the propagation of the foreign key ID if there is an association between two entities. This is where the association is defined from the parent entity object to the child entity object, and when the detail entity object is created from the association accessor of the parent entity object. For example:
Row parentRow = ....RowIterator ri = (RowIterator)parentRow.getAttribute("<childEOAccessorName>"); Row childRow = r1.createRow();
Similarly, if there is a view link between two view objects, the framework also handles the foreign key propagation when the child view row is created via the view link accessor of the parent view row.
List of Values (LOVs) also perform derivation. However, this is at the view object level and you should not place business logic (including derivation) at this level.
A LOV should only be used on the user interface (UI) to show a list of valid values or as a service to derive the foreign key ID based on the foreign alternate key.
ADF Business Components now provide integrated support for Groovy (a Java-like scripting language), which is dynamically compiled and evaluated at run-time. Because it is dynamically compiled, Groovy script can be stored inline in the XML and is eligible for customization. Groovy also supports object access via dot-separated notation, which means you can now use syntax such as empno
instead of getAttribute(EMPNO)
.
You can embed Groovy script into various declarative areas, including:
Validation - Use a Groovy script that returns true or false for declarative validation.
Validation Error Messages - Use Groovy expressions to substitute the tokens in the error message.
Bind Variables - Define the value for a bind variable using a Groovy script expression.
View Accessor Bind Variable Values - Supply bind variable values in a view accessor using Groovy script.
Attributes - Base a transient attribute on a Groovy script. (Currently no UI support).
Attribute Default Values - Define a default value expression on an attribute using Groovy script. (Currently no UI support).
Variables - Define a variable on an entity whose value is computed using Groovy script. (Currently no UI support).
As with the original Script implementation, the current object is passed into the script as "this" object. Therefore, to refer to any attribute inside the current object simply use the attribute name. For example, in an attribute or validator expression for an entity, to refer to an attribute named Ename
, the script may say return Ename
.
There is one top-level reserved name, adf
, which is used to get to objects that the framework makes available to the Groovy script. Currently, these objects are:
ADFContext
(adf.context
)
Object on which the expression is being applied (adf.object
)
Error handler that lets the validator generate exceptions or warnings (adf.error
)
All other names come from the context in which the script is applied:
Variable - gets the Variable, structureDef
in which it is contained via getStructureDef
method on VariableImpl
.
Transient Attribute - gets the Entity or ViewRow as its context so that all attributes in the entity are accessible by name. Any method on the entity may be invoked by directly calling the entity method as if you were writing a method in the entity subclass.
Tip:
Only public methods on the entity are available to call.
You also need to call the method using the "object" keyword, such as adf.object.createUnqualifiedRowSet()
. The "object" keyword is equivalent to the "this" keyword in Java. Without it, in transient expressions, the method is assumed to exist on the script object itself, which it does not.
Validator - gets the Validator context JboValidatorContext
merged with the Entity on which the validator is applied. This is done so that you can use:
newValue
and oldValue
to get to the values being validated
sourceRow
to get to the Entity or ViewRow on which the validator is applied
All attribute names in the Entity or ViewRow as top-level names
Groovy scripting logic is similar to Expression Language (EL) because you can use a "." separated path to get to a value inside an object. Note that if a Java object implements Map, only the map lookup is performed instead of the bean style property lookup. However, for Maps that extend JboAbstractMap
you get the same EL behavior, which is map first followed by bean lookup. This is due to the implementation of get
in JboAbstractMap
.
Consider the following information:
All Java methods, language constructs, and Groovy language constructs are available in the script.
Aggregates are implemented by calling sum(expr)
, count(expr)
, or avg(expr)
on a RowSet
object where expr
can be any Groovy expression that returns a numeric value or number domain.
The defaultRowSet
reserved keyword has been removed. The method EntityImpl.createUnqualifiedRowSet()
replaces EntityImpl.getDefaultRowSet()
and can be accessed like any other public method in EntityImpl
.
Use the return keyword as you would in Java to return a value. That is, unless it is a single-line expression where the return is assumed to be the result of the expression itself. For example, "Sal + Comm"
or "Sal > 0"
.
Do not use {} to surround the entire script because Groovy interprets { to be the beginning of a Closure object.
Any object that implements oracle.jbo.Row
, oracle.jbo.RowSet
, or oracle.jbo.ExprValueSupplier
is wrapped into a Groovy Expando
object. This is to extend the properties available for those objects to beyond the bean properties and also as a way to avoid introspection for most used names.
The following are some examples of Groovy.
Instead of using the following SQL to achieve this:
SELECT C.ISO_COUNTRY_CODE ,C.COUNTRY_NAME FROM COUNTRY_CODES C WHERE LANGUAGE = SYS_CONTEXT('USERENV', 'LANG') ORDER BY C.COUNTRY_NAME
Create a bind variable and base its default value on the adf.context.locale.language
expression:
To get the attribute new value and label:
The above example uses the following two Groovy expressions:
newValue // This works because an attribute level validator has been created. source.hints.ProductId.label
and
source.structureDef.name+" of type "+sourceFullName
Example 6-1 is an example of an Object graph, custom error, and a warning:
Example 6-1 Object Graph, Custom Error, and a Warning
if (EmpSal >= 5000) { // If EmpSal is greater than a property value set on the custom // properties 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 (EmpSal <= 1000) { adf.error.raise("ExcTooLow"); } return true;
Example 6-2 is an example of how to average a collection.
Example 6-2 Averaging a Collection
attribute Number EmpSal : SAL { expressionValidator(expression = "newValue <= source.createUnqualifiedRowSet().avg(\"EmpSal\") * 1.2"); }
Example 6-3 is an example of a built-in or custom method call on the sourceObject
of this validator (sourcObject
being the Entity on which this validator is being run). isAttributeChanged(String)
is a public method on the EntityImpl
:
Example 6-3 Built-in or Custom method Call
if (source.isAttributeChanged("EmpSal") || source.isAttributeChanged("EmpComm")) { return true; } return false;
Example 6-4 is an example of getting to oldValue / newValue of an attribute on which this validator is applied:
Example 6-4 Getting to Old Value and New Value of an Attribute
return (oldValue == null || newValue < olValue * 1.2);
Example 6-5 is an example of accessing the Entity state relative to the database and relative to the last post operation.
Use adf.object.entityState
or adf.object.postState
.
To get the old value of an attribute (this works in the context of a transient Entity Object attribute):
Example 6-5 Getting the Old Value of a Transient Entity Object Attribute
index = object.getStructureDef().getAttributeIndexOf("Salary"); return object.getAttribute(index, oracle.jbo.server.EntityImpl.ORIGINAL_VERSION);
Example 6-6 is an example of the WHILE
construct as well as calling an accessor (Emp):
Example 6-7, Example 6-8, and Example 6-9 are examples of a simple transient attribute, how to sum or count a collection, and how to create a complex calculation of a bind variable value.
Example 6-7 Simple Transient Attribute
attribute transient Integer YearSal { transientexpression = "EmpSal * 12"; }
Example 6-8 Sum or Count a Collection
attribute transient Integer TotalSal { transientexpression = "object.createUnqualifiedRowSet().sum(\"EmpSal\")"; } attribute transient Integer TotalCount { transientexpression = "object.createUnqualifiedRowSet().count(\"EmpSal\")"; }
Example 6-9 Complex Calculation of a Bind Variable Value
query EmpView { entity Emp EmpUsage \*; where "SAL > :avgSal" orderby "1" bindingstyle "OracleName" variables { Double avgSal kind (where) { transientexpression { totSal = 0; empCount =0; fullVO = structureDef.getApplicationModule().createViewObject("_AvgSal", testp.kava.VO7.si33mt.EmpAllView"); empCount = 0; while (fullVO.hasNext()) { row = fullVO.next(); sal = row.EmpSal; totalSal = totSal + sal; empCount = empCount + 1; } fullVO.remove(); if (empCount > 0) { return (int)(totalSal / empCount); } else { return 0; } } } } }
Example 6-10 is of an entity-attribute XML fragment where a transient expression is used to provide a default value for that attribute. This expression is evaluated before the protected create
method of the entity is called. Example 6-11 is an example of an attribute defaulting with a transient attribute calculation expression.
Example 6-10 Attribute Value Defaulting
<Attribute Name="EmpComm" ColumnName="COMM" Type="oracle.jbo.domain.Number" ColumnType="NUMBER" SQLType="NUMERIC" TableName="EMP" > <TransientExpression><![CDATA[ if (EmpSal == null) { return null; } if (EmpDeptNum == null) { return 0; } if (EmpDeptNum > 40) { retune 500; } ]]></TransientExpression>
Example 6-11 Attribute Defaulting with a Transient Attribute Calculation Expression
<ViewAttribute Name="Total" IsUpdateable="false" AttrLoad="Each" IsSelected="false" IsPersistent="false" PrecisionRule="false" Type="java.lang.String" ColumnType="VARCHAR2" AliasName="View_ATTR" SQLType="VARCHAR"> <TransientExpression> <![CDATA[ if (Sal != null && Comm != null) { return Sal + Comm; } else { return Sal; } ]]> </TransientExpression>
An expression for an attribute can be defined using either the Attribute Editor (see Figure 6-2) or the Expression Editor (see Figure 6-3).
If you want to define a string literal instead of a Groovy expression, select Literal as the Value Type and enter the value as "My Literal Value".
To access the Expression Editor, click the Edit button located next to the Value text box.
Note:
Recalculate Expression is used to determine whether the expression must be recalculated as changes are made during run-time. The Recalculate option is hidden for persistent attributes. This is because Persistent attribute values are always updateable by the user and therefore, the expression of the attribute should only act as a default expression so recalculation is not necessary. For non-persistent attributes, the user can choose to always recalculate, never recalculate, or decide if recalculation is needed based on the evaluation of the recalculate expression.
In some situations, you should consider using Oracle ADF validators or converter hints instead of using messages.
Caution:
Oracle ADF validators and converter hints can only be used with messages stored in the Strings resource bundles. They cannot be used for messages stored in the Message Dictionary.
To ensure that the user has supplied the correct sort of value or a value in a valid range, input fields can be validated using an Oracle ADF validator. Values may be converted by a converter, for example to convert a string of input characters into a value of some other type such as a date or color.
To validate or convert an input value, you add the input component to the page and then add a validator or converter to that field. Each validator and converter has some messages associated with it:
Hints to display to the user details of what sort of value they need to enter.
Error messages to display if the user enters an invalid value.
For an individual component, you can explain the error to a user in terms relating to that specific input component by overriding the hints or by adding or overriding a detailed error message.
How to override an Oracle ADF validator or converter message with new text
You may not see any messages when you follow these steps to select the Application Messages resource bundle:
In JDeveloper, select the af validator tag in the UI page.
Open the Property Inspector.
Select the message attribute.
Select the text resource.
Select the Application Messages resource bundle.
In this case, you may need to override the default message from the validator. To do so, follow the procedure in "Displaying Hints and Error Messages for Validation and Conversion" in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.