3 Understanding Flists
Learn about flists (field lists), which pass data between Oracle Communications Billing and Revenue Management (BRM) processes.
Topics in this document:
About Flists
The flist is the primary data structure used in BRM. Flists are containers that hold fields, each of which is a pair consisting of a data field name and its value. Flists do not contain actual data, but instead provide links to where the data is located. The one exception to this is integers, which are stored in flists.
Here is a simple flist example:
LAST_NAME STR "Smith" FIRST_NAME STR "Joe" COMPANY STR "XYZ Corporation"
Many BRM processes interpret data in flist format. For example, the storage manager in the Data Manager (DM) translates flists to a format that the database can process and then translates the data from the database into an flist before passing it to the Connection Manager (CM).
BRM uses flists in these ways:
-
Objects are passed in the form of flists between opcodes or programs that manipulate the objects.
-
Opcodes use flists to pass data between BRM applications and the database. For each opcode, an input flist is passed to pcm_op and the return flist is passed back from this routine.
In an flist, you can use any data type such as decimals, buffers, arrays, and substructures. Flists can contain any number of fields. You can place flists within other flists. Remember though, that except for integers, data is not stored in the flist, just links to where the data is located.
For a description of the BRM data types you can use in an flist, see "Understanding the BRM Data Types".
Note:
[0] after the field type represents the element ID. The numbers 0, 1, 2, and so on at the beginning of each line indicate the nesting level of the field; 0 indicates the top level.
When you include a field in an flist, you must also include an abbreviation of the field's data type. Table 3-1 lists the valid BRM field types and their abbreviation.
Table 3-1 Flist Field Types
Field Type | Abbreviation |
---|---|
PIN_FLDT_ARRAY |
ARRAY |
PIN_FLDT_BINSTR |
BINSTR |
PIN_FLDT_BUF |
BUF |
PIN_FLDT_DECIMAL |
DECIMAL |
PIN_FLDT_ENUM |
ENUM |
PIN_FLDT_ERRBUF |
ERR |
PIN_FLDT_INT |
INT |
PIN_FLDT_POID |
POID |
PIN_FLDT_STR |
STR |
PIN_FLDT_SUBSTRUCT |
SUBSTRUCT |
PIN_FLDT_TSTAMP |
TSTAMP |
Opcode Input and Output Specifications
Each PCM opcode requires certain data to perform its operation. The opcodes take input and output data in the form of field lists (flists), which are lists of field name and value pairs. For more information about flists, see "About Flists".
Each opcode requires its input flist to contain certain fields to perform the operation. For example, to create an object, the PCM_OP_CREATE_OBJECT() opcode requires an input flist that includes all the fields that an object of that storable class requires.
The information for each opcode in the Programmer's Reference includes the input and output flist specifications, defining the following parameters for each field in the flist:
-
The mnemonic field names used by applications to reference the field
-
The data type and size for the field
-
The permissions, which specify if a field is mandatory (M) or optional (O) for the opcode.
The flist specifications use the following syntax to define each field in an flist:
class depth field ( type = data_type perms = permission permission ..., );
Where class specifies whether it is a field, array, or a substruct, depth contains an asterisk for each nesting level of the field, and field specifies the name of the field.
Examples:
field PIN_FLD_NAME ( type = PIN_FLDT_STR(255), perms = M, ); array * PIN_FLD_INHERITED_INFO ( type = PIN_FLDT_ARRAY, perms = O, );
For fields in opcode input and output flists, the flist specifications specify if a field is mandatory or optional.
About Creating and Using an Flist
You create and manipulate flists with the flist manipulation macros in the Portal Information Network (PIN) library. You can add, remove, and modify fields in an flist by using the flist field-handling macros. For more information, see "Flist Management Macros" and "Flist Field-Handling Macros" in BRM Developer's Reference.
Each opcode has an input and output flist specification. For each opcode you call, you must create an flist for the data you want to pass in. Follow the flist specifications for the opcode when you create an input or an output flist for an opcode. See the flist specifications in the individual opcode descriptions.
Flists are dynamically allocated data structures. When a field is added to an flist, the field value is either already dynamically allocated in memory, or is copied into dynamic memory as it is added.
Note:
You must destroy the flist you create in your programs to reclaim the memory that the flist occupied. For details, see "Destroying Flists".
Adding Information to Flists
You add data to flists by replacing pointers to data using these flist management macros:
-
PIN_FLIST_ELEM_PUT
-
PIN_FLIST_FLD_PUT
-
PIN_FLIST_SUBSTR_PUT
For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.
You add data to flists by replacing the data itself using these flist management macros:
-
PIN_FLIST_ELEM_SET
-
PIN_FLIST_FLD_SET
-
PIN_FLIST_SUBSTR_SET
For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.
Removing Data (Pointers) from an Flist
You remove a pointer to data from an flist and add it to another flist by using these flist management macros:
-
PIN_FLIST_ELEM_TAKE
-
PIN_FLIST_FLD_TAKE
-
PIN_FLIST_SUBSTR_TAKE
Note:
These macros overwrite existing pointers to data, not the data itself. To free the memory used by the old data, you must destroy the memory location using PIN_FLIST_DESTROY_EX otherwise, a memory leak may occur.
You usually use the TAKE macros when you want to take data from an flist and change it.
Note:
When you use a TAKE macro to remove a pointer to data, you must free the memory when finished. If the memory is not freed, memory leaks may occur.
For details on these macros, see Flist Management Macros in BRM Developer's Reference.
Copying Data from an Flist
You copy a pointer to data from one flist to another by using these flist management macros:
-
PIN_FLIST_ELEM_GET
-
PIN_FLIST_FLD_GET
-
PIN_FLIST_SUBSTR_GET
You usually use the GET macros when you want to copy data, but not change it.
Note:
You should treat any data that you GET by using these macros as read-only because the original program may also need this data.
For details on these macros, see Flist Management Macros in BRM Developer's Reference.
Destroying Flists
You destroy an flist and free its memory by using these flist management macros in BRM Developer's Reference:
Flists use dynamically allocated memory and must be destroyed to free that memory and prevent memory leaks. These macros first determine whether the flist has a NULL value. If so, they do nothing. If the flist exists, these macros destroy the entire contents of the flist, including all fields.
PIN_FLIST_DESTROY_EX sets the reference to the flist to a NULL value after it destroys the flist.
PIN_FLIST_DESTROY frees the memory for the flist field-value pairs, but does not set a reference to that flist to NULL. If another program subsequently attempts to destroy this flist (with freed memory, but a valid flist pointer), unexpected behavior and core dumps can result.
For details on these macros, see Flist Management Macros in BRM Developer's Reference.
Flist Creation Samples
BRM SDK includes flist creation samples in C, C++, Java, and Perl. Three samples are provided for each language: one to create a simple flist, another to create an flist with a nested array, and a third to create an flist with a substructure. For information about installing and using BRM SDK, see "About BRM SDK".
You can view the following sample programs in BRM Developer's Reference:
These documents also include information about compiling and running the programs.
Flist Management Rules
Follow these rules when creating programs that manipulate flists:
-
The calling applications are responsible for allocating memory for input flists. This includes cases where you use a wrapper opcode to call another opcode.
-
The opcode being called is responsible for allocating memory for output flists. For more information, see "About Creating and Using an Flist".
-
The calling applications are responsible for destroying both input and output flists.
-
The opcode being called is responsible for destroying both input and output flists if the opcode utilizes a wrapper opcode to call another opcode. For more information, see "Destroying Flists".
-
You should never destroy an input flist within an opcode, because a calling application may need it.
-
These flist management macros in BRM Developer's Reference allocate new memory:
You must explicitly de-allocate the memory allocated unless it is used for an output flist.
-
Memory allocation behavior depends on whether the opcode is called through a network (client/server) connection or within an internal Connection Manager (CM) process.
-
If the opcode is called through a client/server connection, the calling application and the CM do not share the same memory. An opcode with memory allocation issues may work if called by a Portal Communications Protocol (PCP) connection, but core dumps if called internally by another opcode.
-
Example
You use the following syntax to copy an flist:
*out_flistpp = PIN_FLIST_COPY(in_flistp, ebufp);
Flist Field Memory Management Guidelines
You use the following guidelines when creating your programs to avoid memory problems:
-
The following macros in BRM Developer's Reference allocate new memory for a passed value before putting it in an flist:
These macros add or replace items in an flist by copying them; no memory ownership is transferred. When you use the SET macros, memory is allocated to copy the values and is owned by the flist. Do not explicitly free this memory.
-
The following macros do not allocate new memory for a value before putting that value in an flist:
These macros add or replace items in the flist, storing the data previously owned by the caller. The allocation memory is transferred to the flist. These macros link the memory occupied by the value to the named flist. You cannot apply these for local scope (auto) variables if you want to put them into the return flist.
-
The following macros take ownership of the memory owned by the flist for a retrieved value:
These macros remove items from the flist, return pointers, and turn ownership of the allocated memory over to the caller.
-
The following macros do not allocate new memory for a retrieved value:
A pointer to the allocated segment of memory that belongs to the flist returns. To maintain the integrity of the flist, you should never apply the PIN_FLIST_DESTROY macro to an flist pointer returned by these macros. The flist retains ownership of its allocated memory.
-
The following macros move fields from one flist to another:
Memory ownership of the field changes from the source flist to the destination flist.
-
The following field management macros allocate new memory:
All of the preceding macros return the memory owned to the caller.
-
The memory allocated by the macros in these guidelines is owned by the flist. Typically, all flists created by code must be destroyed using PIN_FLIST_DESTROY or PIN_FLIST_DESTROY_EX.
-
Any memory allocated using pin_malloc must be freed unless it is added to an flist using a PUT macro.
-
All flists must be destroyed eventually, either directly or by nesting them in another flist as a child and giving memory ownership to that flist.
-
In Facilities Modules (FMs), the output flist is the only flist that does not need to be explicitly destroyed by the FM, because the Connection Manager (CM) framework destroys it after use.
For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.
Handling Errors
All flist routines take a pointer to pin_ebuf_t as the final argument. This pointer, called ebufp, must point to a preallocated pin_ebuf_t into which error information is written.
The BRM APIs use the pin_ebuf_t structure to pass back detailed information about the error. BRM includes standard logging routines that print formatted log messages using the date in pin_ebuf_t. You can use these log messages to determine where the error occurred.
See "Finding Errors in Your Code" for more information on how BRM handles error messages.