BEA Logo BEA Tuxedo Release 7.1

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

 

   Tuxedo Doc Home   |   Programming   |   Topic List   |   Previous   |   Next   |   Contents

   Programming a BEA Tuxedo Application Using C

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

Field

Description

name

Specifies, to the service routine, the name used by the requesting process to invoke the service.

flags

Notifies the service if it is in transaction mode or if the caller is expecting a reply. The various ways in which a service can be placed in transaction mode are discussed in Writing Global Transactions.

The TPTRAN flag indicates that the service is in transaction mode. When a service is invoked through a call to tpcall() or tpacall() with the flags parameter set to TPNOTRAN, the service cannot participate in the current transaction. However, it is still possible for the service to be executed in transaction mode. That is, even when the caller sets the TPNOTRAN communication flag, it is possible for TPTRAN to be set in svcinfo->flags. For an example of such a situation, refer to Writing Global Transactions.

The flags member is set to TPNOREPLY if the service is called by tpacall() with the TPNOREPLY communication flag set. If a called service is part of the same transaction as the calling process, it must return a reply to the caller.

data

Pointer to a buffer that was previously allocated by tpalloc() within the main(). This buffer is used to receive request messages. However, it is recommended that you also use this buffer to send back reply messages or forward request messages.

len

Contains the length of the request data that is in the buffer referenced by the data field.

cd

For conversational communication, specifies the connection descriptor.

appkey

Reserved for use by the application. If application-specific authentication is part of your design, the application-specific authentication server, which is called when a client joins the application, should return a client authentication key as well as an indication of success or failure. The BEA Tuxedo system holds the appkey on behalf of the client and passes the information to subsequent service requests in this field. By the time the appkey is passed to a service, the client has already been authenticated. However, the appkey field can be used within a service to identify the user invoking the service or some other parameters associated with the user.

If this field is not used, the system assigns it a default value of -1.

cltid

Structure of type CLIENTID used by the system to carry the identification of the client. You should not modify this structure.

When the data field in the TPSVCINFO structure is being accessed by a process, the following buffer types must agree:

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 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++]);
}