Table of Contents
Listing 2‑1 Allocating a VIEW Typed Buffer
Listing 2‑6 Putting Data in a Message Buffer - Example 1
Listing 2‑8 Resizing a Buffer
Listing 2‑10 Getting Buffer Size
Listing 2‑11 Freeing a Buffer
Listing 2‑16 myview.flds.h Header File
Figure 2‑1 Encoding Conversion Using MBSTRING Buffers—Example
Listing 2‑18 Default Buffer Type Switch
Listing 2‑18 Default Buffer Type Switch
/* * 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;
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 */},{""}};
Listing 2‑22 Sample Code in Microsoft Visual C++
Listing 4‑1 Allocating a TPINIT Typed Buffer
Notes: The Oracle Tuxedo libraries are linked in automatically; you do not need to specify any Oracle Tuxedo libraries on the command line.
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.
Listing 5‑3 Closing a Resource Manager with tpsvrdone( )
Listing 5‑4 Typical Service Definition
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); }}
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++]);}
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);}
Figure 5‑1 Forwarding a Request
Figure 5‑1 Forwarding a Request
.../* 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);
Notes: The Oracle Tuxedo libraries are linked in automatically. You do not need to specify the Oracle Tuxedo library names on the command line.
long handletpsubscribe (char *eventexpr, char *filter, TPEVCTL *ctl, long flags)
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));}
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);}
Listing 9‑1 Defining a Global Transaction - High-level 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‑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 }
Listing 9‑6 Testing Transaction Level
Listing 9‑6 Testing Transaction Level
Notes: An application-created server thread cannot call either tpreturn() or tpforward().
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);}
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. */
System Errors
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 }