This chapter describes writing a concurrent program in C or Pro*C. It includes utilities you can use along with examples of their usage.
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. Refer to the Oracle E-Business Suite Setup Guide for the exact location of these templates on your operating system.
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:
FDP_SUCCESS
FDP_ERROR
FDP_WARNING
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 */ }
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].
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
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.
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 the Oracle E-Business Suite Setup Guide 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)". |
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.
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.
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.
#include <afcp.h> return(afpend(status, reqinfo, message));
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.
This function returns TRUE if it is successful, and returns FALSE if an error occurs.
status - The status code you want to return. Valid status codes are FDP_SUCCESS, FDP_WARNING AND FDP_ERROR.
reqinfo message - The completion message displayed on the View Requests screen when your concurrent request completes. Possible message values are:
"" - No content, for successful completion.
"text" - For text.
buffer - For text stored in a buffer.
afdget() - For a message stored in the Message Dictionary.
/* 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, "")); }
afreqstate fdpfrs (request_id, errbuf); text request_id; text errbuf;
The fdpfrs() command returns the status of a specific request id. Us this command with the return status macros ORAF_REQUEST_XXX.
This function returns the state of the request id passed as an argument.
request_id - A null terminated string containing the request ID you want to inquire about.
errbuf - A character string returned by fdpfrs() that contains an error message if fdpfrs() fails. You should declare effbuf to be size 241.
#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; }
#include <afcp.h> boolean fdpscp( argc_ptr, argv_ptr, args_method, errbuf) int *argc_ptr; char **argv_ptr[]; text args_method; text *errbuf;
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.
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.
argc_ptr - A pointer to argc, the first argument to main(). You should call fdpscp() using &argc.
argv_ptr - A pointer to argv, the second argument to main(). You should call fdpscp() using &argv.
args_method - This parameter is not currently used. You should initialize it to (text)'\0'.
errbuf - A character string returned by fdpscp() that contains an error message if fdpscp() returns FALSE. You should declare errbuf[] to be size 241.
#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, ""));} }
#include <afcp.h> boolean fdpscr( command, request_id, errbuf ) text *command; text *request_id; text *errbuf;
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.
If fdpscr() successfully submits your concurrent request, it returns TRUE. Otherwise, fdpscr() returns FALSE.
command - A character string that contains the parameters to your concurrent program, preceded by the word CONCURRENT. You should use the same command you use when you call a concurrent program from a form, omitting the #FND.
request_id - A character string returned by fdpscr() that contains the request id that is assigned to your concurrent request. You should declare request_id[] to be size 12.
errbuf - A character string returned by fdpscr() that contains an error message if fdpscr() returns FALSE. You should declare errbuf[] to be size 214.
/* 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); }
#include fdpwrt.h boolean fdpwrt( flag, message) fdcoflgs flags text *message;
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.
The function fdpwrt() returns FALSE if it cannot write your message to the file that you specify. Otherwise, fdpwrt() returns TRUE.
flag - A macro you use to specify what file you want to write to.
AFWRT_LOG writes to a log file. AFWRT_OUT writes to a report output file.
You can choose options to flush the buffer or add a newline character. Use | (bitwise OR) to turn an option on, and use &~ (bitwise AND NOT) to turn an option off.
AFWRT_FLUSH flushes the buffer to the file automatically after each call. By default, AFWRT_FLUSH is on for log files and off for report output files. AFWRT_NEWLINE adds a newline character (\n) at the end of the string in the buffer before flushing the buffer. By default, AFWRT_NEWLINE is off.
message - A null-terminated character string.
/* 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); }