Table of Contents
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Listing 2‑1 Allocating a VIEW Typed Buffer
      
      
      
      
      
      
      Listing 2‑5 Putting Data in a Message Buffer - Example 1
      
      
      
      
      Listing 2‑7 Resizing a Buffer
      
      
      
      
      Listing 2‑9 Getting Buffer Size
      
      
      
      Listing 2‑10 Freeing a Buffer
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Listing 2‑15 myview.flds.h Header File
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      Figure 2‑1 Encoding Conversion Using MBSTRING Buffers—Example
      
      
      
      
      
      
      
      
      
      
      
      
      
      Listing 2‑17 Default Buffer Type Switch
      Listing 2‑17 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‑20 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‑21 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 }