Coding C and Pro*C Concurrent Programs

Coding C and Pro*C Concurrent Programs

This chapter describes writing a concurrent program in C or Pro*C. It includes utilities you can use along with examples of their usage.

Pro*C Concurrent Programs

When writing a program using C or Pro*C, use the Unified Concurrent Processing API templates EXMAIN.c and EXPROG.c to code your program. See your Oracle E-Business Suite System Administrator's Guide Documentation Set for the exact location of these templates on your operating system.

Unified Concurrent Processing API afprcp()

The templates EXMAIN.c and EXPROG.c provide the correct initialization for your system for your programs. You can use concurrent program execution files written using these templates with either the spawned or immediate execution methods.

To code a custom program, copy the files to your own directory and rename them before changing them. We recommend against modifying the original templates.

EXMAIN.c is the main program which performs initialization and calls your subroutine using the afprcp() function. EXPROG.c is the subroutine which contains your application code.

Replace SUBROUTINE_NAME everywhere it appears in both files with the actual name of your subroutine. You should call afpend() at the end of your subroutine to clean up and return from your concurrent program. The utility afpend() closes the database connection, frees Application Object Library memory, closes Application Object Library files, and returns the status code you specify. You can specify one of three status codes:

Also, include the definition for the bit macro in your include code. This should be:

#define bit(a,b)        ((a)&(b)) 

The following are examples of EXMAIN and EXPROG:

EXMAIN.c

/*==================================================+
 |  Example MAIN for concurrent programs            |
 |  File is in $FND_TOP/usrxit/EXMAIN.c             |
 +==================================================*/
/*--------------------------------------------------+
 |  Copy this file to make a main for your          |
 |  concurrent program.  Replace SUBROUTINE_NAME    |
 |  everywhere (2 places) with the actual name of   |
 |  your concurrent program subroutine.  (This is   |
 |  the same subroutine name you register with      |
 |  Application Object Library.)                    |
 |                                                  |
 |  Do not add or modify any other statements in    |
 |  this file.                                      |
 +--------------------------------------------------*/

#ifndef AFPUB
#include <afpub.h> 
#endif 

#ifndef AFCP
#include <afcp.h> 
#endif 

AFP_FUNCS SUBROUTINE_NAME;

int main(argc, argv)
int argc;
char *argv[];
{
    afsqlopt options;
    
    return(afprcp(argc, argv, (afsqlopt *)NULL,
                         (afpfcn *)SUBROUTINE_NAME));
}

EXPROG.c

/*==================================================+
 |  Example SUBROUTINE for concurrent programs      |
 |  File is in $FND_TOP/usrxit/EXPROG.c             |
 +==================================================*/
/*--------------------------------------------------+
 |  Copy this file to write a subroutine for your   |
 |  concurrent program.  Replace SUBROUTINE_NAME    |
 |  with the actual name of your concurrent program |
 |  (This is the same subroutine name you register  |
 |  with Application Object Library.)               |
 |                                                  |
 |  Remember to register your subroutine and        |
 |  concurrent program with Application Object      |
 |  Library and to add it to a library if you wish  |
 |  it to be run as an immediate program.           |
 |                                                  |
 |  Add your code where indicated.                  |
 |                                                  |
 |  Call afpend() to exit your subroutine.          |
 +--------------------------------------------------*/

#ifndef AFPUB
#include <afpub.h> 
#endif 

#ifndef AFCP
#include <afcp.h> 
#endif 

/*--------------------------------------------------+
 |  Add other include files you need here.          |
 |                                                  |
 |  You will need fddmsg.h if you use Message       |
 |  Dictionary.                                     |
 +--------------------------------------------------*/


boolean SUBROUTINE_NAME(argc, argv, reqinfo)
int  argc;
text  *argv[];
dvoid *reqinfo;
{
/* 
 *  This is the beginning of an example program.
 * If you copied this source to create your program, delete the lines below.
 */
  int i;
  text buffer[241];

  fdpwrt(AFWRT_LOG | AFWRT_NEWLINE, "Hello World.");
  fdpwrt(AFWRT_LOG | AFWRT_NEWLINE, "Hello World.");
  fdpwrt(AFWRT_OUT | AFWRT_NEWLINE, "This is a test! Take one.");
  fdpwrt(AFWRT_OUT | AFWRT_NEWLINE, "This is a test! Take two.");
  fdpwrt(AFWRT_OUT | AFWRT_NEWLINE, 
"-------------------------");


  for ( i = 0; i < argc; i++ ) 
  {
        sprintf(buffer, "argv[%d]: %s", i, argv[i]);
        fdpwrt(AFWRT_OUT | AFWRT_NEWLINE, buffer); 
  }

/*  
 *  This is the end of an example program.
 * If you copied this source to create your program,
 * delete the lines above.
 */


/*--------------------------------------------------+
 |  Add your code here                              |
 +--------------------------------------------------*/

/*--------------------------------------------------+
 |  Finished                                        |
 |                                                  |
 |  Always call afpend() to clean up before         |
 |  returning from your subroutine.                 |
 |                                                  | 
 |   return(afpend(status, reqinfo, message));      |
 |                                                  |
 |  status is FDP_SUCCESS                           |
 |            FDP_ERROR                             |
 |            FDP_WARNING                           |
 |                                                  |
 |  message is a completion message displayed on    |
 |  the View Requests screen when your concurrent   |
 |  program/request completes.  Possible values are |
 |  ""       for successful completion              |
 |  "text"   for text                               |
 |  buffer   for text stored in a buffer            |
 |  afdget() for a message stored in Message        |
 |           Dictionary                             |
 +--------------------------------------------------*/

    return(afpend(FDP_SUCCESS, reqinfo, ""));  
                                /* For successful completion */
}

Accepting Input Parameters

Use the standard argument passing method when you write a Pro*C concurrent program. This method, provided by the Unified Concurrent Processing API, retrieves the parameters you pass to your program, loads them into arvg[] and sets argc, logs onto the database, and loads the user profile option values.

If you want to make your program available through Standard Request Submission, the first parameter you define is in argv[1]. You do not define the parameter in argv[0].

Returning From Your Pro*C Program

When your program completes, you must use Oracle Application Object Library macro afpend() to exit and to change the status of your concurrent request.

The macro afpend() logs your process off of the database, indicates to the concurrent manager whether your program was successful, and writes a completion message to your concurrent request's log file. Note that you should surround the macros with parentheses. If your program was successful, the last statement should be:

return(afpend(FDP_SUCCESS, reqinfo, ""));

The concurrent manager uses this macro to display a Completed/Normal phase/status when a user views this concurrent request in the Requests form. If you do not use afpend() to exit from your program and use exit() instead, the concurrent manager marks the request as Completed/Error.

If your program detects an error and you want to display your own error message text, the last statement should be:

return(afpend(FDP_ERROR, reqinfo, "error_message"));

Your users see a phase/status of Completed/Error on the Requests form.

If your program completes successfully, but detects some exception that needs attention, you can return a status of "WARNING" to indicate the situation. The final phase/status of your request on the Requests form is then Completed/Warning. Your last statement should be:

return(afpend(FDP_WARNING, reqinfo, "error_message"));

If your program detects an error and you want to display an error message from Message Dictionary, the last statements should be:

afdname(application_short_name, message_name);
                return(afpend(FDP_FAILURE, reqinfo, afdget()));

You use the Oracle Application Object Library provided C routines afdget() and afdname() to get the error message you need from Message Dictionary.

The concurrent manager displays this error message in the Completion Text field on Request Detail window of the Requests form.

See: Implementing Message Dictionary

Naming Your Execution File

Use the appropriate file naming convention for your operating system as described in Oracle E-Business Suite Concepts. If your operating system is case-sensitive, your file name should be in uppercase, and some operating systems require file name extensions. The execution file name should match the compile file name of your copy of the EXMAIN.c program.

When you later define your spawned concurrent program executable with Oracle Application Object Library, you define your program with the same name as your file name without an extension as the executable file. For example, on Unix if you name your executable file APPOST, then you must define your concurrent program executable with the execution file field APPOST.

Testing Your Pro*C Program

You can run your concurrent program directly from the operating system without running it through a concurrent manager. Use this method if you want to pass arguments to your program and use default user profile options.

Syntax

PROGRAM user/pwd 0 Y [parameter1] parameter2] ...
Variable Description
PROGRAM The name of your execution file containing your program. This is the name you enter in the Execution File field of the Define Concurrent Program Executable form.
user/pwd The ORACLE username and password that connects you to data that your program uses. Alternatively, an Oracle E-Business Suite username and password with the System Administrator responsibility.
parameter1, 2 ... Program specific parameters. If a parameter contains spaces or double quotes, you must use a special syntax. Refer to your Oracle E-Business Suite System Administrator's Guide Documentation Set for the syntax on your operating system. For example in Unix, you can pass a character string using "This is an example of a \" (double quote)".

Compiling Your Immediate Concurrent Program

Once you compile all the files in your concurrent program, you can leave them as distinct object files, or put them in an object library. You can place your object files or object library in the lib directory under your application's top directory. For executables, you can place them in the bin directory under their application's top directory.

Header Files Used With Concurrent Programs

Oracle Application Object Library uses the following system of C program header files. Your spawned and immediate C programs, as well as any user exits written in C, should follow the following header conventions.

The following table lists the header files used with C APIs.

Header File Comments
afpub.h The primary header file for Oracle Application Object Library API's. Include with all C programs accessing Oracle Application Object Library routines.
afcp.h The header file used with concurrent programs using the supplied C API's for concurrent processing. All Pro*C programs used in concurrent processing should include this header file.
afuxit.h The header used with C API's used in user exits. All Pro*C user exits should include this header file.
afufld.h The header file containing the get/put field value functions. Use this header file with <afuxit.h>. All Pro*C user exits should include this header file.
fddutl.h The header file used with message dictionary code. All Pro*C programs accessing the message dictionary feature should include this header.
fdpopt.h The header file used to access profile options. All Pro*C programs accessing profile options should include this header.

If you have custom APIs that call other header files, ensure you use the appropriate headers.

Concurrent Processing Pro*C Utility Routines

This section describes C routines that you can use in your concurrent programs. Some of these routines are optional, and some are required and depend on the type of concurrent program you are writing. This section also includes examples of Pro*C concurrent programs.

Important: Do not call fdpscr(), fdpwrt(), or other concurrent manager functions from user exits. The only supported interface is request submission via the PL/SQL stored procedure API, which you can code from your form.

For information on user profile C options afpoget() and afpoput(), see the User Profiles chapter. See: Overview of User Profiles.

afpend()

#include <afcp.h> 
return(afpend(status, reqinfo, message));

Description

Call the function afpend() at the end of your subroutines written with the unified concurrent processing API templates. Use afpend to clean up and return from your concurrent program with a status code and completion message. It closes the database connection, frees Application Object Library memory, closes Application Object Library files and returns the specified status code.

Return Value

This function returns TRUE if it is successful, and returns FALSE if an error occurs.

Arguments

Example

/*   use afpend to return messages with a success code */
    char errbuf[241];

    if (!submit())
    {
        /* return failure with a message */
        return(afpend(FDP_ERROR, reqinfo,
              "Failed in submit()"));
    }
    else if (!setprofiles())
    {
        /* return warning with a message */
        return(afpend(FDP_WARNING, reqinfo, 
               "Failed in setprofiles()"));
    }
    else if (!subrequest(argc, argv, reqinfo, errbuf))
    {
        /* return failure with a message */
        return(afpend(FDP_ERROR, reqinfo, errbuf));
    }
    else
    {
        /* Successful completion. */
        return(afpend(FDP_SUCCESS, reqinfo, ""));
    }

fdpfrs()

afreqstate fdpfrs (request_id, errbuf);
text request_id;
text errbuf;

Description

The fdpfrs() command returns the status of a specific request id. Us this command with the return status macros ORAF_REQUEST_XXX.

Return Value

This function returns the state of the request id passed as an argument.

Arguments

Example

#ifndef AFPUB
#include <afpub.h>
#endif

#ifndef AFCP
#include <afcp.h>
#endif

boolean check_request_status(request_id, errbuf)
text* request_id;
text* errbuf;

{
afreqstate request_status;

request_status = fdpfrs(request_id, errbuf);

If (ORAF_REQUEST_TEST_FAILURE(request_status) ||
        ORAF_REQUEST_NOT_FOUND(request_status))
        return FALSE;

if (ORAF_REQUEST_COMPLETE(request_status) &&
        (ORAF_REQUEST_NORMAL(request_status))
        return TRUE;

return FALSE;
}

fdpscp()

#include <afcp.h>

boolean fdpscp( argc_ptr, argv_ptr, args_method, errbuf)
int     *argc_ptr;
char    **argv_ptr[];
text    args_method;
text    *errbuf;        

Description

This function exists for compatibility with concurrent programs written with prior versions of Oracle Application Object Library. When writing new concurrent programs, use the unified concurrent processing API.

The function fdpscp() was called in the first statement of any spawned Pro*C concurrent program. This function retrieves the parameters your program expects, loads them into the argv[] array, and prints a standard header including the run date and time in the log file. It also logs your program onto the database. This function connects your program to the database using the ORACLE ID that is assigned to the application with which your concurrent program is defined.

Return Value

This function returns TRUE if it successfully retrieves all the parameters your concurrent request is called with. Otherwise, it returns FALSE. If this function returns FALSE, your concurrent program should print the contents of errbuf and exit with failure.

Arguments

Example

#include     <afcp.h>
/*  This is an example of a Pro*C concurrent program.  This
         sample program prints its input parameter to the 
         log file.      */
routine()
{
        text    args_method = (text)'\0';
        text    errbuf[241];

        if (!fdpscp( &argc, &argv, args_method, errbuf ) ){
                fdpwrt( AFWRT_LOG | AFWRT_NEWLINE,
                        "Error calling fdpscp" );
                fdpwrt( AFWRT_LOG | AFWRT_NEWLINE, errbuf );
                return(afpend(FDP_ERROR, reqinfo, "Failed to get 
                arguments"));
        }
        if (!fdpwrt(AFWRT_LOG | AFWRT_NEWLINE, argv[1] )) {
                return(afpend(FDP_ERROR, reqinfo, "Failed to write 
                arguments"));
        }
        {return(afpend(FDP_SUCCESS, reqinfo, ""));}
}

fdpscr()

#include <afcp.h>
boolean fdpscr( command, request_id, errbuf )
text    *command;
text    *request_id;
text    *errbuf; 

Description

The fdpscr() function submits a request to run a concurrent program. You can only call this function from a Pro*C concurrent programs. The user profile options of the child request default to those of the parent concurrent program. You must commit after you call this function for your request to become eligible to be run by a concurrent manager. If you perform a rollback without having committed, your request will be lost.

Return Value

If fdpscr() successfully submits your concurrent request, it returns TRUE. Otherwise, fdpscr() returns FALSE.

Arguments

Example

/* Submit request */
  if (!fdpscr( command, request_id, errbuf))
  {
       fdpwrt( AFWRT_LOG | AFWRT_NEWLINE,
                    "Failed to submit concurrent request");
       fdpwrt( AFWRT_LOG | AFWRT_NEWLINE, errbuf);

       return(FALSE);
   }
   else  /* Successful completion */
   {

       sprintf(errbuf, "Concurrent request %s submitted
                            successfully", request_id);
       fdpwrt( AFWRT_LOG | AFWRT_NEWLINE, errbuf);

       return(TRUE);
    }

fdpwrt()

#include fdpwrt.h
boolean fdpwrt( flag, message)
fdcoflgs        flags
text            *message; 

Description

The fdpwrt() function writes a text string to a standard log or report output file. You do not need to explicitly open and close the file. Oracle Application Object Library names your log or report output file in the standard naming convention as described in the Oracle E-Business Suite Concepts manual.

Return Value

The function fdpwrt() returns FALSE if it cannot write your message to the file that you specify. Otherwise, fdpwrt() returns TRUE.

Arguments

Example

/* Submit request */
  if (!fdpscr( command, request_id, errbuf))
  {
       fdpwrt( AFWRT_LOG | AFWRT_NEWLINE,
                    "Failed to submit concurrent request");
       fdpwrt( AFWRT_LOG | AFWRT_NEWLINE, errbuf);

       return(FALSE);
   }
   else  /* Successful completion */
   {

       sprintf(errbuf, "Concurrent request %s submitted
                            successfully", request_id);
       fdpwrt( AFWRT_LOG | AFWRT_NEWLINE, errbuf);

       return(TRUE);
    }