Table of Contents Previous Next


Table of Contents

Introduction to Oracle Tuxedo Programming
Oracle Tuxedo Distributed Application Programming
Figure 1‑1 Distributed Application Example - Online Banking System
Communication Paradigms
Oracle Tuxedo Clients
Listing 1‑1 Pseudo-code for a Request/Response Client
Oracle Tuxedo Servers
Basic Server Operation
Figure 1‑2 Pseudo-code for a Request/Response Server and a Service Subroutine
Figure 1‑3 Pseudo-code for a Conversational Service Subroutine
Servers as Requesters
Oracle Tuxedo API: ATMI
Managing Typed Buffers
Overview of Typed Buffers
See Also
Allocating a Typed Buffer
Listing 2‑1 Allocating a VIEW Typed Buffer
Listing 2‑1 Allocating a VIEW Typed Buffer
Listing 2‑2 Allocating an FML Typed Buffer
Listing 2‑3 Allocating a CARRAY Typed Buffer
Listing 2‑4 Allocating a STRING Buffer
Listing 2‑5 Allocating a RECORD Buffer
See Also
Putting Data in a Buffer
Listing 2‑6 Putting Data in a Message Buffer - Example 1
Listing 2‑6 Putting Data in a Message Buffer - Example 1
Listing 2‑7 Placing Data in a Message Buffer - Example 2
See Also
Resizing a Typed Buffer
Listing 2‑8 Resizing a Buffer
Listing 2‑8 Resizing a Buffer
Listing 2‑9 Error Checking for tprealloc()
See Also
Checking for Buffer Type
Listing 2‑10 Getting Buffer Size
Listing 2‑10 Getting Buffer Size
See Also
Freeing a Typed Buffer
Listing 2‑11 Freeing a Buffer
Listing 2‑11 Freeing a Buffer
See Also
Using a VIEW Typed Buffer
Setting Environment Variables for a VIEW Typed Buffer
Creating a View Description File
Listing 2‑12 View Description File for FML VIEW
Listing 2‑13 View Description File for an Independent View
Executing the VIEW Compiler
Listing 2‑14 Header File Created Using the VIEW Compiler
See Also
Using a RECORD Typed Buffer
Setting Environment Variables for a RECORD Typed Buffer
Creating a Copybook File
Generating the RECORD Description File
See Also
Using an FML Typed Buffer
Setting Environment Variables for an FML Typed Buffer
Creating a Field Table File
Listing 2‑15 Field Table File for FML VIEW
Creating an FML Header File
Listing 2‑16 myview.flds.h Header File
Listing 2‑16 myview.flds.h Header File
/* fname fldid *//* ----- ----- */ #define FLOAT1 ((FLDID)24686) /* number: 110 type: float */#define DOUBLE1 ((FLDID)32879) /* number: 111 type: double */#define LONG1 ((FLDID)8304) /* number: 112 type: long */#define SHORT1 ((FLDID)113) /* number: 113 type: short */#define INT1 ((FLDID)8306) /* number: 114 type: long */#define DEC1 ((FLDID)41075) /* number: 115 type: string */#define CHAR1 ((FLDID)16500) /* number: 116 type: char */#define STRING1 ((FLDID)41077) /* number: 117 type: string */#define CARRAY1 ((FLDID)49270) /* number: 118 type: carray */#define   BOOL1#define   SIGNEDCHAR1#define   UNSIGNEDCHAR1#define   WCHAR_T1#define   UNSIGNEDINT1#define   UNSIGNEDLONG1#define   LONGLONG1#define   UNSIGNEDLONGLONG1#define   LONGDOUBLE1#define   STRUCT1
See Also
Using an XML Typed Buffer and the Apache Xerces C++ Parser
About the XML Typed Buffer
About the Apache Xerces C++ Parser
XML Parser Control
XML Parser Support for ICU
XML Parser Sample Application
Xerces Schema Sample
See Also
Converting XML Data To and From FML/FML32 Buffers
Using On-Demand Conversion
Initiating On-Demand Conversion
On-Demand Conversion and Xerces Parser XML Validation
Using Automatic Conversion
Initiating Automatic Conversion
Automatic Conversion and Xerces Parser XML Validation
Listing 2‑17 Sample Input for TXPARSFILE Environment Variable
Mapping XML To and From FML/FML32 Field Types
Conversion Limitations
See Also
Using an MBSTRING Typed Buffer
Figure 2‑1 Encoding Conversion Using MBSTRING Buffers—Example
Figure 2‑1 Encoding Conversion Using MBSTRING Buffers—Example
Multibyte Character Encoding Control
Figure 2‑2 Allocating and Sending an MBSTRING Buffer
Figure 2‑3 Receiving and Converting an MBSTRING Buffer (Sheet 1 of 2)
Figure 2‑3 Receiving and Converting an MBSTRING Buffer (Sheet 2 of 2)
Enabling MBSTRING to be Self-describing
Implementation
Safe/Unsafe Encoding Names
Multibyte Character Support Limitations
Multibyte Character Encoding Support for libiconv
See Also
Customizing a Buffer
Defining Your Own Buffer Types
Listing 2‑18 Default Buffer Type Switch
Listing 2‑18 Default Buffer Type Switch
Listing 2‑18 Default Buffer Type Switch
Listing 2‑19 Buffer Type Structure
/* * The following definitions are in $TUXDIR/include/tmtypes.h */#define TMTYPELEN ED_TYPELEN #define TMSTYPELEN ED_STYPELENstruct tmtype_sw_t {   char type[TMTYPELEN]; /* type of buffer */   char subtype[TMSTYPELEN]; /* subtype of buffer */   long dfltsize; /* default size of buffer */   /* buffer initialization function pointer */   int (_TMDLLENTRY *initbuf) _((char _TM_FAR *, long));   /* buffer reinitialization function pointer */   int (_TMDLLENTRY *reinitbuf) _((char _TM_FAR *, long));   /* buffer un-initialization function pointer */   int (_TMDLLENTRY *uninitbuf) _((char _TM_FAR *, long));   /* pre-send buffer manipulation func pointer */   long (_TMDLLENTRY *presend) _((char _TM_FAR *, long, long));   /* post-send buffer manipulation func pointer */   void (_TMDLLENTRY *postsend) _((char _TM_FAR *, long, long));   /* post-receive buffer manipulation func pointer*/   long (_TMDLLENTRY *postrecv) _((char _TM_FAR *, long, long));   /* XDR encode/decode function pointer */   long (_TMDLLENTRY *encdec) _((int, char _TM_FAR *, long, char _TM_FAR *, long));   /* routing function pointer */   int (_TMDLLENTRY *route) _((char _TM_FAR *, char _TM_FAR *, char _TM_FAR *,    long, char _TM_FAR *));   /* buffer filtering function pointer */   int (_TMDLLENTRY *filter) _((char _TM_FAR *, long, char _TM_FAR *, long));   /* buffer formatting function pointer */   int (_TMDLLENTRY *format) _((char _TM_FAR *, long, char _TM_FAR *,          char _TM_FAR *, long));   /* process buffer before sending, possibly generating copy */   long (_TMDLLENTRY *presend2) _((char _TM_FAR *, long,          long, char _TM_FAR *, long, long _TM_FAR *));   /* Multibyte code-set encoding conversion function pointer*/   long (_TMDLLENTRY *mbconv) _((char _TM_FAR *, long,         char _TM_FAR *, char _TM_FAR *, long, long _TM_FAR *));   /* this space reserved for future expansion */   void (_TMDLLENTRY *reserved[8]) _((void));};/* * application types switch pointer * always use this pointer when accessing the table */extern struct tmtype_sw_t *tm_typeswp;
Coding Switch Element Routines
Listing 2‑20 Semantics of the Presend Switch Element
Adding a New Buffer Type to tm_typesw
Listing 2‑21 Adding a New Type to the Buffer Switch
Listing 2‑21 Adding a New Type to the Buffer Switch
#include <stdio.h>#include <tmtypes.h>/* Customized the buffer type switch */static struct tmtype_sw_t tm_typesw[] = {{"SOUND", /* type */“", /* subtype */50000, /* dfltsize */snd_init, /* initbuf */snd_init, /* reinitbuf */NULL, /* uninitbuf */snd_cmprs, /* presend */snd_uncmprs, /* postsend */snd_uncmprs /* postrecv */},{"FML", /* type */"", /* subtype */1024, /* dfltsize */_finit, /* initbuf */_freinit, /* reinitbuf */_funinit, /* uninitbuf */_fpresend, /* presend */_fpostsend, /* postsend */_fpostrecv, /* postrecv */_fencdec, /* encdec */_froute, /* route */_ffilter, /* filter */_fformat /* format */},{""}};
Compiling and Linking Your New tm_typesw
Compiling and Linking Your New tm_typesw for a 16-bit Windows Platform
Listing 2‑22 Sample Code in Microsoft Visual C++
Listing 2‑22 Sample Code in Microsoft Visual C++
CL -AL -I..\e\|sysinclu -I..\e\|include -Aw -G2swx -Zp -D_TM_WIN -D_TMDLL -Od -c TMTYPESW.CLINK /CO /ALIGN:16 TMTYPESW.OBJ, WBUFT.DLL, NUL, WTUXWS /SE:250 /NOD/NOE LIBW LDLLCEW, WBUFT.DEFRC /30 /T /K WBUFT.DLL
Data Conversion
Programming Environment
Updating the UBBCONFIG Configuration File
See Also
Setting Environment Variables
See Also
Including the Required Header Files
Starting and Stopping the Application
See Also
Writing Clients
Joining an Application
Listing 4‑1 Allocating a TPINIT Typed Buffer
Listing 4‑1 Allocating a TPINIT Typed Buffer
See Also
Using Features of the TPINIT Typed Buffer
Client Naming
Figure 4‑1 Client Naming
Unsolicited Notification Handling
System Access Mode
Resource Manager Association
Client Authentication
Leaving the Application
Building Clients
Notes: The Oracle Tuxedo libraries are linked in automatically; you do not need to specify any Oracle Tuxedo libraries on the command line.
Notes: The Oracle Tuxedo libraries are linked in automatically; you do not need to specify any Oracle Tuxedo libraries on the command line.
See Also
Client Process Examples
Listing 4‑2 Typical Client Process Paradigm
Listing 4‑3 Joining and Leaving an Application
Writing Servers
Oracle Tuxedo System main( )
System-Supplied Server and Services
Notes: If you want to write your own versions of tpsvrinit() and tpsvrdone(), remember that the default versions of these two routines call tx_open() and tx_close(), respectively. If you write a new version of tpsvrinit() that calls tpopen() rather than tx_open(), you should also write a new version of tpsvrdone() that calls tpclose(). In other words, both functions in an open/close pair must belong to the same set.
Notes: If you want to write your own versions of tpsvrinit() and tpsvrdone(), remember that the default versions of these two routines call tx_open() and tx_close(), respectively. If you write a new version of tpsvrinit() that calls tpopen() rather than tx_open(), you should also write a new version of tpsvrdone() that calls tpclose(). In other words, both functions in an open/close pair must belong to the same set.
System-Supplied Server: AUTHSVR( )
System-Supplied Services: tpsvrinit( ) Function
Receiving Command-line Options
Listing 5‑1 Receiving Command-line Options in tpsvrinit( )
Opening a Resource Manager
Listing 5‑2 Opening a Resource Manager in tpsvrinit( )
System-Supplied Services: tpsvrdone( ) Function
Listing 5‑3 Closing a Resource Manager with tpsvrdone( )
Listing 5‑3 Closing a Resource Manager with tpsvrdone( )
voidtpsvrdone(){      /* Close the database */      if(tpclose() == -1)           (void)userlog("tpsvrdone: failed to close database: ");           switch (tperrno) {                   case TPESYSTEM:                          (void)userlog("BEA TUXEDO error\n");                          break;                   case TPEOS:                          (void)userlog("Unix error %d\n",Uunixerr);                          break;                   case TPEPROTO:                          (void)userlog("Called in improper context\n");                          break;                   case TPERMERR:                          (void)userlog("RM failure\n");                          break;          }           return;    }    return;}
Guidelines for Writing Servers
Defining a Service
Listing 5‑4 Typical Service Definition
Listing 5‑4 Typical Service Definition
Example: Checking the Buffer Type
Listing 5‑5 Checking for Buffer Type
Listing 5‑5 Checking for Buffer Type
#define TMTYPERR 1 /* return code indicating tptypes failed */#define INVALMTY 2 /* return code indicating invalid message type */ voidABAL(transb) TPSVCINFO *transb; {   struct aud *transv; /* view message */   FBFR *transf; /* fielded buffer message */   int repc; /* tpgetrply return code */   char typ[TMTYPELEN+1], subtyp[TMSTYPELEN+1]; /* type, subtype of message */   char *retstr; /* return string if tptypes fails */ /* find out what type of buffer sent */    if (tptypes((char *)transb->data, typ, subtyp) == -1) {      retstr=tpalloc("STRING", NULL, 100);      (void)sprintf(retstr,      "Message garbled; tptypes cannot tell what type message\n");      tpreturn(TPFAIL, TMTYPERR, retstr, 100, 0);   }/* Determine method of processing service request based on type */   if (strcmp(typ, "FML") == 0) {      transf = (FBFR *)transb->data;... code to do abal service for fielded buffer ... tpreturn succeeds and sends FML buffer in reply   }   else if (strcmp(typ, "VIEW") == 0 && strcmp(subtyp, "aud") == 0) {      transv = (struct aud *)transb->data;... code to do abal service for aud struct ... tpreturn succeeds and sends aud view buffer in reply   }   else {      retstr=tpalloc("STRING", NULL, 100);      (void)sprintf(retstr,      "Message garbled; is neither FML buffer nor aud view\n");      tpreturn(TPFAIL, INVALMTY, retstr, 100, 0);   }}
Example: Checking the Priority of the Service Request
Listing 5‑6 Checking the Priority of a Received Request
Listing 5‑6 Checking the Priority of a Received Request
#include <stdio.h>#include "atmi.h" char *roundrobin(); PRINTER(pbuf) TPSVCINFO *pbuf; /* print buffer */ {char prname[20], ocmd[30]; /* printer name, output command */long rlen; /* return buffer length */int prio; /* priority of request */FILE *lp_pipe; /* pipe file pointer */ prio=tpgprio();if (prio <= 20)   (void)strcpy(prname,"bigjobs"); /* send low priority (verbose)                                     jobs to big comp. center                                     laser printer where operator                                     sorts output and puts it                                     in a bin */else if (prio <= 60)   (void)strcpy(prname,roundrobin()); /* assign printer on a                                        rotating basis to one of                                        many local small laser printers                                        where output can be picked                                        up immediately; roundrobin() cycles                                        through list of printers */else   (void)strcpy(prname,"hispeed");                                   /* assign job to high-speed laser                                      printer; reserved for those who                                      need verbose output on a daily,                                      frequent basis */ (void)sprintf(ocmd, "lp -d%s", prname); /* output lp(1) command */lp_pipe = popen(ocmd, "w"); /* create pipe to command */(void)fprintf(lp_pipe, "%s", pbuf->data); /* print output there */(void)pclose(lp_pipe); /* close pipe */ if ((pbuf->flags & TPNOREPLY))   tpreturn(TPSUCCESS, 0, NULL, 0, 0);rlen = strlen(prname) + 1;pbuf->data = tprealloc(pbuf->data, rlen); /* ensure enough space for name */(void)strcpy(pbuf->data, prname);tpreturn(TPSUCCESS, 0, pbuf->data, rlen, 0); char *roundrobin() {static char *printers[] = {"printer1", "printer2", "printer3", "printer4"};static int p = 0; if (p > 3)   p=0;return(printers[p++]);}
Terminating a Service Routine
Sending Replies
Listing 5‑7 tpreturn( ) Function
Listing 5‑7 tpreturn( ) Function
#include <stdio.h> /* UNIX */#include <string.h> /* UNIX */#include "fml.h" /* BEA Tuxedo System */#include "atmi.h" /* BEA Tuxedo System */#include "Usysflds.h" /* BEA Tuxedo System */#include "userlog.h" /* BEA Tuxedo System */#include "bank.h" /* BANKING #defines */#include "bank.flds.h" /* bankdb fields */ /* * Service to transfer an amount from a debit account to a credit * account */ void#ifdef __STDC__TRANSFER(TPSVCINFO *transb) #else TRANSFER(transb)TPSVCINFO *transb;#endif {   FBFR *transf; /* fielded buffer of decoded message */   long db_id, cr_id; /* from/to account id’s */   float db_bal, cr_bal; /* from/to account balances */   float tamt; /* amount of the transfer */   FBFR *reqfb; /* fielded buffer for request message*/   int reqlen; /* length of fielded buffer */   char t_amts[BALSTR]; /* string for transfer amount */   char db_amts[BALSTR]; /* string for debit account balance */   char cr_amts[BALSTR]; /* string for credit account balance */ /* Set pointr to TPSVCINFO data buffer */transf = (FBFR *)transb->data; /* Get debit (db_id) and credit (cr_id) account IDs */ /* must have valid debit account number */if (((db_id = Fvall(transf, ACCOUNT_ID, 0)) < MINACCT) || (db_id > MAXACCT)) {   (void)Fchg(transf, STATLIN, 0,"Invalid debit account number",(FLDLEN)0);   tpreturn(TPFAIL, 0, transb->data, 0L, 0);}/* must have valid credit account number */if ((cr_id = Fvall(transf, ACCOUNT_ID, 1)) < MINACCT || cr_id > MAXACCT) {   (void)Fchg(transf,STATLIN, 0,"Invalid credit account number",(FLDLEN)0);   tpreturn(TPFAIL, 0, transb->data, 0L, 0);} /* get amount to be withdrawn */if (Fget(transf, SAMOUNT, 0, t_amts, < 0) 0 || strcmp(t_amts,"") == 0) {   (void)Fchg(transf, STATLIN, 0, "Invalid amount",(FLDLEN)0);   tpreturn(TPFAIL, 0, transb->data, 0L, 0);}(void)sscanf(t_amts,"%f",tamt); /* must have valid amount to transfer */if (tamt = 0.0) {   (void)Fchg(transf, STATLIN, 0,      "Transfer amount must be greater than $0.00",(FLDLEN)0);    tpreturn(TPFAIL, 0, transb->data, 0L, 0);} /* make withdraw request buffer */if ((reqfb = (FBFR *)tpalloc("FML",NULL,transb->len)) == (FBFR *)NULL) {   (void)userlog("tpalloc failed in transfer\n");   (void)Fchg(transf, STATLIN, 0,      "unable to allocate request buffer", (FLDLEN)0);   tpreturn(TPFAIL, 0, transb->data, 0L, 0);}reqlen = Fsizeof(reqfb); /* put ID in request buffer */(void)Fchg(reqfb,ACCOUNT_ID,0,(char *)&db_id, (FLDLEN)0); /* put amount in request buffer */(void)Fchg(reqfb,SAMOUNT,0,t_amts, (FLDLEN)0); /* increase the priority of withdraw call */if (tpsprio(PRIORITY, 0L) == -1)   (void)userlog("Unable to increase priority of withdraw\n"); if (tpcall("WITHDRAWAL", (char *)reqfb,0, (char **)&reqfb,      (long *)&reqlen,TPSIGRSTRT) == -1) {   (void)Fchg(transf, STATLIN, 0,         "Cannot withdraw from debit account", (FLDLEN)0);   tpfree((char *)reqfb);   tpreturn(TPFAIL, 0,transb->data, 0L, 0);} /* get "debit" balance from return buffer */ (void)strcpy(db_amts, Fvals((FBFR *)reqfb,SBALANCE,0));void)sscanf(db_amts,"%f",db_bal);if ((db_amts == NULL) || (db_bal < 0.0)) {   (void)Fchg(transf, STATLIN, 0,         "illegal debit account balance", (FLDLEN)0);   tpfree((char *)reqfb);   tpreturn(TPFAIL, 0, transb->data, 0L, 0);} /* put deposit account ID in request buffer */(void)Fchg(reqfb,ACCOUNT_ID,0,(char *)&cr_id, (FLDLEN)0); /* put transfer amount in request buffer */(void)Fchg(reqfb,SAMOUNT,0,t_amts, (FLDLEN)0); /* Up the priority of deposit call */if (tpsprio(PRIORITY, 0L) == -1) (void)userlog("Unable to increase priority of deposit\n"); /* Do a tpcall to deposit to second account */if (tpcall("DEPOSIT", (char *)reqfb, 0, (char **)&reqfb,        (long *)&reqlen, TPSIGRSTRT) == -1) {   (void)Fchg(transf, STATLIN, 0,           "Cannot deposit into credit account", (FLDLEN)0);   tpfree((char *)reqfb);   tpreturn(TPFAIL, 0,transb->data, 0L, 0);} /* get "credit" balance from return buffer */ (void)strcpy(cr_amts, Fvals((FBFR *)reqfb,SBALANCE,0));(void)sscanf(cr_amts,"%f",&cr_bal);if ((cr_amts == NULL) || (cr_bal 0.0)) {   (void)Fchg(transf, STATLIN, 0,         "Illegal credit account balance", (FLDLEN)0);    tpreturn(TPFAIL, 0, transb->data, 0L, 0);} /* set buffer for successful return */(void)Fchg(transf, FORMNAM, 0, "CTRANSFER", (FLDLEN)0);(void)Fchg(transf, SAMOUNT, 0, Fvals(reqfb,SAMOUNT,0), (FLDLEN)0);(void)Fchg(transf, STATLIN, 0, "", (FLDLEN)0);(void)Fchg(transf, SBALANCE, 0, db_amts, (FLDLEN)0);(void)Fchg(transf, SBALANCE, 1, cr_amts, (FLDLEN)0);tpfree((char *)reqfb);tpreturn(TPSUCCESS, 0,transb->data, 0L, 0);}
Invalidating Descriptors
Listing 5‑8 Invalidating a Reply After Timing Out
Forwarding Requests
Figure 5‑1 Forwarding a Request
Figure 5‑1 Forwarding a Request
Figure 5‑1 Forwarding a Request
Listing 5‑9 tpforward( ) Function
.../* set pointer to TPSVCINFO data buffer */ transf = (FBFR *)transb->data;.../* Insert new account record into ACCOUNT*/ account_id = ++last_acct; /* get new account number */tlr_bal = 0.0; /* temporary balance of 0 */ EXEC SQL insert into ACCOUNT (ACCOUNT_ID, BRANCH_ID, BALANCE,ACCT_TYPE, LAST_NAME, FIRST_NAME, MID_INIT, ADDRESS, PHONE) values(:account_id, :branch_id, :tlr_bal, :acct_type, :last_name,      :first_name, :mid_init, :address, :phone);if (SQLCODE != SQL_OK) { /* Failure to insert */      (void)Fchg(transf, STATLIN, 0,          "Cannot update ACCOUNT", (FLDLEN)0);      tpreturn(TPFAIL, 0, transb->data, 0L, 0);} /* Update branch record with new LAST_ACCT */ EXEC SQL update BRANCH set LAST_ACCT = :last_acct where BRANCH_ID = :branch_id;if (SQLCODE != SQL_OK) { /* Failure to update */       (void)Fchg(transf, STATLIN, 0,           "Cannot update BRANCH", (FLDLEN)0);       tpreturn(TPFAIL, 0, transb->data, 0L, 0);}/* up the priority of the deposit call */if (tpsprio(PRIORITY, 0L) == -1)     (void)userlog("Unable to increase priority of deposit\n"); /* tpforward same buffer to deposit service to add initial balance */tpforward("DEPOSIT", transb->data, 0L, 0);
Advertising and Unadvertising Services
Advertising Services
Unadvertising Services
Example: Dynamic Advertising and Unadvertising of a Service
Listing 5‑10 Dynamic Advertising and Unadvertising
Building Servers
Notes: The Oracle Tuxedo libraries are linked in automatically. You do not need to specify the Oracle Tuxedo library names on the command line.
Notes: The Oracle Tuxedo libraries are linked in automatically. You do not need to specify the Oracle Tuxedo library names on the command line.
See Also
Using a C++ Compiler
Declaring Service Functions
Using Constructors and Destructors
Writing Request/Response Clients and Servers
Overview of Request/Response Communication
Figure 6‑1 Example of Request/Response Communication in Online Banking
Sending Synchronous Messages
Example: Using the Same Buffer for Request and Reply Messages
Listing 6‑1 Using the Same Buffer for Request and Reply Messages
Example: Testing for Change in Size of Reply Buffer
Listing 6‑2 Testing for Change in Size of the Reply Buffer
Example: Sending a Synchronous Message with TPSIGRSTRT Set
Listing 6‑3 Sending a Synchronous Message with TPSIGRSTRT Set
Example: Sending a Synchronous Message with TPNOTRAN Set
Listing 6‑4 Sending a Synchronous Message with TPNOTRAN Set
Example: Sending a Synchronous Message with TPNOCHANGE Set
Listing 6‑5 Sending a Synchronous Message with TPNOCHANGE Set
Sending Asynchronous Messages
Sending an Asynchronous Request
Example: Sending an Asynchronous Message with TPNOTRAN | TPNOREPLY
Listing 6‑6 Sending an Asynchronous Message with TPNOREPLY | TPNOTRAN
Example: Sending Asynchronous Requests
Listing 6‑7 Sending Asynchronous Requests
Getting an Asynchronous Reply
Setting and Getting Message Priorities
Setting a Message Priority
Listing 6‑8 Setting the Priority of a Request Message
Getting a Message Priority
Listing 6‑9 Determining the Priority of a Request After It Is Sent
Writing Conversational Clients and Servers
Overview of Conversational Communication
Figure 7‑1 Example of Conversational Communication in an Online Banking Application
Joining an Application
Establishing a Connection
Listing 7‑1 Establishing a Conversational Connection
Sending and Receiving Messages
Sending Messages
Listing 7‑2 Sending Data in Conversational Mode
Receiving Messages
Listing 7‑3 Receiving Data in Conversation
Ending a Conversation
Example: Ending a Simple Conversation
Figure 7‑2 Simple Conversation Terminated Gracefully
Example: Ending a Hierarchical Conversation
Figure 7‑3 Connection Hierarchy
Executing a Disorderly Disconnect
Building Conversational Clients and Servers
Understanding Conversational Communication Events
Writing Event-based Clients and Servers
Overview of Events
Unsolicited Events
Brokered Events
Notification Actions
EventBroker Servers
System-defined Events
Programming Interface for the EventBroker
Defining the Unsolicited Message Handler
Sending Unsolicited Messages
Broadcasting Messages by Name
inttpbroadcast(char *lmid, char *usrname, char *cltname, char *data, long len, long flags)
Listing 8‑1 Using tpbroadcast( )
Broadcasting Messages by Identifier
Checking for Unsolicited Messages
Subscribing to Events
long handletpsubscribe (char *eventexpr, char *filter, TPEVCTL *ctl, long flags)
long handletpsubscribe (char *eventexpr, char *filter, TPEVCTL *ctl, long flags)
Notification via Unsolicited Message
Notification via Service Call or Reliable Queue
Unsubscribing from Events
Posting Events
Listing 8‑2 Posting an Event with tppost( )
Listing 8‑2 Posting an Event with tppost( )
.../* Event logic related */static float evt_thresh = 10000.00 ; /* default for event threshold */static char emsg[200] ; /* used by event posting logic */.../* Post a BANK_TLR_WITHDRAWAL event ? */if (amt < evt_thresh) {     /* no event to post */     tpreturn(TPSUCCESS, 0,transb->data , 0L, 0);}/* prepare to post the event */if ((Fchg (transf, EVENT_NAME, 0, "BANK_TLR_WITHDRAWAL", (FLDLEN)0) == -1) ||(Fchg (transf, EVENT_TIME, 0, gettime(), (FLDLEN)0) == -1) ||(Fchg (transf, AMOUNT, 0, (char *)&amt, (FLDLEN)0) == -1)) {     (void)sprintf (emsg, "Fchg failed for event fields: %s",     Fstrerror(Ferror)) ;}/* post the event */else if (tppost ("BANK_TLR_WITHDRAWAL", /* event name */(char *)transf, /* data */0L, /* len */TPNOTRAN | TPSIGRSTRT) == -1) {/* If event broker is not reachable, ignore the error */     if (tperrno != TPENOENT)     (void)sprintf (emsg, "tppost failed: %s", tpstrerror (tperrno));}
Example of Event Subscription
Listing 8‑3 Subscribing to an Event with tpsubscribe( )
Listing 8‑3 Subscribing to an Event with tpsubscribe( )
.../* Event Subscription handles */static long sub_ev_largeamt = 0L ;.../* Preset default for option 'w' - watchdog threshold */(void)strcpy (amt_expr, "AMOUNT > 10000.00") ;.../* * Subscribe to the events generated * when a "large" amount is transacted. */evctl.flags = TPEVSERVICE ;(void)strcpy (evctl.name1, "WATCHDOG") ;/* Subscribe */sub_ev_largeamt = tpsubscribe ("BANK_TLR_.*",amt_expr,&evctl,TPSIGRSTRT) ;if (sub_ev_largeamt == -1L) {     (void)userlog ("ERROR: tpsubscribe for event BANK_TLR_.* failed: %s",     tpstrerror(tperrno)) ;     return -1 ;}...{/* Unsubscribe to the subscribed events */if (tpunsubscribe (sub_ev_largeamt, TPSIGRSTRT) == -1)    (void)userlog ("ERROR: tpunsubscribe to event BANK_TLR_.* failed: %s",    tpstrerror(tperrno)) ;    return ;}/** Service called when a BANK_TLR_.* event is posted.*/void#if defined(__STDC__) || defined(__cplusplus)WATCHDOG(TPSVCINFO *transb)#elseWATCHDOG(transb)TPSVCINFO *transb;#endif{FBFR *transf; /* fielded buffer of decoded message *//* Set pointr to TPSVCINFO data buffer */transf = (FBFR *)transb->data;/* Print the log entry to stdout */(void)fprintf (stdout, "%20s|%28s|%8ld|%10.2f\n",Fvals (transf, EVENT_NAME, 0),Fvals (transf, EVENT_TIME, 0),Fvall (transf, ACCOUNT_ID, 0),*( (float *)CFfind (transf, AMOUNT, 0, NULL, FLD_FLOAT)) );/* No data should be returned by the event subscriber's svc routine */tpreturn(TPSUCCESS, 0,NULL, 0L, 0);}
Writing Global Transactions
What Is a Global Transaction?
Starting the Transaction
Listing 9‑1 Defining a Global Transaction - High-level View
Listing 9‑1 Defining a Global Transaction - High-level View
Listing 9‑2 Defining a Global Transaction - Detailed View
#include <stdio.h> /* UNIX */#include <string.h> /* UNIX */#include <atmi.h> /* BEA Tuxedo System */#include <Uunix.h> /* BEA Tuxedo System */#include <userlog.h> /* BEA Tuxedo System */#include "bank.h" /* BANKING #defines */#include "aud.h" /* BANKING view defines */ #define INVI 0 /* account inquiry */#define ACCT 1 /* account inquiry */#define TELL 2 /* teller inquiry */ static int sum_bal _((char *, char *));static long sitelist[NSITE] = SITEREP; /* list of machines to audit */static char pgmname[STATLEN]; /* program name = argv[0] */static char result_str[STATLEN]; /* string to hold results of query */ main(argc, argv)int argc;char *argv[];{        int aud_type=INVI; /* audit type -- invalid unless specified */        int clarg; /* command line arg index from optind */        int c; /* Option character */        int cflgs=0; /* Commit flags, currently unused */        int aflgs=0; /* Abort flags, currently unused */        int nbl=0; /* count of branch list entries */        char svc_name[NAMELEN]; /* service name */        char hdr_type[NAMELEN]; /* heading to appear on output */        int retc; /* return value of sum_bal() */        struct aud *audv; /* pointer to audit buf struct */        int audrl=0; /* audit return length */        long q_branchid; /* branch_id to query */ . . . /* Get Command Line Options and Set Variables */ /* Join application */ if (tpinit((TPINIT *) NULL) == -1) {        (void)userlog("%s: failed to join application\n", pgmname);        exit(1);}/* Start global transaction */if (tpbegin(30, 0) == -1) {        (void)userlog("%s: failed to begin transaction\n", pgmname);        (void)tpterm();        exit(1);}if (nbl == 0) { /* no branch id specified so do a global sum */ retc = sum_bal(svc_name, hdr_type); /* sum_bal routine not shown */ } else {         /* Create buffer and set data pointer */                if ((audv = (struct aud *)tpalloc("VIEW", "aud", sizeof(struct aud)))                == (struct aud *)NULL) {                (void)userlog("audit: unable to allocate space for VIEW\n");                exit(1);        }         /* Prepare aud structure */         audv->b_id = q_branchid;        audv->balance = 0.0;        audv->ermsg[0] = '\0';         /* Do tpcall */         if (tpcall(svc_name,(char *)audv,sizeof(struct aud),           (char **)audv,(long *)audrl,0) == -1){                    (void)fprintf (stderr,"%s service failed\n%s: %s\n",                    svc_name, svc_name, audv->ermsg);                    retc = -1;         }else {                  (void)sprintf(result_str,"Branch %ld %s balance is $%.2f\n",                  audv->b_id, hdr_type, audv->balance);        }                 tpfree((char *)audv);} /* Commit global transaction */ if (retc < 0) /* sum_bal failed so abort */       (void) tpabort(aflgs);else {         if (tpcommit(cflgs) == -1) {                 (void)userlog("%s: failed to commit transaction\n", pgmname);                 (void)tpterm();                 exit(1);        }        /*print out results only when transaction has committed successfully*/        (void)printf("%s",result_str);} /* Leave application */ if (tpterm() == -1) {        (void)userlog("%s: failed to leave application\n", pgmname);        exit(1);}
Listing 9‑3 Testing for Transaction Timeout
Suspending and Resuming a Transaction
Suspending a Transaction
Resuming a Transaction
Example: Suspending and Resuming a Transaction
Listing 9‑4 Suspending and Resuming a Transaction
Terminating the Transaction
Committing the Current Transaction
Prerequisites for a Transaction Commit
Two-phase Commit Protocol
Selecting Criteria for a Successful Commit
Trade-offs Between Possible Commit Criteria
Aborting the Current Transaction
Example: Committing a Transaction in Conversational Mode
Figure 9‑1 Connection Hierarchy in Transaction Mode
Example: Testing for Participant Errors
Listing 9‑5 Testing for Participant Success or Failure
Listing 9‑5 Testing for Participant Success or Failure
001 #include <stdio.h>002 #include "atmi.h"003004 main()005 {006 char *sbuf, *rbuf;007 long slen, rlen;008 if (tpinit((TPINIT *) NULL) == -1)009 error message, exit program;010 if (tpbegin(30, 0) == -1)011 error message, tpterm, exit program;012 if ((sbuf=tpalloc("STRING", NULL, 100)) == NULL)013 error message, tpabort, tpterm, exit program;014 if ((rbuf=tpalloc("STRING", NULL, 2000)) == NULL)015 error message, tpfree sbuf, tpabort, tpterm, exit program;016 (void)strcpy(sbuf, "REPORT=accrcv DBNAME=accounts");017 slen=strlen(sbuf);018 if (tpcall("REPORT", sbuf, slen, &rbuf, &rlen, 0) == -1) {019 switch(tperrno) {020 case TPESVCERR:021 fprintf(stderr,022 "REPORT service's tpreturn encountered problems\n");023 break;024 case TPESVCFAIL:025 fprintf(stderr,026 "REPORT service TPFAILED with return code of %d\n", tpurcode);027 break;028 case TPEOTYPE:029 fprintf(stderr,030 "REPORT service's reply is not of any known data type\n");031 break;032 default:033 fprintf(stderr,034 "REPORT service failed with error %d\n", tperrno);035 break;036 }037 if (tpabort(0) == -1){038 check for errors;039 }040 }041 else042 if (tpcommit(0) == -1)043 fprintf(stderr, "Transaction failed at commit time\n");044 tpfree(rbuf);045 tpfree(sbuf);046 tpterm();047 exit(0);048 }
Implicitly Defining a Global Transaction
Implicitly Defining a Transaction in a Service Routine
Defining Global Transactions for an XA-Compliant Server Group
Testing Whether a Transaction Has Started
Listing 9‑6 Testing Transaction Level
Listing 9‑6 Testing Transaction Level
Listing 9‑6 Testing Transaction Level
001 #define BEGFAIL 3 /* tpurcode setting for return if tpbegin fails */ 002 void003 OPEN_ACCT(transb) 004 TPSVCINFO *transb; 005 { ... other declarations ...006 FBFR *transf; /* fielded buffer of decoded message */007 int dotran; /* checks whether service tpbegin/tpcommit/tpaborts */ 008 /* set pointer to TPSVCINFO data buffer */ 009 transf = (FBFR *)transb->data; 010 /* Test if transaction exists; initiate if no, check if yes */ 011 dotran = 0;012 if (tpgetlev() == 0) {013 dotran = 1;014 if (tpbegin(30, 0) == -1) {015 Fchg(transf, STATLIN, 0,016 "Attempt to tpbegin within service routine failed\n");017 tpreturn(TPFAIL, BEGFAIL, transb->data, 0, 0);018 }019 } . . .
See Also
Programming a Multithreaded and Multicontexted ATMI Application
Support for Programming a Multithreaded/Multicontexted ATMI Application
Platform-specific Considerations for Multithreaded/Multicontexted Applications
See Also
Planning and Designing a Multithreaded/Multicontexted ATMI Application
What Are Multithreading and Multicontexting?
What Is Multithreading?
Figure 10‑1 Sample Multithreaded Process
Figure 10‑2 Multiple Service Threads Dispatched in One Server Process
What Is Multicontexting?
Figure 10‑3 Multicontexted Process in Two Domains
Auditing a Multithreaded or Multicontexted Application
See Also
Advantages and Disadvantages of a Multithreaded/Multicontexted ATMI Application
Advantages of a Multithreaded/Multicontexted ATMI Application
Disadvantages of a Multithreaded/Multicontexted ATMI Application
See Also
How Multithreading and Multicontexting Work in a Client
Start-up Phase
Client Threads Join Multiple Contexts
Client Threads Switch to an Existing Context
Work Phase
Service Requests
Replies to Service Requests
Transactions
Unsolicited Messages
Userlog Maintains Thread-specific Information
Completion Phase
See Also
How Multithreading and Multicontexting Work in Server-Dispatched Threads an on ATMI Server
Start-up Phase
Work Phase
How Server-Dispatched Threads Are Used
Bulletin Board Liaison Verifies Sanity of System Processes
System Keeps Statistics on Server Threads
Userlog Maintains Thread-specific Information
Completion Phase
See Also
How Multithreading and Multicontexting Work in Application-Created Threads of an ATMI Server
Start-Up Phase
Work Phase
Notes: An application-created server thread cannot call either tpreturn() or tpforward().
Notes: An application-created server thread cannot call either tpreturn() or tpforward().
Userlog Maintains Thread-specific Information
Completion Phase
See Also
Design Considerations for a Multithreaded and Multicontexted ATMI Application
Environment Requirements
Design Requirements
Is the Task of Your Application Suitable for Multithreading and/or Multicontexting?
How Many Applications and Connections Do You Want?
What Synchronization Issues Need to Be Addressed?
Will You Need to Port Your Application?
Which Threads Model Is Best for You?
Interoperability Restrictions for Workstation Clients
See Also
Implementing a Multithreaded/ Multicontexted ATMI Application
Preliminary Guidelines for Programming a Multithreaded/Multicontexted ATMI Application
Prerequisites for a Multithreaded ATMI Application
General Multithreaded Programming Considerations
Concurrency Considerations
See Also
Writing Code to Enable Multicontexting in an ATMI Client
Context Attributes
Setting Up Multicontexting at Initialization
Listing 10‑1 Sample Code for a Client Joining a Multicontexted Application
Implementing Security for a Multicontexted ATMI Client
Synchronizing Threads Before an ATMI Client Termination
Switching Contexts
Listing 10‑2 Sample Code for Switching Contexts in a Client
Listing 10‑2 Sample Code for Switching Contexts in a Client
#include <stdio.h>#include "atmi.h" /* Oracle Tuxedo header file */#if defined(__STDC__) || defined(__cplusplus)main(int argc, char *argv[])#elsemain(argc, argv)int argc;char *argv[];#endif{          TPINIT * tpinitbuf;       TPCONTEXT_T firstapp_contextID, secondapp_contextID;   /* Assume that TUXCONFIG is initially set to /home/firstapp/TUXCONFIG*/          /*         * Attach to the Oracle Tuxedo system in multicontext mode.        */        tpinitbuf=tpalloc(“TPINIT”, NULL, TPINITNEED(0));   tpinitbuf->flags = TPMULTICONTEXTS;       if (tpinit((TPINIT *) tpinitbuf) == -1) {      (void) fprintf(stderr, "Tpinit failed\n");      exit(1);       }       /*        * Obtain a handle to the current context.        */          tpgetctxt(&firstapp_contextID, 0);          /*        * Use tuxputenv to change the value of TUXCONFIG,        * so we now tpinit to another application.        */        tuxputenv("TUXCONFIG=/home/second_app/TUXCONFIG");        /*        * tpinit to secondapp.        */        if (tpinit((TPINIT *) tpinitbuf) == -1) {                 (void) fprintf(stderr, "Tpinit failed\n");                 exit(1);       }    /*        * Get a handle to the context of secondapp. */       tpgetctxt(&secondapp_contextID, 0);       /*        * Now you can alternate between the two contexts        * using tpsetctxt and the handles you obtained from           * tpgetctxt. You begin with firstapp.        */       tpsetctxt(firstapp_contextID, 0);       /*           * You call services offered by firstapp and then switch        * to secondapp.        */          tpsetctxt(secondapp_contextID, 0);        /*           * You call services offered by secondapp.        * Then you switch back to firstapp.        */          tpsetctxt(firstapp_contextID, 0);       /*           * You call services offered by firstapp. When you have           * finished, you terminate the context for firstapp.        */       tpterm();       /*           * Then you switch back to secondapp.        */       tpsetctxt(secondapp_contextID, 0);       /*           * You call services offered by secondapp. When you have              finished, you terminate the context for secondapp and          end your program.        */       tpterm();       return(0);}
Handling Unsolicited Messages
Coding Rules for Transactions in a Multithreaded/Multicontexted ATMI Application
See Also
Writing Code to Enable Server-Dispatched Multicontexting and Multithreading Threads in an ATMI Server
Context Attributes
Coding Rules for Server-Dispatched Threads in Multicontexted ATMI Server
Initializing and Terminating ATMI Servers and Server Threads
See Also
Writing Code to Enable Multicontexting in Application-Created Threads of an ATMI Server
Creating Threads
Associating Application Threads with a Context
Associating Application Threads with an Existing Server-Dispatched Context
Sample Code for Associating Application Thread with an Existing Server-Dispatched Context in a Multicontexted Server
Listing 10‑3 Code Sample for Application-Created Server Thread Working in Server-Dispatched Context
Associating Application Threads with Application-Created Context
Context Attributes
Code Rules for Application-Created Thread of an ATMI Server in Application-Created Context
Sample Code for Associating Application Thread with Application-created server Context in a Multicontexted Server
Listing 10‑4 Code Sample for Application-Created Server Thread Working in Application-Created Context
See Also
Writing a Multithreaded ATMI Client
Coding Rules for a Multithreaded ATMI Client
Initializing an ATMI Client to Multiple Contexts
Context State Changes for an ATMI Client Thread
Figure 10‑4 Multicontext State Transitions
Getting Replies in a Multithreaded Environment
Using Environment Variables in a Multithreaded and/or Multicontexted Environment
Using Per-context Functions and Data Structures in a Multithreaded ATMI Client
Using Per-process Functions and Data Structures in a Multithreaded ATMI Client
Using Per-thread Functions and Data Structures in a Multithreaded ATMI Client
Sample Code for a Multithreaded ATMI Client
Listing 10‑5 Sample Code for a Multithreaded Client
Listing 10‑5 Sample Code for a Multithreaded Client
#include <stdio.h>#include <pthread.h>#include <atmi.h>TPINIT * tpinitbuf;int timeout=60;pthread_t withdrawalthreadid, stockthreadid;TPCONTEXT_T ctxt;void * stackthread(void *);void * withdrawalthread(void *);main(){       tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));       /*        * This code will perform a transfer, using separate threads for the         * withdrawal and deposit. It will also get the current         * price of Oracle stock from a separate application, and calculate how        * many shares the transferred amount can buy.        */       tpinitbuf->flags = TPMULTICONTEXTS;       /* Fill in the rest of tpinitbuf. */       tpinit(tpinitbuf);       tpgetctxt(&ctxt, 0);       tpbegin(timeout, 0);       pthread_create(&withdrawalthreadid, NULL, withdrawalthread, NULL);       tpcall("DEPOSIT", ...);       /* Wait for the withdrawal thread to complete. */       pthread_join(withdrawalthreadid, NULL);       tpcommit(0);       tpterm();       /* Wait for the stock thread to complete. */       pthread_join(stockthreadid, NULL);       /* Print the results. */       printf("$%9.2f has been transferred \       from your savings account to your checking account.\n", ...);       printf("At the current Oracle stock price of $%8.3f, \       you could purchase %d shares.\n", ...);       exit(0);}void *stockthread(void *arg){     /* The other threads have now called tpinit(), so resetting TUXCONFIG can      * no longer adversely affect them.     */     tuxputenv("TUXCONFIG=/home/users/xyz/stockconf");     tpinitbuf->flags = TPMULTICONTEXTS;     /* Fill in the rest of tpinitbuf. */     tpinit(tpinitbuf);     tpcall("GETSTOCKPRICE", ...);     /* Save the stock price in a variable that can also be accessed in main(). */     tpterm();     return(NULL);}void *withdrawalthread(void *arg){       /* Create a separate thread to get stock prices from a different        * application.        */
     pthread_create(&stockthreadid, NULL, stockthread, NULL);     tpsetctxt(ctxt, 0);     tpcall("WITHDRAWAL", ...);     return(NULL);}
See Also
Writing a Multithreaded ATMI Server
Compiling Code for a Multithreaded/Multicontexted ATMI Application
See Also
Testing a Multithreaded/Multicontexted ATMI Application
Testing Recommendations for a Multithreaded/Multicontexted ATMI Application
Troubleshooting a Multithreaded/Multicontexted ATMI Application
Improper Use of the TPMULTICONTEXTS Flag to tpinit( )
Calls to tpinit( ) Without TPMULTICONTEXTS
Insufficient Thread Stack Size
Error Handling for a Multithreaded/Multicontexted ATMI Application
See Also
Managing Errors
System Errors
System Errors
Abort Errors
Oracle Tuxedo System Errors
Call Descriptor Errors
Limit Errors
Invalid Descriptor Errors
Conversational Errors
Duplicate Object Error
General Communication Call Errors
TPESVCFAIL and TPESVCERR Errors
TPEBLOCK and TPGOTSIG Errors
Invalid Argument Errors
MIB Error
No Entry Errors
Operating System Errors
Permission Errors
Protocol Errors
Queuing Error
Release Compatibility Error
Resource Manager Errors
Timeout Errors
Transaction Errors
Typed Buffer Errors
Application Errors
Handling Errors
Listing 11‑1 Handling Errors
Listing 11‑2 Handling Errors Using tpstrerrordetail( )
Transaction Considerations
Communication Etiquette
Transaction Errors
Non-fatal Transaction Errors
Fatal Transaction Errors
Heuristic Decision Errors
Transaction Timeouts
Effect on the tpcommit() Function
Effect on the TPNOTRAN Flag
tpreturn( ) and tpforward( ) Functions
tpterm( ) Function
Resource Managers
Sample Transaction Scenarios
Called Service in Same Transaction as Caller
Called Service in Different Transaction with AUTOTRAN Set
Figure 11‑1 Transaction Roles of tpforward( ) and tpreturn() with AUTOTRAN
Called Service That Starts a New Explicit Transaction
Oracle TUXEDO System-supplied Subroutines
Central Event Log
Log Name
Log Entry Format
Writing to the Event Log
Debugging Application Processes
Debugging Application Processes on UNIX Platforms
Debugging Application Processes on Windows 2003 Platforms
Comprehensive Example
Listing 11‑3 ACCT Server
Listing 11‑3 ACCT Server
001 #include <stdio.h> /* UNIX */002 #include <string.h> /* UNIX */003 #include <fml.h> /* BEA Tuxedo System */004 #include <atmi.h> /* BEA Tuxedo System */005 #include <Usysflds.h> /* BEA Tuxedo System */006 #include <sqlcode.h> /* BEA Tuxedo System */007 #include <userlog.h> /* BEA Tuxedo System */008 #include "bank.h" /* BANKING #defines */009 #include "bank.flds.h" /* bankdb fields */010 #include "event.flds.h" /* event fields */011012013 EXEC SQL begin declare section;014 static long account_id; /* account id */015 static long branch_id; /* branch id */016 static float bal, tlr_bal; /* BALANCE */017 static char acct_type; /* account type*/018 static char last_name[20], first_name[20]; /* last name, first name */019 static char mid_init; /* middle initial */020 static char address[60]; /* address */021 static char phone[14]; /* telephone */022 static long last_acct; /* last account branch gave */023 EXEC SQL end declare section; 024 static FBFR *reqfb; /* fielded buffer for request message */025 static long reqlen; /* length of request buffer */026 static char amts[BALSTR]; /* string representation of float */ 027 code for OPEN_ACCT service 028 /*029 * Service to close an account030 */ 031 void032 #ifdef __STDC__033 LOSE_ACCT(TPSVCINFO *transb) 034 #else 035 CLOSE_ACCT(transb)036 TPSVCINFO *transb;037 #endif 038 {039 FBFR *transf; /* fielded buffer of decoded message */ 040 /* set pointer to TPSVCINFO data buffer */041 transf = (FBFR *)transb->data; 042 /* must have valid account number */043 if (((account_id = Fvall(transf, ACCOUNT_ID, 0)) < MINACCT) ||044 (account_id > MAXACCT)) {045 (void)Fchg(transf, STATLIN, 0, "Invalid account number", (FLDLEN)0);046 tpreturn(TPFAIL, 0, transb->data, 0L, 0);047 } 048 /* Set transaction level */049 EXEC SQL set transaction read write; 050 /* Retrieve AMOUNT to be deleted */051 EXEC SQL declare ccur cursor for052 select BALANCE from ACCOUNT where ACCOUNT_ID = :account_id;053 EXEC SQL open ccur;054 EXEC SQL fetch ccur into :bal;055 if (SQLCODE != SQL_OK) { /* nothing found */056 (void)Fchg(transf, STATLIN, 0, getstr("account",SQLCODE), (FLDLEN)0);057 EXEC SQL close ccur;058 tpreturn(TPFAIL, 0, transb->data, 0L, 0);059 } 060 /* Do final withdrawal */ 061 /* make withdraw request buffer */062 if ((reqfb = (FBFR *)tpalloc("FML",NULL,transb->len)) == (FBFR *)NULL) {063 (void)userlog("tpalloc failed in close_acct\n");064 (void)Fchg(transf, STATLIN, 0,065 "Unable to allocate request buffer", (FLDLEN)0);066 tpreturn(TPFAIL, 0, transb->data, 0L, 0);067 }068 reqlen = Fsizeof(reqfb);069 (void)Finit(reqfb,reqlen); 070 /* put ID in request buffer */071 (void)Fchg(reqfb,ACCOUNT_ID,0,(char *)&account_id, (FLDLEN)0); 072 /* put amount into request buffer */073 (void)sprintf(amts,"%.2f",bal);074 (void)Fchg(reqfb,SAMOUNT,0,amts, (FLDLEN)0); 075 /* increase the priority of this withdraw */076 if (tpsprio(PRIORITY, 0L) == -1)077 (void)userlog("Unable to increase priority of withdraw"); 078 /* tpcall to withdraw service to remove remaining balance */079 if (tpcall("WITHDRAWAL", (char *)reqfb, 0L, (char **)&reqfb,080 (long *)&reqlen,TPSIGRSTRT) == -1) {081 (void)Fchg(transf, STATLIN, 0,"Cannot make withdrawal", (FLDLEN)0);082 tpfree((char *)reqfb);083 tpreturn(TPFAIL, 0,transb->data, 0L, 0);084 } 085 /* Delete account record */ 086 EXEC SQL delete from ACCOUNT where current of ccur;087 if (SQLCODE != SQL_OK) { /* Failure to delete */088 (void)Fchg(transf, STATLIN, 0,"Cannot close account", (FLDLEN)0);089 EXEC SQL close ccur;090 tpfree((char *)reqfb);091 tpreturn(TPFAIL, 0, transb->data, 0L, 0);092 }093 EXEC SQL close ccur; 094 /* prepare buffer for successful return */095 (void)Fchg(transf, SBALANCE, 0, Fvals(reqfb,SAMOUNT,0), (FLDLEN)0);096 (void)Fchg(transf, FORMNAM, 0, "CCLOSE", (FLDLEN)0);097 (void)Fchg(transf, STATLIN, 0, " ", (FLDLEN)0);098 tpfree((char *)reqfb);099 tpreturn(TPSUCCESS, 0, transb->data, 0L, 0);100 }
Oracle® Tuxedo
12c Release 2 (12.1.3)
Oracle Tuxedo Programming an Oracle Tuxedo ATMI Application Using C, 12c Release 2 (12.1.3)

Copyright © 1994, 2017, Oracle and/or its affiliates. All rights reserved.