User defined RDML Built-in function

Date:Archived
Product/Release:LANSA for the AS/400
Abstract:It is now possible to write user defined built in functions via a LANSA function instead of via a 3GL program
Submitted By:LANSA Technical Support

It is now possible to write user defined built in functions via a LANSA function instead of via a 3GL program. The following pages contain a description of how to develop and use this special type of LANSA function as well as a simple example.

This document consists of the following details:

  1. Steps to create RDML built-in functions
  2. Initial creation of an RDML built-in function
  3. RDML naming conventions
  4. Example – defining a BIF as an RDML function

1. Steps to Creating RDML Built-In Functions

  • Design the Built-In Function.
  • Allocate the next Unique number. If this is a User Defined Built-In Function, this step may not necessarily need to be done, but if it is, use the next available number between 401 and 600. If this is an Other Vendor Built-In Function then use the next available number in the ASPECT allocated range (within the Other Vendor range of 601 to 999).
  • Give the Built-In Function a name. Use something that even a non-programmer would understand. Prefix User Defined BIFs with 'UD_' and Other Vendor BIFs with 'OV_' for easy identification.
  • Give the function a name. If the RDML BIF is to be distributed, this name must be as documented under naming conventions. If the BIF name is less than 7 characters and this is a User Defined BIF, then the function name could be the same as the BIF name.
    Note: Remember the naming conventions.
  • Fill out a Built-In Function definition form (see LANSA built-in function guide). Note: This step is not necessary but it is a good idea if this is the first Built-In Function.  
  • Code the function. Use the BBRDMLBIF template supplied to assist with initial coding of the BIF definition, arguments and return values.

2. Initial Creation of an RDML Built-In Function

It is recommended that the RDML commands of an RDML Built-In Function function be in the following sequence:

FUNCTION OPTIONS(*BUILTIN *DIRECT)

Followed optionally by the override BIF name and description:

DEFINE FIELD(#BIF_NAME) TYPE(*CHAR) LENGTH(20) DESC(<BIF description>) DEFAULT(<BIF name>)

Followed optionally by the required and then optional arguments:

DEFINE/DEF_LIST #BIF_ARGnn

Followed optionally by the required and then optional return values:

DEFINE/DEF_LIST #BIF_RETnn

Note: A working list argument or return value is always required.

It is also recommended that the naming convention for working list argument counters be BIF_ALCnn and for working list return value counters be BIF_RLCnn.

Note that these recommendations are followed in the function skeleton generated from the application template BBRDMLBIF supplied by LANSA.

Return Value Working Lists

Return value working lists are not cleared automatically as a result of either specifying them in a USE of an RDML Built-In Function or on entry to an RDML Built-In Function.

It is the responsibility of the RDML Built-In Function provider to either explicitly execute CLR_LIST commands against return value working lists in the RDML Built-In Function to document that entries are added on the end of the return value working list.

This behaviour allows the RDML Built-In Function to be more flexible with regard to return value working lists.

Interactive Commands

It would be extremely unusual to code DISPLAY, POP_UP or REQUEST commands in an RDML BIF function, unless it was documented that the RDML BIF is to run only in an interactive environment and appropriate checking for such an environment were coded on entry to the RDML BIF. This would affect the portability of the RDML BIF.

Termination of RDML Built-In Function

An RDML Built-In Function that is *LIGHTUSAGE will terminate after every USE of it.

An RDML Built-In Function that is *HEAVYUSAGE will not terminate after every USE of it. Instead, when the Using function ends, there will be a termination call made to it. Such an RDML Built-In Function can have its evaluation logic conditioned by testing that the system variable *BIF_SHUTDOWN is not 'Y'. Any special shutdown logic can be conditioned by testing that *BIF_SHUTDOWN is 'Y'.

Any RDML Built-In Function can refer to the system variable *BIF_SHUTDOWN. For RDML Built-In Functions that are *LIGHTUSAGE, its value will always be 'N', and consequently any special shutdown logic conditioned by its value being 'Y' will never be executed.

Optional Arguments and Return Values

It would be usual to condition references to optional return values and their derivation by testing the value of the system variable *BIF_RETCOUNT. In particular where deriving an optional return value is expensive in terms of machine resources, this would be more efficient.

Optional arguments, if not passed, will have their default value. References to optional arguments can be conditioned by testing the value of the system variable *BIF_ARGCOUNT. In particular, if the default value is not distinguishable from a passed value, but processing still needs to be different, this would be necessary.

Optional arguments and return values can be referred to in the RDML Built-In Function whether or not they have been coded in the USE command of the Using function.

Access to an RDML BIF Function

Functions are partition specific. Built-In Function definitions are LANSA system wide. If an RDML Built-In Function has to be made available to a partition other than that where it has been compiled, it must be accessible in the library list for that other job. As with 3GL BIFS, this is the responsibility of the LANSA administrator or provider of the BIF.

Replacing 3GL BIFs with RDML BIFS

If, in the interests of portability, a 3GL BIF is replaced by an RDML BIF, all functions that USE that BIF will need to be recompiled, because of differences in the underlying architecture between 3GL and RDML BIFs.

Adding Optional Arguments and Return Values

New optional arguments and return values can be added to RDML Built-In Functions without having to recompile all functions that already USE the RDML BIF if the new optional arguments or return values are added after all other arguments and return values. Obviously functions that need to take advantage of the new optional arguments or return values will need to be recompiled.

RDML BIFS in a Client / Server Environment

An RDML BIF can be used to redirect execution from the client to the server without the rest of the application having to be concerned with the 'mechanics' of it.

3. RDML Naming Conventions

Functions

Function names can be up to 7 characters in length. LANSA uses the following naming convention for RDML Built-In Function objects that are to be distributed:

XX@Y999

Where XX identifies this as Built-In Function code, either BI for Aspect Supplied or OV for Other Vendor. Y is the type of object, either P for Program or D for Display file. 999 is the unique identifier. This is only really important where the BIF is to be distributed, as function names need to be unique.

Built-In Function Definition

BIF names can be up to 18 characters in length. Unless overridden by the definition of field BIF_NAME within the function it defaults to the Function name.

XX_YYYYYYYYYYYYYYYYY

Where XX identifies this as Built-In Function code, either UD for User Defined or OV for Other Vendors. YYYYYYYYYYYYYYYYY is the name that will describe even to the nonprogrammer what functions the BIF performs.

Built-In Function Argument

Inside the RDML BIF, an argument is signified by a field or working list defined with the name "BIF_ARGnn", where nn is between 01 and 20.

Built-In Function Return Value

Inside the RDML BIF, a return value is signified by a field or working list defined with the name "BIF_RETnn", where nn is between 01 and 20.

4. Example - Defining a BIF as an RDML Function

This section goes through the steps involved in creating an RDML Built-In Function as a function. The example shown is very simple, but should give an insight to how an RDML Built-In Function is plugged into a LANSA system.

SCENARIO: This is a User Defined RDML Built-In Function. The Built-In Function is passed two arguments :a working list of packed 11,2 numbers and optionally whether to return those that are above or below the average of the numbers, defaulting to be above. The Built-In Function will return a working list of the packed 11,2 numbers as per the criteria and optionally the average value as a packed 30,9 number. The RDML BIF will be used extensively in a new application, so will be coded not to terminate between USEs.

  • The BIF name will be UD_GET_HI_LO_AVG.
  • The BIF description will be 'Return numbers over or under the average'.
  • The RDML Built-In Function is generated from template BBRDMLBIF.
  • The argument and return value working lists are then customized from the prototype generated by the template.
  • The actual evaluation logic is then added.
* Beginning of RDML commands **********
* ********* Process .......: CR4587SMPL
* ********* Function ......: CR4587S
* ********* Type ..........: Built_In Function
* ********* Description ...: Sample RDML BIF Function
* ********* =======================================================
FUNCTION OPTIONS(*DIRECT *NOMESSAGES *HEAVYUSAGE *MLOPTIMISE *BUILTIN)
* ********* =======================================================
* ********* Special field to name the Built-In Function
* ********* =======================================================
DEFINE FIELD(#BIF_NAME) TYPE(*CHAR) LENGTH(20) DESC('Return numbers over or under the average')
DEFAULT('UD_GET_HI_LO_AVG')
* ********* =======================================================
* ********* Built-In Function Arguments
* ********* =======================================================
* ********* Argument 01, Supplied numbers list
DEFINE FIELD(#BIF_ALC01) TYPE(*DEC) LENGTH(7) DECIMALS(0) DESC('Supplied numbers list')
DEFINE FIELD(#NUMBER) TYPE(*DEC) LENGTH(11) DECIMALS(2) DESC('Number')
DEF_LIST NAME(#BIF_ARG01) FIELDS((#NUMBER)) COUNTER(#BIF_ALC01) TYPE(*WORKING)
ENTRYS(9999)
* ********* Argument 02, Over or under numbers required (O or U)
DEFINE FIELD(#BIF_ARG02) TYPE(*CHAR) LENGTH(1) DESC('Over or under numbers required (O or U)')
DEFAULT('O')
* ********* =======================================================
* ********* Working fields, lists and groups
* ********* =======================================================
DEFINE FIELD(#TOTAL) TYPE(*DEC) LENGTH(30) DECIMALS(2) DESC('Total')
* ********* =======================================================
* ********* Built-In Function Return Values
* ********* =======================================================
* ********* Return Value 01, Over or under average numbers list
DEFINE FIELD(#BIF_RLC01) TYPE(*DEC) LENGTH(7) DECIMALS(0) DESC('Over or under average numbers list')
DEF_LIST NAME(#BIF_RET01) FIELDS((#NUMBER)) COUNTER(#BIF_RLC01) TYPE(*WORKING)
ENTRYS(9998)
* ********* Return Value 02, Average of supplied numbers
DEFINE FIELD(#BIF_RET02) TYPE(*DEC) LENGTH(30) DECIMALS(9) DESC('Average of supplied numbers')
DEFAULT(*ZERO)
* ********* =======================================================
* ********* Function Mainline : CR4587S
* ********* =======================================================
* ********* This is an evaluation call
* *********
* *********
IF COND('*BIF_SHUTDOWN *NE Y')
********** calculate the average
CHANGE FIELD(#TOTAL) TO(0)
SELECTLIST NAMED(#BIF_ARG01)
CHANGE FIELD(#TOTAL) TO('#TOTAL + #NUMBER')
ENDSELECT
CHANGE FIELD(#BIF_RET02) TO('#TOTAL / #BIF_ALC01') ROUND_UP(*YES)
* ********* go through the list again and add the overs or unders
* ********* to the return list
CLR_LIST NAMED(#BIF_RET01)
SELECTLIST NAMED(#BIF_ARG01) WHERE('((#BIF_ARG02 *EQ O) *AND (#NUMBER *GT #BIF_RET02))
* OR
((#BIF_ARG02 *EQ U) *AND (#NUM BER *LT #BIF_RET02))')
ADD_ENTRY TO_LIST(#BIF_RET01)
ENDSELECT
* ********* This is a shutdown call
* *********
ELSE
* ********* No shutdown logic
ENDIF
* ********* Return control to the invoker
RETURN
* ********* End of RDML commands **********

Note:

  • The return value list is explicitly cleared prior to any entries being added.
  • The optional argument and return value can be referred to even though they may not have been coded in the USE statement. It would be more usual to condition references to any optional arguments or return values by testing the value of *BIF_ARGCOUNT and *BIF_RETCOUNT respectively. There is no extra processing to derive the optional return value. It saves defining another work field.
  • Because the function is heavyusage, its evaluation logic is conditioned by ensuring that it is not a shutdown call. Also the accumulation field is reset to 0 every time. For this RDML BIF there is no special shutdown logic.