Using PeopleCode in Application Engine Programs

This section provides an overview of PeopleCode and Application Engine programs and discusses how to:

  • Decide when to use PeopleCode.

  • Consider the program environment.

  • Access state records with PeopleCode.

  • Use If/Then logic.

  • Use PeopleCode in loops.

  • Use the AESection class.

  • Make synchronous online calls to Application Engine programs.

  • Use the file class.

  • Call COBOL modules.

  • Call PeopleTools application programming interfaces (APIs).

  • Use the CommitWork function.

  • Call WINWORD Mail Merge

  • Use PeopleCode examples.

Inserting PeopleCode into Application Engine programs enables you to reuse common function libraries and improve performance. In many cases, a small PeopleCode program used instead of Application Engine PeopleCode is an excellent way to build dynamic SQL, perform simple If/Else edits, set defaults, and perform other tasks that do not require a trip to the database.

Scope of Variables

This table presents the different types of variables typically used in Application Engine programs and their scope:

Type of Variable

Scope

Comments

State record (work record)

Transaction (unit of work)

Using a work record as your Application Engine state record means that the values in the work record cannot be committed to the database. Commits happen as directed, but any values in work records are not retained after a commit.

State record (database record)

Application Engine program

Using a database record as your Application Engine state record preserves the values in the state record on commit, and the committed values are available in the event of a restart.

Local PeopleCode variables

PeopleCode program

Local PeopleCode variables are available only for the duration of the PeopleCode program that is using them.

Global PeopleCode variables

Application Engine program

Global PeopleCode variables are available during the life of the program that is currently running. Any global PeopleCode variables are saved when an Application Engine program commits and checks points; therefore, they are available in the event of a restart.

Component PeopleCode variables

Application Engine program

Component PeopleCode variables act like global variables in Application Engine.

Action Execution Order

A step can contain only one PeopleCode action because no other types of actions are required within a step in conjunction with a PeopleCode action (or program). If you include other actions with your PeopleCode action within the same step, keep in mind the hierarchy when you run it.

With PeopleCode actions, Application Engine runs the PeopleCode program before the SQL, Call Section, or Log Message actions, but a PeopleCode program runsafter any program flow checks.

Because multiple action types exist, they must execute in agreement within a system; therefore, the order in which actions execute is significant. At runtime, actions defined for a given step are evaluated based on their action type. All of the action types exist within a strict hierarchy of execution. For example, if both a Do When action and a PeopleCode action exist within a given step, then the Do When action always runs first.

The following example shows the sequence and level of execution for each type of action:

Image: Example of action execution hierarchy

This is an example of action execution hierarchy.

Example of action execution hierarchy

Application Engine is not intended to run programs that include only PeopleCode actions. The primary purpose of Application Engine is to run SQL against your data.

Use PeopleCode primarily for setting If, Then, Else logic constructs, performing data preparation tasks, and building dynamic portions of SQL statements; rely on SQL to complete the bulk of actual program processing. Also use PeopleCode to reuse previously developed online logic. PeopleCode is the tool to use to take advantage of new technologies such as component interfaces and application classes.

Most programs must verify that a certain condition is true before they run a particular section. For example, if the hourly wage is less than or equal to X, do Step A; if not, fetch the next row. In certain instances, you must modify variables that exist in a state record. PeopleCode enables you to set state record variables dynamically.

Avoid rowset processing in an Application Engine program. Loading data into a rowset can use a significant amount of memory, which this formula approximates:

mem = nrows * (row overhead + nrecords * (rec overhead + nfields * (field overhead) + average cumulative fielddata))

where

  • mem is the amount of memory required to store the rowset.

  • nrows is the number of rows.

  • row overhead is the overhead per row.

  • nrecords is the number of records per row.

  • rec overhead is the record overhead (approximately 40 bytes).

  • nfields is the number of fields in the record.

  • field overhead is the overhead per field (approximately 80 bytes).

  • average cumulative fielddata is the average amount of data per field.

Using this formula, a rowset containing 500,000 rows with one record per row, 50 fields, and 200 bytes per field would require approximately 2.3 gigabytes of memory.

When writing or referencing PeopleCode in a PeopleCode action, you must consider the environment in which the Application Engine program runs. Environment indicates the differences between online and batch modes. Application Engine programs usually run in batch mode; consequently, your PeopleCode cannot access pages or controls as it can while running in online mode. Any PeopleCode operations that manipulate pages will not run successfully. Even if you invoke your Application Engine program online from a record or a page using the CallAppEngine PeopleCode function, the Application Engine PeopleCode still does not have direct access to component buffers.

Any record field references that appear in a PeopleCode action can refer only to fields that exist on an Application Engine state record. Component buffers, controls, and so on are still inaccessible even if you define the page records as state records in the Program Properties dialog box. An Application Engine program can access only state records or other objects you create in PeopleCode.

However, you do have several options for passing data from a component buffer to an Application Engine program: you can use the CallAppEngine PeopleCode function or you can define global variables.

Passing Parameters Through the CallAppEngine Function

For individual page fields and simple PeopleCode variables such as numbers and strings, you can use the CallAppEngine PeopleCode function to pass values as parameters.

To use the CallAppEngine function:

  1. Declare a record object in PeopleCode.

    For example, Local Record &MyRecord;.

  2. Assign record objects to any state record that you want to pass to the Application Engine program.

    Record objects are parameters to the CallAppEngine function.

  3. Set the appropriate values on that state record.

  4. Include the record object in the function call.

After these values are set in the state record, all the actions in a particular program, not just the PeopleCode actions, can use the values.

Defining Global Variables

You can define global variables or objects in PeopleCode before you call an Application Engine program. Application Engine PeopleCode actions are able to access only the variables you define; however, the PeopleCode could set a state record field equal to a number or string variable for use by other Application Engine actions.

Also, an Application Engine PeopleCode program can read or update a scroll area or a grid using a global rowset object. When accessing a scroll area or a grid from Application Engine PeopleCode, the same rules apply and the same illegal operations are possible that you see with accessing PeopleCode not in an Application Engine program.

The parameters submitted in a CallAppEngine are by value. These parameters seed the specified Application Engine state record field with a corresponding value. If that value changes within Application Engine by updating the state record field, then the component data will not be affected. The only way to update component buffers or external PeopleCode variables from Application Engine is to use global PeopleCode variables and objects.

Running PeopleCode from Application Engine steps enables you to complete some simple operations without having to use SQL. For example, to assign a literal value to an Application Engine state record field using SQL, you may have issued a statement similar to this one:

%SELECT(MY_AET.MY_COLUMN)
SELECT 'BUSINESS_UNIT' FROM PS_INSTALLATION

You can use a PeopleCode assignment instead:

MY_AET.MY_COLUMN = "BUSINESS_UNIT";

Similarly, you can use a PeopleCode If statement instead of a Do When action to check the value of a state record field.

When accessing state records with PeopleCode, keep in mind that:

  • State records are unique to Application Engine programs.

  • Within Application Engine PeopleCode, state record values can be accessed and modified using the standard recordname.fieldname notation.

Note: When you launch an Application Engine program from PeopleSoft Process Scheduler, you can generate a process warning status after the program completes by including and modifying the AE_APPSTATUS field in a state record. You can generate the warning status by setting AE_APPSTATUS to a value of 1.

From PeopleCode, you can trigger an error status, or false return, by using the Exit function. Use the On Return value in the PeopleCode action properties to specify how your Application Engine program behaves according to the return of your PeopleCode program. This example shows the On Return property:

Image: Example of On Return action property

This example illustrates the fields and controls on the Example of On Return action property.

Example of On Return action property

By default, the program terminates, similar to what happens when a SQL error occurs. By changing the On Return value to Skip Step, however, you can control the flow of your Application Engine program.

You can use Exit to add an If condition to a step or a section break. For example:

If StateRec.Field1 = ‘N’
Exit(1);
Else
/* Do processing */
End-if;

You must specify a non-zero return value to trigger an On Return action. The concepts of “return 1” and “return True” are equivalent; therefore, if the return value is non-zero or True, then Application Engine performs what you specify for On Return, as in Abort orSkip Step. However, if the program returns zero or False, Application Engine ignores the selected On Return value.

You can insert PeopleCode inside of a Do loop, but be careful when using PeopleCode inside of high-volume Do loops (While, Select, Until). Minimize the number of distinct programs inside the loop. You should avoid having PeopleCode perform the actual work of the program and instead use it primarily to control the flow (If, Then logic), build dynamic SQL, or interact with external systems.

Using bind variables instead of literals to pass values to SQL statements is essential in PeopleCode loops or if the PeopleCode is called in a loop. If the PeopleCode loops, Application Engine probably will use a dedicated cursor, which saves the overhead of recompiling the SQL for all iterations. If the PeopleCode is called from within a loop, Application Engine does not reduce the number of compiles, but it avoids flooding the SQL cache (for those database servers that support SQL cache) when it uses bind variables. Do not use bind variables for values in a Select list or for SQL identifiers, such as table and column names, as some databases do not support them.

Note: Null bind values of type DateTime, Date, or Time are always resolved into literals.

On database platforms for which this feature is implemented, setting BulkMode to True often results in significant performance gains when inserting rows into a table within a loop.

In general, avoid PeopleCode calls within a loop. If you can call the PeopleCode outside of the loop, use that approach to increase overall performance.

The AESection PeopleCode class enables you to change the properties of an Application Engine program section dynamically, without having to modify any of the Application Engine tables directly. This capability enables you to develop rule-based applications that conform dynamically to variables that a user submits through a page, such as the Application Engine Request page.

The AESection class provides the following flexibility:

  • Portions of SQL are determined by checks before a run.

  • The logic flow conforms as rules change, and the program adjusts to the rules.

When using an AESection object:

  • Ensure that you require primarily dynamic capabilities with the SQL your program generates.

  • Ensure that the rules to which your program conforms are relatively static or at least defined well enough that a standard template could easily accommodate them.

  • Consider using SQL definitions to create dynamic SQL for your programs to avoid the complexity created by the AESection object using the StoreSQL function.

  • The AESection class is designed to dynamically update SQL-based actions only, not PeopleCode, Call Section, or other actions.

    You can add a PeopleCode action to your generated section, but you cannot alter the PeopleCode.

  • The AESection class is designed to use for online processing.

    Typically, dynamic sections should be constructed in response to a user action.

Note: Do not call an AESection object from an Application Engine PeopleCode action.

To make synchronous online calls to an Application Engine program, use the PeopleCode function CallAppEngine.

Note: If you make a synchronous call, users cannot perform another PeopleSoft task until the Application Engine program completes. Consider the size and performance of the Application Engine program called by CallAppEngine. You should ensure that the program will run to successful completion consistently within an acceptable amount of time.

If an Application Engine program called by CallAppEngine terminates abnormally, the user receives an error, similar to other save time errors, that forces the user to cancel the operation. The CallAppEngine function returns a value based on the result of the Application Engine call. If the program was successful, it returns a zero; if the program was unsuccessful, it returns a value other than zero.

The file layout class enables you to perform file input and output operations with Application Engine using PeopleCode. A file object enables you to open a file (for reading or writing), read data from a file, or write data to it. Using the combination of the file class and Application Engine provides an effective method to integrate (or exchange) the data stored in a legacy system with your PeopleSoft system. The file class facilitates the creation of a flat file that both your legacy system and Application Engine programs support.

An Application Engine program running on the application server uses a file object to read the file sent from the legacy system and to translate it so that the file can update affected PeopleSoft application tables. For the PeopleSoft system and the legacy system to communicate, you first must construct a file object that both systems can use to insert and read data.

Attain rowset and record access for a file using a file layout definition. You create the file layout definition in Application Designer, and it acts as a template for the file that both systems read from and write to. This file layout definition simplifies reading, writing, and manipulating complex transaction data with PeopleCode.

Generally, use the file class and Application Engine combination when you cannot implement the PeopleSoft Integration Broker solution.

Using the PeopleCode RemoteCall function, you can call COBOL modules from a PeopleCode action. This option supports existing Application Engine programs that call COBOL modules. You also can use it to upgrade Application Engine programs from previous releases.

PTPECOBL Program

The PTPECOBL interface program is a PeopleSoft executable that enables you to invoke your called COBOL module and pass it required values. You code the RemoteCall function to invoke PTPECOBL, which in turn calls the specified COBOL module.

If you use PTPECOBL, you do not have to write your own executable to process this task. However, PTPECOBL does not perform any SQL processing other than retrieving a list of state record values. Consequently, if your current logic requires previous SQL processing, you may want to write your own executable file to call your COBOL module. In most situations, PTPECOBL saves you from having to write a custom executable file to handle each call to a generated dynamically loadable code (.GNT) file.

PTPECOBL performs the following tasks:

  1. Initializes the specified state record in memory.

  2. Invokes the COBOL module specified in your PeopleCode.

  3. Submits required parameters to the called COBOL module.

  4. Updates the state record as necessary, issues a commit, and then disconnects from the database after your program completes.

Note: While your COBOL program runs, it can access and return values to the state record.

Shared Values in Application Engine and COBOL

The following options are available for sharing values between the Application Engine program and a called COBOL program:

  • Use state records.

    If you add field names, Application Engine enables you to pass state record values to the called COBOL program and to get changes passed back to the calling PeopleCode program. If you pass the state record values in this way, use PTPECACH to retrieve and update values just as PTPEFCNV does.

  • Code custom SQL.

    If you do not pass initial values using state record fields, you need to insert the appropriate SQL in your called COBOL module to retrieve the appropriate values. Then, to return any updated values to the calling Application Engine program, you must insert the appropriate SQL into a PeopleCode program.

    If your COBOL program needs values that do not appear in a state record field, then you can pass PeopleCode variables and values. These variables and values are then retrieved and updated by calling PTPNETRT from within your COBOL program.

  • Create a custom executable file.

    If you include extra SQL processing and use non-state record values, for consistency purposes, creating a custom executable file might be a better approach. It enables you to call your program directly and have it perform all the PTPNETRT processing. Remember that a RemoteCall command can only call an executable program, not a GNT file.

Syntax and Parameters

This example shows a sample RemoteCall function issued from an Application Engine PeopleCode action to a COBOL module:

RemoteCall ("PSRCCBL",?
 "PSCOBOLPROG", "PTPECOBL",?
 "AECOBOLPROG", "MY_GNT",?
 "STATERECORD", "MY_AET",?
 "PRCSINST", MY_AET.PROCESS_INSTANCE,?
 "RETCODE", &RC,?
 "ERRMSG", &ERR_MSG,?
 "FIELD1", MY_AET.FIELD1,?
 "FIELD2", MY_AET.FIELD2);

This table describes each parameter in the RemoteCall function:

Parameters

Description

PSRCCBL

The Remote Call dispatcher, which runs the specified COBOL program using the connect information of the current operator.

PSCOBOLPROG

Specify the name of the COBOL program to run, which in this case is PTPECOBL.

This parameter makes the remote call from Application Engine distinct from a normal remote call. When you enter this parameter, in effect you enable the following parameters, some of which are required.

AECOBOLPROG

Specify the name of the COBOL module you are calling; for example, MY_GNT.

STATERECORD

Specify the appropriate state record that your Application Engine program will share with your COBOL module; for example, MY_AET. PTPECOBL then reserves space in memory for all of the fields in the state record, regardless of whether they will ultimately store values for processing.

PRCSINST

Specify the state record and Process Instance field; for example, MY_AET.PROCESS_INSTANCE. This setting retrieves the current process instance value that appears on the state record and submits it to your COBOL module using PTPECOBL.

RETCODE and ERRMSG

(Optional) Include RETCODE if you need to return information about any potential problems that the COBOL processing encountered, or use it if your Application Engine program must know whether it completed successfully.

Fieldnames and Values

Specify any fields in the state record that contain initial values for your COBOL module. The quoted field names you specify must exist in the specified state record. The corresponding value can be a PeopleCode variable, a record.field reference, or a hard-coded value.

Commit and RemoteCall

When using RemoteCall and an Application Engine program:

  • The called COBOL module runs as a separate unit of work.

  • Run a commit in the step immediately preceding the step containing the RemoteCall PeopleCode action and also in the step containing the Remote Call PeopleCode action.

    These two actions enable the COBOL process to recognize the data changes made up to the point that it was called, and minimizes the time when the process might be in a non-restartable state.

  • If you insert SQL processing into your COBOL module, your module makes commit updates.

    PTPECOBL does not issue any commits.

  • If the intent of your COBOL process is to update the value of a passed state record field, then the calling Application Engine PeopleCode is responsible for ensuring that the state record field is modified, and the Application Engine program is responsible for committing the state record updates.

  • Consider how your COBOL module will react in the event of a restart.

    Because the work in COBOL will have already completed and been committed, will your module ignore a duplicate call or be able to undo or redo the work multiple times? You face similar issues when you run a remote call from PeopleCode.

  • Typically, when a COBOL program updates the database and then disconnects or terminates without having issued an explicit commit or rollback, an implicit rollback occurs.

    Without an explicit commit, the database does not retain any updates.

Note: By default, RemoteCall does not generate any log files after the program completes. To generate and retain the .out and .err log files, you must set the RCCBL Redirect parameter in the PeopleSoft Process Scheduler configuration file to a value of1.

See RemoteCall.

You can call all of the PeopleTools APIs from an Application Engine program. When using APIs, remember that:

  • All the PeopleTools APIs contain a Save method.

    However, when you call an API from your Application Engine program, regardless of the Save method of the API, the data is not saved until the Application Engine program issues a commit.

  • If you called a component interface from an Application Engine program, all the errors related to the API are logged in the PSMessage collection associated with the current session object.

  • If you sent a message, errors are written to the message log and the Application Engine message log.

  • If an Application Engine program called from a message subscription PeopleCode encounters errors and the program exits (with Exit (1)), the error is written to the message log and is marked as an error

This function commits pending changes (inserts, updates, and deletes) to the database. When using CommitWork, remember that:

  • This function can be used only in an Application Engine program that has restart disabled.

  • The CommitWork function is useful only when you are processing SQL one row at a time in a single PeopleCode program, and you need to commit without exiting the program.

    In a typical Application Engine program, SQL commands are split between multiple Application Engine actions that fetch, insert, update, or delete application data. You use the section or step level commit settings to manage the commits.

If the Process Scheduler is booted using a shared drive on another machine and you intend to call a WINWORD mail merge process from Application Engine, then you must do one of the following to ensure successful completion:

  1. Configure the Process Scheduler to run Application Engine programs using psae instead ofpsaesrv.

  2. Ensure the generated document is saved locally, not on a shared network drive.

The following topics provide examples of common ways that you can use PeopleCode within Application Engine programs.

Do When Actions

Instead of a Do When action that checks a %BIND value, you can use PeopleCode to perform the equivalent operation. For example, suppose the following SQL exists in your program:

%SELECT(EXISTS) SELECT 'Y' FROM PS_INSTALLATION WHERE %BIND(TYPE) = 'X'), 

Using PeopleCode, you could insert this code:

If TYPE = 'X' Then
   Exit(0);
Else
   Exit(1);
End-if;

If you set the On Return parameter on the PeopleCode action properties to Skip Step, this code behaves the same as the Do When action. The advantage of using PeopleCode is that no trip to the database occurs.

Dynamic SQL

If you have a Select statement that populates a text field with dynamic SQL, such as the following:

%SELECT(AE_WHERE1)
SELECT 'AND ACCOUNTING_DT  <= %Bind(ASOF_DATE)'

You can use this PeopleCode:

AE_WHERE1 = "AND ACCOUNTING_DT  <= %Bind(ASOF_DATE)";

Sequence Numbering

If you typically use Select statements to increment a sequence number inside of a Do Select, While, or Until loop, you can use the following PeopleCode instead:

SEQ_NBR = SEQ_NBR + 1;

Using PeopleCode rather than SQL can affect performance significantly. Because the sequencing task occurs repeatedly inside a loop, the cost of using a SQL statement to increment the counter increases with the volume of transactions your program processes. When you are modifying a program to take advantage of PeopleCode, the areas of logic you should consider are those that start with steps that run inside a loop.

Note: You can also use the meta-SQL constructs %Next and %Previous when performing sequence numbering. These constructs may improve performance in both PeopleCode and SQL calls.

Rowsets

You can use rowsets in Application Engine PeopleCode; however, using rowsets means you will be using PeopleCode to handle more complicated processing, which degrades performance.

Math Functions

Use the math functions that your database offers whenever possible.

Internally, PeopleCode assigns types to numeric values. Calculations for the Decimal type are processed in arrays to ensure decimal point uniformity across hardware and operating system environments. This processing is much slower than calculations for type Integer, which are processed at the hardware level.

When PeopleCode converts strings to numeric values, it does so using the internal Decimal type. For performance reasons, avoid calculations using these values.

A third type of numeric value is the Float type. It is not used as frequently for the following reasons:

  • Constants are never stored as Float types in the compiled code.

    For example, 2.5 is always Decimal type.

  • The only way to produce a Float value is by using built-in functions, such as Float or the Financial math functions.

Use the Float type to produce a float result only if all operands are also of the Float type. Float operations occur at the hardware level.

PeopleCode does not offer optimum performance when processing non-Integer, non-Float math calculations. To perform calculations with these numeric types, consider allowing the database to perform the calculations in COBOL.

PeopleCode supports a range of mathematical functions and numeric types. In general, if a complex calculation is run repetitively in an Application Engine program, you should carefully analyze whether to perform the calculation in a PeopleCode action or use the relational database management system (RDBMS) functions through a SQL action. Using SQL may require PeopleSoft meta-SQL to handle platform differences, but it may be the most efficient way to update field values. If SQL is not appropriate, consider numeric typing in PeopleCode, as it affects the speed and accuracy of the calculation.

SQL Class

Instead of using the SQL class within PeopleCode, have Application Engine issue the SQL and use a Do Select action that loops around sections containing PeopleCode actions.

Coding all of the logic within a single PeopleCode program might appear to be easier, but splitting the logic into smaller pieces is preferable because you will have better performance and will get more detailed commit control. Within a PeopleCode program, you can commit in certain cases using the CommitWork function. You can always issue a commit between Application Engine steps.

See PeopleCode Language Reference.

See Understanding SQL Objects and Application Engine Programs.

Arrays

Instead of using arrays in Application Engine PeopleCode, explore the use of temporary tables for storing pertinent or affected data. Arrays offer the following advantages:

  • Data is available for restarts.

  • An RDBMS is efficient at managing and searching tables.

  • Temporary tables lend themselves to set-based processing.

You can use the Statement Timings and PeopleCode Detail Timings trace options to generate an Application Engine timings report to determine whether your program is spending significant time processing arrays.