![]() |
![]() |
|
|
Defining a Service
You must define every service routine as a function that receives one argument consisting of a pointer to a TPSVCINFO structure. The TPSVCINFO structure is defined in the atmi.h header file and includes the following information:
char name[32];
long flags;
char *data;
long len;
int cd;
int appkey;
CLIENTID cltid;
The following table summarizes the TPSVCINFO data structure.
TPSVCINFO Data Structure
The following example illustrates a typical service definition. This code is borrowed from the ABAL (account balance) service routine that is part of the banking application provided with the BEA Tuxedo software. ABAL is part of the BAL server.
Typical Service Definition
#include <stdio.h> /* UNIX */
#include <atmi.h> /* BEA Tuxedo System */
#include <sqlcode.h> /* BEA Tuxedo System */
#include "bank.flds.h" /* bankdb fields */
#include "aud.h" /* BANKING view defines */
EXEC SQL begin declare section;
static long branch_id; /* branch id */
static float bal; /* balance */
EXEC SQL end declare section;
/*
* Service to find sum of the account balances at a SITE
*/
void
#ifdef __STDC__
ABAL(TPSVCINFO *transb)
#else
ABAL(transb)
TPSVCINFO *transb;
#endif
{
struct aud *transv; /* view of decoded message */
/* Set pointer to TPSVCINFO data buffer */
transv = (struct aud *)transb->data;
set the consistency level of the transaction
/* Get branch id from message, do query */
EXEC SQL declare acur cursor for
select SUM(BALANCE) from ACCOUNT;
EXEC SQL open acur; /* open */
EXEC SQL fetch acur into :bal; /* fetch */
if (SQLCODE != SQL_OK) { /* nothing found */
(void)strcpy (transv->ermsg,"abal failed in sql aggregation");
EXEC SQL close acur;
tpreturn(TPFAIL, 0, transb->data, sizeof(struct aud), 0);
}
EXEC SQL close acur;
transv->balance = bal;
tpreturn (TPSUCCESS, 0, transb->data, sizeof(struct aud), 0);
}
In the preceding example, the application allocates a request buffer on the client side by a call to tpalloc() with the type parameter set to VIEW and the subtype set to aud. The ABAL service is defined as supporting the VIEW typed buffer. The BUFTYPE parameter is not specified for ABAL and defaults to ALL. The ABAL service allocates a buffer of the type VIEW and assigns the data member of the TPSVCINFO structure that was passed to the ABAL subroutine to the buffer pointer. The ABAL server retrieves the appropriate data buffer by accessing the corresponding data member, as illustrated in the preceding example.
Note: After the buffer is retrieved, but before the first attempt is made to access the database, the service must specify the consistency level of the transaction. Refer to Writing Global Transactions for more details on transaction consistency levels.
Example: Checking the Buffer Type
The code example in this section shows how a service can access the data buffer defined in the TPSVCINFO structure to determine its type by using the tptypes() function. (This process is described in Checking for Buffer Type.) The service also checks the maximum size of the buffer to determine whether or not to reallocate space for the buffer.
This example is derived from the ABAL service that is part of the banking application provided with the BEA Tuxedo software. It shows how the service is written to accept a request either as an aud VIEW or an FML buffer. If its attempt to determine the message type fails, the service returns a string with an error message plus an appropriate return code; otherwise it executes the segment of code that is appropriate for the buffer type. For more information on the tpreturn() function, refer to Terminating a Service Routine.
Checking for Buffer Type
#define TMTYPERR 1 /* return code indicating tptypes failed */
#define INVALMTY 2 /* return code indicating invalid message type */
void
ABAL(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
Note: The tpgprio() and tpsprio() functions, used for getting and setting priorities, respectively, are described in detail in Setting and Getting Message Priorities.
The example code in this section shows how a service called PRINTER tests the priority level of the request just received using the tpgprio() function. Then, based on the priority level, the application routes the print job to the appropriate destination printer and pipes the contents of pbuf—>data to that printer.
The application queries pbuf—>flags to determine whether a reply is expected. If so, it returns the name of the destination printer to the client. For more information on the tpreturn() function, refer to Terminating a Service Routine.
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++]);
}
![]() |
![]() |
![]() |
|
Copyright © 2001 BEA Systems, Inc. All rights reserved.
|