Previous Topic: OutputNext Topic: Using a C Proxy


Proxy.c

The following is an example of a C proxy program using Decimal Precision attribute. This code is hand-written not generated.

/*
 * This sample's purpose is to provide a C programmer a starting
 * point for coding a C proxy routine.
 *
 * This sample builds upon the CA (R) Gen sample model that is included
 * with the CA Gen Toolset. The Gen server module used by this proxy
 * example is packaged within the sample model as load module P900. This proxy
 * example will only exercise a small amount of the sample models capabilities.
 *
 *  This example application performs the following actions:
 *  - delDiv  - deletes 4 division name records based on data specified in
 *              the import view. Implemented in the delete() function.
 *  - addDiv  - adds four division name records based on data specified in the
 *              import view. Implemented in the add() function.
 *  - readDiv - retrieves division name records and moves them to the export
 *              repeating group view. Implemented in the read function.
 *  - check   - the check function extracts data from the returned export
 *              view depending upon the delete/add/read operation just executed
 *
 * - The import view assignment statements are hard coded. In your
 *   application you will probably use a GUI interface to query for
 *   values.
 *
 * - The export views are displayed on the screen. In your application
 *   you will probably use a GUI interface to display these values.
 *
 * NOTE:  Variable Name Case Sensitivity
 *
 * The C Proxy API uses case sensitivity to use the procedure step name
 * as multiple variable names. If you use this sample C program as a basis
 * for your program, take care to "match case" when replacing variable names.
 *
 * For example:
 *
 * - SERVER_DETAIL_DIVISION is used to represent the TranEntry data structure
 *   which contains all the information needed for a transaction (such as
 *   trancode and model name).
 *
 * - server_detail_division is used to represent the transaction specific
 *   view data structure which will be used to reference import and export
 *   views.
 *
 *
 * This proxy example is designed to communicate with a server packaged
 * within the CA Gen sample model which is included with the product
 * distribution. The sample model's Cooperative Server load module P900
 * must be generated and installed within the target environment to which
 * this C proxy is to communicate, prior to attempting to execute this
 * sample.
*/

/* Include the Gen C Proxy generated header file created from the
 * sample model included with the product distribution
*/

#include "p900.h"

/* the following value is one of the returned exit state values. It's
 * definition was obtained from server generated code. Additional exit state
 * values could be obtained if desired.
*/
#define gui_return_from_link 219941543


/* Include other standard libraries as needed */
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef WIN32
/* for Windows */
#include <windows.h>
#define SLEEP(i) Sleep(i*1000)
#else
/* for UNIX    */
#include <unistd.h>
#define SLEEP(i) sleep(i)
#endif


/* Contains communication information */
static ProxyParam*       psParamBlock; 

/* Used to store a communication configuration string */
char      comcfg[256]; 

/* Error message length can be from 0-2048 this will determine 
 * how much of the error message will be returned by ProxyExecute.
 * A shorter message may be returned depending on the error.      
*/
#define   errMsgLen 2048
char      errMsg[errMsgLen];  

/* Return code from routines  {Failure, Success}
 * ProxyExecuteReturnValues is defined in the proxyexe.h file supplied
 * with the Gen installation.
*/
ProxyExecuteReturnValues ReturnVal;


/* Misc defines */
int       nRC;            /* Integer return code */

char      ClientUserid[ProxyClientUseridLen+1]= "MYUSER";      
char      ClientPassword[ProxyClientPasswordLen+1]= "123";  
char      Dialect[ProxyDialectLen + 1] = "DEFAULT";              
char      NextLocation[ProxyNextLocationLen+1] = "TEST";      
/* Command is one of A (add), D (delete), R (read) */
char      Command[ProxyCommandLen+1] = " ";                
long      ExitStateNum;                              
MsgType   ExitMsgType;                               
char      ExitStateMsg[ProxyExitStateMsgLen+1];      
char      OutClientUserid[ProxyClientUseridLen+1];      
char      OutClientPassword[ProxyClientPasswordLen+1];  
char      OutDialect[ProxyDialectLen + 1];              
char      OutNextLocation[ProxyNextLocationLen+1];      
char      OutCommand[ProxyCommandLen+1];                
long      OutExitStateNum;                              
MsgType   OutExitMsgType;                               
char      OutExitStateMsg[ProxyExitStateMsgLen+1];  
   

/* local function prototypes */
ProxyExecuteReturnValues addDiv();    
ProxyExecuteReturnValues delDiv();    
ProxyExecuteReturnValues readDiv();    
void check();

int main (void)
{

   printf ("Beginning of sample C proxy application \n\n");


/************************************************************************/
/*                                Setup                                 */

/* ProxyStartTracing opens a file for debug/status information.
 * ProxyStopTracing will be used to close the file.
 * This function is optional, but must be called before ProxyTraceOut
 * if used
 *    - The first parameter must be valid filename, the file will be
 *      created
 *    - The second parameter is the trace level.
 *      0xFFFFFFFF requests the highest (verbose) level of messages. 
 *      NULL indicates that the value of the CMIDEBUG environment
 *      variable should be used to determine the trace level
 * Functions which return with a Failure status will generally write
 * detailed information regarding the failure to the trace file.
*/

   ProxyStartTracing((char *) "cproxy.out", (char*)"0xFFFFFFFF");  
  
/* ProxyTraceOut writes a message to the trace file. These
 * messages will be interspersed with standard debugging messages.
 * This function call is optional.
 */

   ProxyTraceOut(NULL, (char *) "CPROXY.C - *****  Beginning program");



/* ProxyAllocateParamBlock is used to create the parameter block
 * (data structure) which contains information required for the
 * transaction. A NULL return indicates an error in the creation
 * of the parameter block.
 * This function call is required.
*/

   psParamBlock = ProxyAllocateParamBlock();
   if (NULL == psParamBlock)
   {
      printf("Unsuccessful return from ProxyAllocateParamBlock\n");
      return (Failure);
   }


/* ProxySetClientUserid is used to set a userid in the parameter block.
 * This function call is required if security on the server is used,
 * otherwise it is optional.
*/
                         
   nRC = ProxySetClientUserid(psParamBlock, ClientUserid);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxySetClientUserid\n");
      return (Failure);
   }

/* ProxySetClientPassword is used to set a password in the parameter
 * block.
 * This function call is required if security on the server is used,
 * otherwise it is optional.
*/

   nRC = ProxySetClientPassword(psParamBlock, ClientPassword);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxySetClientPassword\n");
      return (Failure);
   }

/* ProxySetDialect is used to set the dialect in the parameter block.
 * This function call is optional.
*/

   nRC = ProxySetDialect(psParamBlock, Dialect);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxySetDialect\n");
      return (Failure);
   }

/* ProxySetNextLocation is used to set the next location in the parameter
 * block.
 * This function call is optional.
*/

   nRC = ProxySetNextLocation(psParamBlock, NextLocation);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxySetNextLocation\n");
      return (Failure);
   }

/* ProxySetCommand is used to set the command in the parameter block.
 * This function call is optional.
*/

   nRC = ProxySetCommand(psParamBlock, Command);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxySetCommand\n");
      return (Failure);
   }

#ifndef TUXEDO
/* NOTE: ProxyConfigureComm() must not be called if targeting a Tuxedo Server
  * environment. Tuxedo environment does not support retargeting the server.
*/

/* ProxyConfigureComm is used to set communication options.
 * This function call is optional, communication options can be set in
 * the following ways:
 * - by specifying the options in the SERVER_DETAIL_DIVISION structure
 *   without a call to ProxyConfigureComm
 * - by calling ProxyConfigureComm with a NULL third parameter to
 *   indicate that the file commcfg.ini should be used
 * - by calling ProxyConfigureComm with a string containing the
 *   Comm Service Type, Host and Port as the third parameter
*/

/* This call to ProxyConfigureComm will use the file commcfg.ini
 * NOTE: the commcfg.ini file must contain a valid override entry
 * if this call is to succeed.
*/

   nRC = ProxyConfigureComm(&SERVER_DETAIL_DIVISION, SERVER_DETAIL_DIVISION.service, NULL);
   if (nRC == FALSE)
   {
      printf("Unsuccessful return from ProxyConfigureComm using File\n");
      return (Failure);
   }

/*  This call to ProxyConfigureComm will use the string containing the
 *  Comm Service Type, Host and Port to set communication
 *  options. Be sure to include a space between each token.
*/

    strcpy( comcfg, "TCP " );     /* Comm Service Type */
    strcat( comcfg, "hostname " );  /* Host              */
    strcat( comcfg, "port#" );    /* Port              */

    nRC = ProxyConfigureComm(&SERVER_DETAIL_DIVISION, SERVER_DETAIL_DIVISION.service, comcfg);

   if (nRC == FALSE)
   {
      printf("Unsuccessful return from ProxyConfigureComm using comcfg string \n");
      return (Failure);
   }
#endif /* ! TUXEDO */


/* The ProxyClear set of functions are used to clear the parameter block.
 * Each part of the parameter block can be cleared individually, or the
 * ProxyClearParamBlock function can be used to clear the entire
 * parameter block.
 * These function calls are optional.
 * The ProxyClearParamBlock function would replace the other ProxyClear
 * functions shown further below.
*/
    nRC = ProxyClearParamBlock(psParamBlock);
    if (nRC == Failure)
    {
      printf("Unsuccessful return from ProxyClearParamBlock\n");
      return (Failure);
    }


/* Function specific to this proxy example
 * Deletes the division name records which will be added by the addDiv
 * Note: delete will call ProxyClearParamBlock
*/
   delDiv();

   SLEEP(2);

/* Function specific to this proxy example
 * add several divisions
 * Note: add will call ProxyClearParamBlock
 */
   addDiv();

   SLEEP(2);

/* Function specific to this proxy example
 * read back the divisions just added
 * Note: read will call ProxyClearParamBlock
 */
   readDiv();


/* For sample purposes, the set of individual ProxyClear functions are shown
 * below
*/
   nRC = ProxyClearClientUserid(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearClientUserid\n");
      return (Failure);
   }

   nRC = ProxyClearClientPassword(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearClientPassword\n");
      return (Failure);
   }

   nRC = ProxyClearDialect(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearDialect\n");
      return (Failure);
   }

   nRC = ProxyClearNextLocation(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearNextLocation\n");
      return (Failure);
   }

   nRC = ProxyClearCommand(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearCommand\n");
      return (Failure);
   }

   nRC = ProxyClearExitStateMsg(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearExitStateMsg\n");
      return (Failure);
   }

   nRC = ProxyClearExitStateNum(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearExitStateNum\n");
      return (Failure);
   }

   nRC = ProxyClearExitMsgType(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearExitMsgType\n");
      return (Failure);
   }

/* The ProxyDeleteParamBlock function is used to delete the psParamBlock
 * structure.
 * This function call is optional, but recommended.
*/
   nRC = ProxyDeleteParamBlock(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyDeleteParamBlock\n");
      return (Failure);
   }

/*  ProxyStopTracing is used to close the trace file opened by
 *  ProxyStartTracing.
 *  This function is optional, but is recommended if ProxyStartTracing is
 *  used.
*/
   ProxyStopTracing();

   printf ("\nEnding program cproxy \n");
   return (TRUE);
}


/* addDiv()
 * This function is specific to this proxy example.
 * It attempts to add 4 division records
*/

ProxyExecuteReturnValues addDiv()
{

   /* Add Divisions */
   int count;

   printf("Adding test divisions\n");

   strcpy(Command,"A"); /* Add */
   strcpy(server_detail_division.importRequest_command.value, Command);


   /* add 4 Divisions */
   for (count = 0; count <= 3; count++ )
   {
      /* use Numbers 90-93 */
      server_detail_division.import_division.number = 90+count;
      sprintf(server_detail_division.import_division.name, "Test Divison %d", count);

      /* in case there are no employes in the database  use 0*/
      server_detail_division.import_employee.number = 0;

      /* clear the parameter block */
      nRC = ProxyClearParamBlock(psParamBlock);
      if (nRC == Failure)
      {
        printf("Unsuccessful return from ProxyClearParamBlock\n");
        return (Failure);
      }

    
/*  Transaction processing
 *  ProxyExecute sends the transaction to the server and returns export 
 *  data and messages. This function use the following parameters:
 *  - SERVER_DETAIL_DIVISION transaction structure which contains
 *    import and export views
 *  - psParamBlock parameter structure which contain communication
 *    information
 *  - errMsg will return any error message from the server
 *  - errMsgLen specifies the number of characters to write to errMsg
 *    This function call is required. The return value is Success or
 *    Failure
*/
      if (ProxyExecute(&SERVER_DETAIL_DIVISION, psParamBlock, errMsg, errMsgLen) != Success)
      {
         printf("Unsuccessful return from ProxyExecute \n");
         printf("errMsg = %s\n",errMsg);
         ProxyTraceOut(NULL, errMsg);
         return (Failure); 
      }
      else /* check results */
         check();
   }

   return (Success);
}

/* readDiv()
 * This function is specific to this proxy example.
 * read all divisions, returning division name and number
 * The server returns the data in a repeating group view.
 * If the previous add was successful there should be
 * at least four divisions present. The check() function
 * will extract the data read from the repeating group view.
*/
ProxyExecuteReturnValues readDiv()
{
   printf("Reading test divisions\n");

#ifndef TUXEDO
/* NOTE: ProxyConfigureComm() must not be called if targeting a Tuxedo Server
  * environment. Tuxedo environment does not support retargeting the server.
*/

/* setup to use SERVER_MAINTAIN_DIVISION
 * This read uses a different procedure step than did delDiv/addDiv, so
 * must call ProxyConfigureComm() to initialize for the desired
 * procedure step
*/
   nRC = ProxyConfigureComm(&SERVER_MAINTAIN_DIVISION,
                               SERVER_MAINTAIN_DIVISION.service, comcfg);

   if (nRC == FALSE)
   {
      printf("Unsuccessful return from ProxyConfigureComm using comcfg string\n");
      return (Failure);
   }

#endif /* !TUXEDO */

   strcpy(Command,"R");

/* non space implies server is to return sorted data */
   strcpy(server_maintain_division.importSortWrk_sorting.sort_sequence, "S");

/* clear the paramater block */
   nRC = ProxyClearParamBlock(psParamBlock);
   if (nRC == Failure)
   {
      printf("Unsuccessful return from ProxyClearParamBlock\n");
      return (Failure);
   }

/*  Transaction processing
 *  ProxyExecute sends the transaction to the server and returns export 
 *  data and messages. This function use the following parameters:
 *  - SERVER_MAINTAIN_DIVISION transaction structure which contains
 *    import and export views
 *  - psParamBlock parameter structure which contain communication
 *    information
 *  - errMsg will return any error message from the server
 *  - errMsgLen specifies the number of characters to write to errMsg
 *    This function call is required. The return value is Success or
 *    Failure
*/
   if (ProxyExecute(&SERVER_MAINTAIN_DIVISION, psParamBlock,
                                               errMsg, errMsgLen) != Success)
   {
      printf("Unsuccessful return from ProxyExecute \n");
      printf("errMsg = %s\n",errMsg);
      ProxyTraceOut(NULL, errMsg);
      return (Failure); 
   }
   check();

   return (Success);
}

/* delDiv()
 * This function is specific to this proxy example.
 * Attempts to delete the four division records that addDiv() will then add.
 * Hard coded to delete division 90-93, which may or may not exist.
*/
ProxyExecuteReturnValues delDiv()
{
   int count;

   printf("Deleting test divisions\n");
   strcpy(Command,"D"); /* Delete */

   strcpy(server_detail_division.importRequest_command.value, Command);

   for (count = 0; count <=3; count ++)
   {
     
      server_detail_division.import_division.number = 90 + count;
      printf("  Attempting to Delete Division %d\n",
                  server_detail_division.import_division.number);

      nRC = ProxyClearParamBlock(psParamBlock);
      if (nRC == Failure)
      {
         printf("Unsuccessful return from ProxyClearParamBlock\n");
         return (Failure);
      }

/*  Transaction processing
 *  ProxyExecute sends the transaction to the server and returns export 
 *  data and messages. This function use the following parameters:
 *  - SERVER_DETAIL_DIVISION transaction structure which contains
 *    import and export views
 *  - psParamBlock parameter structure which contain communication
 *    information
 *  - errMsg will return any error message from the server
 *  - errMsgLen specifies the number of characters to write to errMsg
 *    This function call is required. The return value is Success or
 *    Failure
*/
      if (ProxyExecute(&SERVER_DETAIL_DIVISION, psParamBlock, errMsg, errMsgLen) != Success)
      {
         printf("Unsuccessful return from ProxyExecute \n");
         printf("errMsg = %s\n",errMsg);
         ProxyTraceOut(NULL, errMsg);
         return (Failure); 
      }
   }
   printf("\n");
   return (Success);
}

/* check()
 * This function is specific to this proxy example.
 * check the results of the ProxyExecute()
*/
void check()
{

   int loop=0;

/* The ProxyGet set of functions are used to query the various data items
 * within parameter block.
 * These function calls are optional.
*/
    strcpy(OutClientUserid,ProxyGetClientUserid(psParamBlock));
    strcpy(OutClientPassword, ProxyGetClientPassword(psParamBlock));
    strcpy(OutDialect, ProxyGetDialect(psParamBlock));
    strcpy(OutNextLocation, ProxyGetNextLocation(psParamBlock));
    strcpy(OutCommand, ProxyGetCommand(psParamBlock));
    OutExitStateNum = ProxyGetExitStateNum(psParamBlock);
    OutExitMsgType = ProxyGetExitMsgType(psParamBlock);
    strcpy(OutExitStateMsg, ProxyGetExitStateMsg(psParamBlock));

/* processing a delete command */
    if (strcmp(Command, "D") == 0)
    {

/* did server set an exit state? If so, delete failed */
       if (OutExitStateNum != 0)
       {
          printf("OutExitStateNum=%d\n", OutExitStateNum);
          printf("OutExitStateMsg=%s\n", OutExitStateMsg);
       }
       else
          printf("Delete successful\n");
       return;
    }

/* processing the add command */
    if (strcmp(Command, "A") == 0)
    {
       if (OutExitStateNum == gui_return_from_link)
       {
          printf(" Division successfully added\n");
          printf("    Exit State Number | Divsion: Number    Name\n");
          printf("  ----------------------------------------------------------\n");
          printf("   %d", OutExitStateNum);
          printf("\t\t\t    %d", server_detail_division.export_division.number);
          printf("      %s\n\n", server_detail_division.export_division.name);
       }
       else /* error */
       {
          printf("OutExitStateNum=%d\n", OutExitStateNum);
          printf("OutExitStateMsg=%s\n", OutExitStateMsg);
          return;
       }
    }

    /* processing the read repeating group view */
    if (strcmp(Command, "R") == 0)
    {
       printf("  List of Divisions\n");
       if (server_maintain_division.allOutput.cardinality > 0)
       {
          printf("    Number    Name\n");
          printf("  ------------------------------\n");
          for (loop = 0; loop < server_maintain_division.allOutput.cardinality; loop++ )
          {
            printf("    %d", server_maintain_division.allOutput.export_division.number[loop]);
            printf("         %s\n", server_maintain_division.allOutput.export_division.name[loop]);
          }
       }
       else
          printf("\tNo Data Found\n");
    }
}