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

Customizing a Buffer

You may find that the buffer types supplied by the BEA Tuxedo system do not meet your needs. For example, perhaps your application uses a data structure that is not flat, but has pointers to other data structures, such as a parse tree for an SQL database query. To accommodate unique application requirements, the BEA Tuxedo System supports customized buffers.

To customize a buffer, you need to identify the following characteristics.

Custom Buffer Type Characteristics

Characteristic

Description

Buffer type

Name of the buffer type, specified by a string of up to eight characters.

Buffer subtype

Name of the buffer subtype, specified by a string of up to 16 characters. The system uses a subtype to identify different processing requirements for buffers of a given type. When the wildcard character (*) is specified as the subtype value, all buffers of a given type can be processed using the same generic routine. Any buffers for which a subtype is defined must appear before the wildcard in the list, in order to be processed correctly.

Default size

Minimum size of the associated buffer type that can be allocated or reallocated. For buffer types that have a value greater than zero and that are sized appropriately, you can specify a buffer size of zero when allocating or reallocating a buffer to use this default size.

The following table defines the list of routines that you may need to specify for each buffer type. If a particular routine is not applicable, you can simply provide a NULL pointer; the BEA Tuxedo system uses default processing, as necessary.

Custom Buffer Type Routines

Routine

Description

Buffer initialization

Initializes a newly allocated typed buffer.

Buffer reinitialization

Reinitializes a typed buffer. This routine is called after a buffer has been reallocated (that is, assigned a new size).

Buffer uninitialization

Uninitializes a typed buffer. This routine is called just before a typed buffer is freed.

Buffer presend

Prepares the typed buffer for sending. This routine is called before a typed buffer is sent as a message to another client or server. It returns the length of the data to be transmitted.

Buffer postsend

Returns the typed buffer to its original state. This routine is called after the message is sent.

Buffer postreceive

Prepares the typed buffer once it has been received by the application. It returns the length of the application data.

Encode/decode

Performs all the encoding and decoding necessary for the buffer type. A request to encode or decode is passed to the routine, along with input and output buffers and lengths. The format used for encoding is determined by the application and, as with the other routines, it may be dependent on the buffer type.

Routing

Specifies the routing information. This routine is called with a typed buffer, the length of the data for that buffer, a logical routing name configured by an administrator, and a target service. Based on this information, the application must select the server group to which the message should be sent or indicate that the message is not needed.

Filter

Specifies filter information. This routine is called to evaluate an expression against a typed buffer and to return a match if it finds one. If the typed buffer is VIEW or FML, the FML Boolean expressions are used. This routine is used by the EventBroker to evaluate matches for events.

Format

Specifies a printable string for a typed buffer.

Defining Your Own Buffer Types

The application programmer is responsible for the code that manipulates buffers, which allocates and frees space, and sends and receives messages. For applications in which the default buffer types do not meet the needs of the application, other buffer types can be defined, and new routines can be written and then incorporated into the buffer type switch.

To define other buffer types, complete the following steps:

  1. Code any switch element routines that may be required.

  2. Add your new types and the names of your buffer management modules to tm_typesw.

  3. Build a new shared object or a DLL. The shared object or DLL must contain your updated buffer type switch and associated functions.

  4. Install your new shared object or DLL so that all servers, clients, and executables provided by the BEA Tuxedo system are loaded dynamically at run time.

If your application is using static libraries and you are providing a customized buffer type switch, then you must build a custom server to link in your new type switch. For details, see buildwsh (1), TMQUEUE (5), or TMQFORWARD (5).

The rest of the sections in this topic address the steps listed in the preceding procedure to define a new buffer type in a shared-object or DLL environment. First, however, let's look at the buffer switch that is delivered with the BEA Tuxedo system software. The following listing shows the switch delivered with the system.

Default Buffer Type Switch


#include <stdio.h>
#include <tmtypes.h>

/* Initialization of the buffer type switch */
static struct tmtype_sw_t tm_typesw[] = {
{
"CARRAY", /* type */
"", /* subtype */
0 /* dfltsize */
},
{
"STRING", /* type */
"", /*subtype */
512, /* dfltsize */
NULL, /* initbuf */
NULL, /* reinitbuf */
NULL, /* uninitbuf */
_strpresend, /* presend */
NULL, /* postsend */
NULL, /* postrecv */
_strencdec, /* encdec */
NULL, /* route */
NULL, /* filter */
NULL /* format */
},
{
"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 */
},
{
"FML32", /* type */
"", /* subtype */
1024, /* dfltsize */
_finit32, /* initbuf */
_freinit32, /* reinitbuf */
_funinit32, /* uninitbuf */
_fpresend32, /* presend */
_fpostsend32, /* postsend */
_fpostrecv32, /* postrecv */
_fencdec32, /* encdec */
_froute32, /* route */
_ffilter32, /* filter */
_fformat32 /* format */
},
{
"VIEW", /* type */
"*", /* subtype */
1024, /* dfltsize */
_vinit, /* initbuf */
_vreinit, /* reinitbuf */
NULL, /* uninitbuf */
_vpresend, /* presend */
NULL, /* postsend */
NULL, /* postrecv */
_vencdec, /* encdec */
_vroute, /* route */
_vfilter, /* filter */
_vformat /* format */
},
{
"VIEW32", /* type */
"*" /* subtype */
1024, /* dfltsize */
_vinit32, /* initbuf */
_vreinit32, /* reinitbuf */
NULL, /* uninitbuf */
_vpresend32, /* presend */
NULL, /* postsend */
NULL, /* postrecv */
_vencdec32, /* encdec */
_vroute32, /* route */
_vfilter32, /* filter */
_vformat32 /* format */
},
{
"X_OCTET", /* type */
"", /* subtype */
0, /* dfltsize */
},
{
"'X','_','C','_','T','Y','P','E'", /* type */
"*", /* subtype */
1024, /* dfltsize */
_vinit, /* initbuf */
_vreinit, /* reinitbuf */
NULL, /* uninitbuf */
_vpresend, /* presend */
NULL, /* postsend */
NULL, /* postrecv */
_vencdec, /* encdec */
_vroute, /* route */
_vfilter, /* filter */
_vformat /* format */
},
{
"'X','_','C','O','M','M','O','N'", /* type */
"*", /* subtype */
1024, /* dfltsize */
_vinit, /* initbuf */
_vreinit, /* reinitbuf */
NULL, /* uninitbuf */
_vpresend, /* presend */
NULL, /* postsend */
NULL, /* postrecv */
_vencdec, /* encdec */
_vroute, /* route */
_vfilter, /* filter */
_vformat /* format */
},
{
"XML", /* type */
"*", /* subtype */
0, /* dfltsize */
NULL, /* _xinit - not available */
NULL, /* _xrein

For a better understanding of the preceding listing, consider the declaration of the buffer type structure that is shown in the following listing.

Buffer Type Structure


/* The following definitions are in $TUXDIR/include/tmtypes.h */

#define TMTYPELEN			      8
#define TMSTYPELEN 16

struct tmtype_sw_t {
char type[TMTYPELEN]; /* type of buffer */
char subtype[TMSTYPELEN]; /* sub-type of buffer */
long dfltsize; /* default size of buffer */
/* buffer initialization function pointer */
int (_TMDLLENTRY *initbuf) _((char _TM_FAR *, long));
/* buffer re-initialization 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));
/* 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));
/* this space reserved for future expansion */
void (_TMDLLENTRY *reserved[10]) _((void));
};


The listing for the default buffer type switch shows the initialization of the buffer type switch. The nine default buffer types are shown, followed by a field for naming a subtype. Except for the VIEW (and equivalently X_C_TYPE and X_COMMON) type, subtype is null. The subtype for VIEW is given as \Q\Q*'', which means that the default VIEW type puts no constraints on subtypes; all subtypes of type VIEW are processed in the same manner.

The next field gives the default (minimum) size of the buffer. For the CARRAY (and equivalently X_OCTET) type this is given as 0, which means that the routine that uses a CARRAY buffer type must tpalloc() enough space for the expected CARRAY.

For the other types, the BEA Tuxedo system allocates (with a tpalloc() call) the space shown in the dfltsize field of the entry (unless the size argument of tpalloc() specifies a larger size).

The remaining eight fields of entries in the buffer type switch contain the names of switch element routines. These routines are described in the buffer(3c) page in BEA Tuxedo C Function Reference. The name of a routine provides a clue to the purpose of the routine. For example, _fpresend on the FML type is a pointer to a routine that manipulates the buffer before sending it. If no presend manipulation is needed, a NULL pointer may be specified. NULL means no special handling is required; the default action should be taken. See buffer(3c) for details.

It is particularly important that you notice the NULL entry at the end of the switch. Any changes that are made must always leave the NULL entry at the end of the array.

Coding Switch Element Routines

Presumably an application that is defining new buffer types is doing so because of a special processing need. For example, let's assume the application has a recurring need to compress data before sending a buffer to the next process. The application could write a presend routine. The declaration for the presend routine is shown in the following listing.

Semantics of the Presend Switch Element


long
presend(ptr, dlen, mdlen)
char *ptr;

long dlen, mdlen;


The data compression that takes place within your presend routine is the responsibility of the system programmer for your application.

On completion the routine should return the new, hopefully shorter length of the data to be sent (in the same buffer), or a -1 to indicate failure.

The name given to your version of the presend routine can be any identifier accepted by the C compiler. For example, suppose we name it _mypresend.

If you use our _mypresend compression routine, you will probably also need a corresponding _mypostrecv routine to decompress the data at the receiving end. Follow the template shown in the buffer(3c) entry in BEA Tuxedo C Function Reference.

Adding a New Buffer Type to tm_typesw

After the new switch element routines have been written and successfully compiled, the new buffer type must be added to the buffer type switch. To do this task, we recommend making a copy of $TUXDIR/lib/tmtypesw.c (the source code for the default buffer type switch). Give your copy a name with a .c suffix, such as mytypesw.c. Add the new type to your copy. The name of the type can be up to 8 characters in length. Subtype can be null ("") or a string of up to 16 characters. Enter the names of your new switch element routines in the appropriate locations, including the extern declarations. The following listing provides an example.

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 */
},
{
""
}
};


In the previous listing, we added a new type: SOUND. We also removed the entries for VIEW, X_OCTET, X_COMMON, and X_C_TYPE, to demonstrate that you can remove any entries that are not needed in the default switch. Note that the array still ends with the NULL entry.

An alternative to defining a new buffer type is to redefine an existing type. Suppose, for the sake of argument, that the data compression for which you defined the buffer type MYTYPE was performed on strings. You could substitute your new switch element routines, _mypresend and _mypostrecv, for the two _dfltblen routines in type STRING.

Compiling and Linking Your New tm_typesw

To simplify installation, the buffer type switch is stored in a shared object.

Note: On some platforms the term "shared library" is used instead of "shared object." On the NT platform a "dynamic link library" is used instead of a "shared object." For the purposes of this discussion, however, the functionality implied by all three terms is equivalent, so we use only one term.

This section describes how to make all BEA Tuxedo processes in your application aware of the modified buffer type switch. These processes include application servers and clients, as well as servers and utilities provided by the BEA Tuxedo system.

  1. Copy and modify $TUXDIR/lib/tmtypesw.c, as described in Adding a New Buffer Type to tm_typesw. If additional functions are required, store them in either tmtypesw.c or a separate C source file.

  2. Compile tmtypesw.c with the flags required for shared objects.

  3. Link together all object files to produce a shared object.

  4. Copy libbuft.so.71 from the current directory to a directory in which it will be visible to applications, and processed before the default shared object supplied by the BEA Tuxedo system. We recommend using one of the following directories: $APPDIR, $TUXDIR/lib, or $TUXDIR/bin (on an NT platform).

Different platforms assign different names to the buffer type switch shared object, to conform to operating system conventions.

OS-specific Names for the Buffer Type Switch Shared Object

On This Platform . . .

The Name of the Buffer Type Switch Shared Object Is . . .

UNIX System
(most SVR4)

libbuft.so.71

HP-UX

libbuft.sl

Sun OS

libbuft.so.71

Windows (16-bit)

wbuft.dll

Windows (32-bit)

wbuft32.dll

OS/2 (16-bit)

obuft.dll

OS/2 (32-bit)

obuft.dll

Please refer to the software development documentation for your platform for instructions on building a shared object library.

As an alternative, it is possible to statically link a new buffer type switch in every client and server process, but doing so is more error-prone and not as efficient as building a shared object library.

Compiling and Linking Your New tm_typesw for a 16-bit Windows Platform

If you have modified tmtypesw.c on a Windows platform, as described in Compiling and Linking Your New tm_typesw, then you can use the commands shown in the following sample code listing to make the modified buffer type switch available to your application.

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.C
LINK /CO /ALIGN:16 TMTYPESW.OBJ, WBUFT.DLL, NUL, WTUXWS /SE:250 /NOD
/NOE LIBW LDLLCEW, WBUFT.DEF
RC /30 /T /K WBUFT.DLL


Data Conversion

The purpose of the TYPE parameter in the MACHINES section of the configuration file is to group together machines that have the same form of data representation (and use the same compiler) so that data conversion is done on messages going between machines of different TYPEs. For the default buffer types, data conversion between unlike machines is transparent to the user (and to the administrator and programmer, for that matter).

If your application defines new buffer types for messages that move between machines with different data representation schemes, you must also write new encode/decode routines to be incorporated into the buffer type switch. When writing your own data conversion routines, keep the following guidelines in mind:

The encode/decode routines are called only when the BEA Tuxedo system determines that data is being sent between two machines that are not of the same TYPE.