This article serves two purposes:
- it extends the JHeadstart Application Generator to set UIX items to "required" based on a new custom Mandatory property – instead of driven from the Required property of the underlying Entity Object Attribute
- it illustrates how you can make simple extensions to the functionality of the JHeadstart Application Generator (release 10.1.2 and 10.1.2.1)
When an attribute is set to required – in the Entity Object
Attribute definition – it will be shown in the Web Interface with an asterisk; furthermore, UIX will enforce validation in the Client: that means that no changes in the record can be submitted as long as the mandatory attribute does not have a value.
This new functionality is particulary useful in cases where the Entity Object actually represents several subtypes – like the EMP Entity Object that represents Salesmen and Other employees: the Attribute Commission is not allowed for Other Employees
while it is mandatory for Salesmen. Since there are therefore Employees without a value for Commission, the Attribute cannot be made Mandatory at the EO level. However, in my ViewObject Salesmen (all Employees where job =’SALESMAN’) and the screen built on top of that ViewObject, I want the Commission item to be Mandatory.
I will show in this article how I can make JHeadstart generate required items for optional Entity Object Attributes.
The UIX expression for making a field required is very simple:
In a table layout form, required is indicated through an * in the Column Header:
<columnHeader>
<sortableHeader model="${ctrl:createSortableHeaderModel(bindings.Salesmen1,'Empno')}" text="Empno" required="yes"/>
</columnHeader>
JHeadstart also generates a JavaScript call that sets the Required Items in the table page when the page is first loaded; this ensures
validation upon submit:
<script>
<contents>
…
addRequiredRowItems(['Salesmen1:Empno']);
…
</contents>
</script>
In the Form Layout it is even simpler: simply use the required="yes" attribute on the UIX element.
However, JHeadstart has the UIX elements use the model attribute to derive many properties from way down in the ADF stack. From Steve Muench’s weblog I found:" … We learned more about the powerful UIX model attribute on UIX UI components that you can bind using familiar EL expressions. Once the UIX component knows what the binding object is, it automatically infers a number of that controls properties from the ADF binding object that’s specified via the EL expression like prompt, tooltip, updateability, whether or not its required, etc. …"
You can override the value retrieved for any UIX attribute from the underlying model by explicitly setting a value in the UIX page
definition.
In our case, we want to be able to specify that a field in our webpage is mandatory even though the underlying Entity Object’s Attribute is
not required. That means we will have to explicitly set the required attribute on the messageTextInput element.
To change the behavior of the JHeadstart Application Generator, we need to find out:
- Where we find the functionality that generates the messageTextInput elements
- How we can change that functionality
Most of the page generation by the JAG is done through a number of XSLT stylesheets that would will find in the file JAGLauncher.jar that you have set up in the [JDeveloper Home]\ jdev\lib\ext\jheadstart directory.
To change the generator with regard to the Table Layout, we have to modify the XSLT document UIXTableLib.xsl. For the elements in a Form style layout, we need to look at the file UIXLibrary.xsl.
Alternatively, we could try to find a way to change the interpretation of the model attribute in UIX. Apparently, the default implementation results in the case of ADF Business Components of the Entity Object Attribute property IsNotNull to be used for the runtime setting of the UIX required property. If somehow we can override one of the classes involved in this interpretation, we may have a runtime way of influencing the required-ness of our items. Perhaps Steve Muench can help us out… Note that this involves a chain of classes, starting at oracle.jbo.server.AttributeDefImpl that implements the isMandatory() method.
Changing generation of the Table Layout
We open file UIXTableLib.xsl and look at two things:
- Generation of the column headers – more specifically, generation of the required attribute in the columnHeader element
- Generation of the JavaScript call to function addRequiredItems that ensures submit time validation – per record – of mandatory items
Both pieces of generator functionality are to be changed: they should first look at the MANDATORY property on the ViewObject Attribute and only if that does not have a value fall back to the current behavior of using the Entity Object Attribute’s IsNotNull property.
Inside template columnHeader, I add this piece of XSLT logic to derive the value of a new XSLT variable $mandatory:
<!-- LJ added derivation of variable mandatory -->
<xsl:variable name="mandatory">
<xsl:call-template name="getCustomProperty">
<xsl:with-param name="entityAttribute" select="$entityAttribute"/>
<xsl:with-param name="propertyName" select="'MANDATORY'"/>
<xsl:with-param name="defaultValue" select="$entityAttribute/@IsNotNull"/>
</xsl:call-template>
</xsl:variable>
Inside the derivation of the <columnHeader> element, I make a change: instead of using the select="$entityAttribute/@IsNotNull" to determine the required property, I make use of the new variable $mandatory:
<!-- LJ changed $entityAttribute/@IsNotNull to $mandatory -->
<xsl:if test="$mandatory='true' and ($group/@tableInsert='true' or $group/tableUpdate='true')">
<xsl:attribute name="required">yes</xsl:attribute>
</xsl:if>
Inside XSL template requiredRowItems, I have added the definition of the variable $mandatory:
<!-- LJ added variable mandatory; removed variable required (only looked at IsNotNull in Entity Attribute) -->
<xsl:variable name="mandatory">
<xsl:call-template name="getCustomProperty">
<xsl:with-param name="entityAttribute" select="$entityAttribute"/>
<xsl:with-param name="propertyName" select="'MANDATORY'"/>
<xsl:with-param name="defaultValue" select="$entityAttribute/@IsNotNull"/>
</xsl:call-template>
</xsl:variable>
In the next expression, I replace $required in $mandatory:
<xsl:if test="$display='true' and $mandatory='true'">
Changing generation of the Form Layout
Generation of the Form Layout is a little harder to influence. Because of the way JHeadstart 10.1.2(.1) uses the UIX model attribute to implicitly derive the mandatory-ness from the underlying model, the generator no longer contains the logic to derive the required property and set it on generated items. We will have to make some more adjustments. Open the file UIXLibrary.xsl.
Inside template createFormElement we change the derivation for the variable $required:
<!-- LJ changed definition of required variable, using MANDATORY instead of $entityAttribute/@IsNotNull -->
<xsl:variable name="required">
<xsl:call-template name="getCustomProperty">
<xsl:with-param name="entityAttribute" select="$entityAttribute"/>
<xsl:with-param name="propertyName" select="'MANDATORY'"/>
<xsl:with-param name="defaultValue" select="''"/>
</xsl:call-template>
</xsl:variable>
Note how we do not use the IsNotNull property of the EntityAttribute as default this time. If no specific MANDATORY was set, we leave it to the default behavior driven from the model attribute whether or not the item will be displayed as required, we do not have to set an explicit value on the required attribute.
The second modification that is required, is made in the template fieldProps. Here we add, near the beginning of the template, the following section that will set the required attribute under certain circumstances:
<!-- LJ if required is true and we are in a form layout block, then explicitly set the required attribute --> <xsl:if test="$layoutStyle!='quickSearch' and $layoutStyle!='table' and $isFindElement='false' and $required='true'"> <xsl:attribute name="required">yes</xsl:attribute> </xsl:if> <!-- LJ end of change -->
Adding the new property MANDATORY to the BC4J Property Editor
It is one thing to be able to specify the value of the new MANDATORY property in the Custom Property Dialog in the standard BC4J View Object Editor:
It is quite another – at least in terms of productivity – to be able to do so in the JHeadstart Property Editor for View Object attributes. In this section, we are going to achieve the latter:
The JHeadstart View Object property editor is configured from an XML file called ViewAttributeCustomPropertiesDefinition.xml. This file can be found in the jar file Bc4jPropertyEditor.jar in the same directory where we found JAGLauncher.jar. We can easily add our new MANDATORY property to the property editor’s configuration file, by simply inserting the following XML fragment:
<!-- LJ added new property MANDATORY -->
<PropertyDefinition name="MANDATORY" displayName="Mandatory in client?" defaultValue="" editor="" readOnly="false" mandatory="false">
<Description>Indicates whether the attribute should be made mandatory in the client; this can override the Entity Object Attribute Required property when that property is set to false (optional attribute) and you want to make this attribute required in certain screens. Allowable values: empty or true. Empty means that the underlying value from the Entity Object is used.</Description>
<AllowableValues>
<Value></Value>
<Value>true</Value>
</AllowableValues>
</PropertyDefinition>