11 Writing a Custom Data Manager

This chapter describes how to create a new Oracle Communications Billing and Revenue Management (BRM) Data Manager (DM) to access data in a custom data storage systems or a legacy storage system.

You need to create your custom storable objects before creating a new Data Manager.

For more information, see "Creating Custom Fields and Storable Classes".

About Adding a Custom Data Manager

DMs provide a storable object model on top of different underlying storage models. There is a standard interface, Storage Manager (SM), between the generic DM code and the various underlying storage access codes. This section describes the SM interface, which you customize to create a custom Data Manager (DM).

You can add a new DM to the BRM system for the following reasons:

About Mapping Storable Objects to Alternate Storage Mechanisms

BRM is shipped with a standard SM, which provides an interface for mapping storable object operations to any storage paradigm that you require. BRM views the data at the storable object operation level, so there is no effect on the rest of the system when a data set is managed by a custom SM. This flexibility lets you use highly specialized storage paradigms, such as an indexed file system.

About Adding Interfaces to Legacy Systems

BRM allows transparent integration with legacy systems. Operations that are routed to a legacy system for execution appear as storable object manipulations within the BRM system. The interface to the legacy system is written with the same client APIs you use to create custom applications. Only the custom SM, which is the legacy translation module, is aware that the storable object operations are being translated. The fact that the operations are not performed within the BRM system is transparent to all other modules in the system.

You can integrate any type of legacy storage system with BRM. Any type of storable object operation can be defined and sent to the custom SM for translation to the legacy system.

Understanding the Data Manager Interface

To build a new DM, you need to understand:

Calling Conventions

Your custom DMs can be called only from the Base opcodes. The FM opcodes call other underlying opcodes, which in turn call base opcodes which are executed by the DMs. The ops/base.h header file must be included in your application unless the application uses an FM opcode. FM opcodes already include the base opcode header file.

When you create a custom DM you need to implement the base opcodes or a subset of the base opcodes that your DM requires to provide the functionality you want. Each of the DMs included with BRM uses a different Implementation of a base opcode depending on the DM and the storage system it interacts with. For example, the base opcode PCM_OP_SEARCH is implemented differently for dm_oracle and dm_ldap.

For details, see the descriptions of the PCM_OP_SEARCH opcodes in "Base Opcodes" in BRM Developer's Reference.

Data Manager Memory Model

The DM uses shared memory to pass data back and forth between the BRM front-end and back-end (Storage Manager) processes. The DM uses a queuing-based memory management model. For more information about queuing based memory management, see "About Queuing-Based Processes" in BRM System Administrator's Guide.

The DM and QM are separate processes, so external libraries do not have to be multi-thread safe.

For an example of queuing-based processes, see "Example of Queuing in a Client-to-CM Connection" in BRM System Administrator's Guide.

Function Entry Points

The routines described in this section provide the entry points for your custom DM. You must name and define the entry points exactly as shown in the following list. Different underlying storage modules are dynamically linked when you use the dm_sm_obj keyword in the DM configuration file. If this dynamic linking does not work, link the DMs directly using a DM-specific makefile.

dm_if_init_process()

This routine sets up the initial process. It is called when a child DM is started, for example, to connect to a database. It reads in the configuration information from the DM configuration file. This routine uses the following syntax:

void
dm_if_init_process(struct dm_sm_config *confp, int32 *errp)
  

dm_if_process_op()

This routine processes an operation that comes from the CM. This is implemented in the backend. This routine uses the following syntax:

void
dm_if_process_op(
      struct dm_sm_info *dsip,
       int32pcm_op,
       int32pcm_flags,
       pin_flist_t*in_flistp,
       pin_flist_t**out_flistpp,
       pin_errbuf_t*ebufp)
  

dm_if _terminate_connect()

When the CM or the DM is disconnected, this routine is called to clean up the CM connection, for example to rollback a transaction in progress. It is called only when a SIGQUIT signal is sent to the DM main process and by System Manager.

This routine uses the following syntax:

void
dm_if_terminate_connect(
       struct dm_sm_info *dsip,
    int32 *errp)
  

dm_if_terminate_process()

If a custom DM is stopped with a SIGQUIT signal resulting from a kill -QUIT pid' command in the stop script, this routine is called when the DM process is terminated. This routine uses the following syntax:

void
dm_if_terminate_process(int32 *errp)

Argument Descriptions

Table 11-1 describes the arguments used in the DM entry-point routines:

Table 11-1 Arguments Used in DM Entry-Point Routines

Argument Description

confp

Pointer to the structure that contains the information about the DM to SM configuration. It is passed in to dm_if_init_process().

The structure contains the following elements:

  • be_id: ID number of the SM starting from 0.

  • sm_shm_size: Size of the shared memory allocated to this SM. A value of 0 means there is no shared memory allocated to the SM.

  • sm_shm_base: Base shared memory allocated if the sm_shm_size is not 0.

See dm_sm.h for more information.

dsip

Pointer to the structure that contains the information about the DM to SM connection such as the connection state. The structure contains two sets of information, public and private, relevant to the underlying code.

Public information:

  • poidp: Pointer to the POID of the input flist.

  • who: Pointer to the ID of the sender.

  • trans_flag: contains the transaction flags

Private information:

  • pvti: An int for private use.

  • pvtp: Pointer to the SM private area.

See dm_sm.h for more information.

pcm_op

A base PCM opcode. Only the opcodes PCM_OP_CREATE_OBJ through PCM_OP_TRANS_COMMIT defined in the BRM_Home\include\ops\base.h are supported in the DM. BRM_Home is the directory in which you installed BRM components.

pcm_flags

Bit-mask flags that you can set for operations. For information on different flags, see BRM_Home\include\pcm.h.

in_flistp

Input flist pointer. It can be used as it is in pin_flist_xxx functions.

out_flistpp

Output flist pointer. It can be used as it is in pin_flist_xxx functions.

ebufp

Pointer to an error buffer structure. For a definition of the structure, see pcm.h.

ebufp pointing to a pin_err will be PIN_ERR_NONE on entry. Use a different value to indicate an error. Also, if there is an error, specify the rest of the values or clear them.


About Creating a New Data Manager

Use the BRM_SDK_Home/source/templates/dm_temp/dm_generic.c program as a template for your new DM. The dm_generic.c program just echoes any flist sent into it, but it contains all the elements needed for a new DM.

Follow these programming guidelines when writing a new DM.

Handling Errors

You can use one or a combination of the following ways to return failure status to the application.

  • You can set an error condition in the ebuf, which is passed back as the ebuf to the application that calls pcm_op().

  • You can use PIN_ERR_NONE in the ebuf and use a field on the return flist to identify the reason for failure.

When writing a custom DM, follow the BRM conventions for error handling:

  • Set errors in ebuf.

  • Set errors in fields on the return flist so that applications or code that calls it can read the error.

Managing Memory

To allocate storage from the shared memory segment instead of the stack, use pin_malloc(), pin_strdup(), pin_free(), and pin_realloc() routines in each custom DM. This allows the front-end and back-end processes to pass data between them, since the only common portion of their address spaces is the shared memory segment.

Use these routines to manage flists and to do GET/SET or PUT/TAKE flist operations.

For managing memory that is not related to flists, use the standard Solaris/Linux versions of the memory-management routines: malloc(3C), strdup(3C), free(3C), and realloc(3C).

To allocate memory in the shared memory area:

  1. Use the Solaris/Linux pin_malloc(), pin_strdup(), or pin_realloc() routine.

  2. Use the pin_free() routine.

Creating a New Data Manager

To create a new DM, perform the following tasks:

  1. Writing, Compiling, and Linking a Custom DM

  2. Configuring Your Custom DM

  3. Starting and Stopping Your Custom DM

Writing, Compiling, and Linking a Custom DM

  1. Write the new DM code, using BRM_SDK_Home/source/templates/dm_template/dm_generic.c as a template.

  2. Run the make file that accompanies dm_generic.c to compile the custom DM. Edit the make file to refer to the new source file.

Configuring Your Custom DM

  1. Create a directory for your custom DM and copy the compiled .so file to that directory.

  2. Copy the configuration file (pin.conf) from BRM_SDK_Home/sys/dm to the new directory.

  3. Edit the pin.conf file to refer to the new custom DM.

    The file includes information about changing its entries.

Starting and Stopping Your Custom DM

This section provides the steps for creating Start and Stop scripts. In this example, the custom DM is called dm_new.

  1. Go to the BRM_Home/bin directory:

    cd BRM_Home/bin
      
    
  2. Copy the DM start and stop scripts to the BRM_Home/bin/ directory. For example, if BRM is using the Oracle DM:

    cp start_dm_oracle start_dm_new
    cp stop_dm_oracle stop_dm_new
      
    
  3. Create a symbolic link from dm to the dm_new to distinguish custom DM processes from other DM processes:

    ln -s dm dm_new
      
    
  4. Edit the following entries in the start script to reference your custom DM and save it:

    start dm_new
      
    DM=BRM_Home/bin/dm_new
      
    DMDIR=BRM_Home/sys/dm_new
      
    LOGDIR=BRM_Home/var/dm_new
      
    DMLOG=${LOGDIR}/dm_new.log
      
    DMPID=${LOGDIR}/dm_new.pid
      
    
  5. Edit the stop script.

    1. Change the following entries to reference your custom DM:

      stop dm_new
        
      DM=dm_new
        
      LOGDIR=BRM_Home/var/dm_new
        
      DMPID=${LOGDIR}/dm_new.pid
        
      
    2. Change the kill entry to include the QUIT signal:

      kill -QUIT `cat ${DMPID}`
        
      
    3. Save the stop script.

  6. Start your custom DM and verify that the scripts are working:

    start_dm_new
      
    ps -ef | grep new
      
    ...
    cd BRM_Home/var/dm_new
      
    more dm_new.pinlog
    D Thu Mar 12 15:43:51 1999  trainsun10  dm:8241  dm_main.c(1.82):1508
      
    DM dm_name set to "-"
    

Configuring Your CM to Use the Custom DM

In your CM configuration file, add the following entries:

  • dm_pointer, which specifies where to find your DM. Each pointer has three values:

    • Database number, such as 0.0.0.4

    • IP address or host name of the computer running your custom DM

    • Port number of the DM service

    - cm  dm_pointer  0.0.0.1  test_machine  11950
      
    
  • The database number for the custom FM to access. The entry has the name of the FM accessing the custom DM, the name of the configuration entry, and the following values for the database number, which must have the same format as the POID:

    • The database number, such as 0.0.0.2 in the example below. This value is required and must be the same as that of the dm_db_no in the configuration file of the custom DM.

    • The service type such as /cc_db for the credit card processing service. This can be any meaningful text string to identify the custom database and is a placeholder for the POID format.

    • The ID of 0, which is an arbitrary value needed as a placeholder for the POID format.

An example of these entries in the configuration file is as follows:

- fm_bill  cc_db  0.0.0.2  /_cc_db  0

Editing Your Custom Opcodes to Access the Custom DM

If you have written custom opcodes, you need to edit them to access your custom DMs.

For information on editing your custom opcodes, see "Adding and Modifying Policy Facilities Modules".