Developing Tamino Server Extensions

This section describes how server extensions can be implemented. The Direct and Java infrastructures can be used. Direct extensions are written in C++; Java extensions are of course written in Java. First decide on the infrastructure that you want to use before choosing the programming language. The tool to be used depends on this decision. For related information about Tamino server extensions and how they can be developed, see the Introduction and the section Tamino Server Extension Functions.

As described in the section Building a Tamino Server Extension Package, it is easy to create Tamino server extensions using the tools provided with Tamino. Basic knowledge of C++ or Java is sufficient to create simple but effective server extensions. We recommend using these tools whenever you develop a Tamino server extension.

Note:
The use of external synchronization mechanisms within a server extension that is not under control of the Tamino Server / X-Machine can lead to problems. Such problems can include deadlocks that cannot be resolved by the X-Machine's deadlock resolution capabilities; this may lead to requests hanging up, either completely or until a transaction timeout occurs. Therefore, for example, the Java code in a server extension should not use Java-based locking.

The following sections, which address some specific programming issues, should help you write valid function code.


Constructors and Destructors

Constructors and destructors that are required for object-oriented programming can also be used in Tamino server extensions. As Tamino server extension objects are created implicitly by the Tamino Server, if one of its extension functions is called, it is not possible to use constructors that pass parameters, with the exception of the callback handle in the Direct infrastructure (see below).

Direct

You can use common C++ constructors. Note that two types of constructors can be called when a Direct server extension is initialized:

  • Constructors that can accept one single parameter of type SXDCHandle. This type of constructor must be available if callbacks are to be used in the Direct server extension's code. The SXDCHandle parameter is the callback handle that must be used for all callbacks. We recommend storing this handle in a member variable of the server extension's class:

    CMyExtension::CMyExtension (SXDCHandle h)
            : m_callback (h)
    {
           // more initializations here
    }
  • The default constructor (i.e. a constructor without parameters). In this case no callbacks are available.

Java

You can use the common Java constructors. Note that the default constructor (this is one without any parameters) is called when a Java server extension is initialized. If you do not define any constructors in your server extension class, this default constructor is implicitly provided by Java. As stated above, constructors with parameters cannot be called by the Tamino Server; instead, you should use an initial function. If for some reason your server extension class contains one or more constructors with one or more parameters, you must also define a default constructor without any parameters; otherwise an error occurs when initializing the class.

Initial Functions

The initial function can be generated automatically if the Tamino server extension development tools are used. You can find detailed information in the section Initial Server Extension Functions.

String and Memory Handling

Direct

For all kinds of string parameters (including the XML type "ino:XML-OBJ") and byte arrays, the special data type "sxdstring" must be used. For return and output values, sxdstrings must be allocated by the callback functions:

sxdstring AllocString (wchar_t*)

Input can be a zero-terminated ASCII or wide character string or a string constant.

sxdstring AllocStringByte (void*, sxdulong)

Used for binary data.

Strings allocated by these functions (including input parameters) may be freed by

  • FreeString

However, it is not mandatory to use FreeString, as the memory used for a Direct server extension is released when a server extension object is deleted.

For reading operations, you may treat strings of type sxdstring like common wide character strings (see the examples).

There are two more string handling functions:

  • sxdulong StringLen (sxdstring)

  • sxdulong StringByteLen (sxdstring)

to get the length of string variables.

Examples:

Get the callback handle in the constructor (see above):

      MyExtension::MyExtension (SXDCHandle h)
              :m_callback (h)
      { ... }

Have a query function:

sxdstring MyExtension:::myQuery(sxdstring input)
{
    // allocate a wide character string myBuffer
    swprintf(myBuffer, L "This was the input: %", input);

    sxdstring retval = m_callback->AllocString(myBuffer);
    free (myBuffer);

    return retval;
}

Caution:
Do not assign a string constant to an output parameter of type sxdstring*, for example *nodeinfo=L"abc"; instead, use *nodeinfo = m_callback -> AllocString (L"abc");

Java

All Java string objects used as "in" and "out" parameters are initialized by the Tamino Server and can be used in the server extension function. You must write code in the server extension function to initialize any java.lang.String that is used as a return value.

As is usual in Java, it is not necessary to free or delete objects.

Specialities of Different Infrastructure/Language Combinations

The information in this section is broken down as follows:

Restrictions for Java Server Extensions

To ensure the stability of the Tamino Server and the Java Virtual Machine, the following operations are locked for Java-based server extensions. Any attempt to call them leads to a security exception:

  • Exit the Java Virtual Machine;

  • Modify or stop Java system threads;

  • Redefine the standard I/O streams;

  • Define your own security manager;

  • Modify Java security configuration aspects such as policy, security provider, identifications, and private keys.

As the Java Virtual Machine runs in batch mode, the standard I/O streams cannot be used in server extensions. Output has no effect. To avoid long waits when trying to read from standard input, this stream is set to null, so any attempt to read from it immediately leads to a null pointer exception.

Callbacks

Arbitrary database calls to arbitrary databases, including the Tamino Server, can be implemented in a server extension function via the standard database interfaces. In general, however, it is more desirable to access databases from within the same session and transaction context as the Tamino Server session in which the server extension function is called. Databases can be accessed in this way by using Tamino callbacks. Tamino callbacks are interfaces to the Tamino Server that can be used in a server extension function. They provide access to the various databases that can be attached by the Tamino Server, and also to system information available in the running Tamino Server.

The following categories of callbacks are supported: XML callbacks, ODBC callbacks and system callbacks.

For information about runtime errors that can result from callback calls and the handling of these errors, see the section Callback Error Handling.

XML Callbacks

XML callbacks support X-Machine command requests to the running Tamino database. The callback functions and their corresponding X-Machine commands are listed in the following table:

Callback Function X-Machine Command
SxsXMLAdmin _admin
SxsXMLDefine _define
SxsXMLDelete _delete
SxsXMLProcess _process
SxsXMLUndefine _undefine
SxsXMLXql _xql
SxsXMLXQuery _xquery

These X-Machine commands are described in the section Requests using X-Machine Commands of the X-Machine Programming documentation.

There is an additional callback function, SxsXMLGetMessage, to get messages from the Tamino Server.

The following administration functions are available in the SxsXMLAdmin callback:

All other administration functions mentioned in the documentation section X-Machine Programming > Requests using X-Machine Commands > The _admin command are unavailable.

Notes:

  1. When an XML callback is used, the following database commands cannot be issued: open database session, close database session, commit and rollback. These commands are implicitly handled by the Tamino Server.
  2. An XML callback cannot be used within an event function.

Direct

The following functions are methods of the callback handle and must be called using m_callback-> <function name> (<arglist>):

sxdint SxsXMLXQuery (sxdstring collection, sxdstring query, sxdresult* result);

sxdint SxsXMLXql (sxdstring collection, sxdstring query, sxdstring* response);

sxdint SxsXMLProcess (sxdstring collection, sxdstring xmlDoc, sxdstring* response);

sxdint SxsXMLDefine (sxdstring xmlSchema, sxdstring* response);

sxdint SxsXMLUndefine (sxdstring collection, sxdstring schema, sxdstring doctype, sxdstring* response);

sxdint SxsXMLDelete(sxdstring collection, sxdstring query, sxdstring* response);

sxdint SxsXMLAdmin (sxdstring command, sxdstring* response);

sxdint SxsGetDocument (sxdstring collection, sxdstring doctype, sxduint inoid, sxdresult* result);

sxdint SxsGetDocument (sxdstring collection, sxdstring doctype, sxdstring documentId, sxdresult* result);

sxdint SxsXMLGetMessage(sxdstring* msgContent);

Input parameters of type sxdstring must be allocated using m_callback -> AllocString() and freed after the call using m_callback -> FreeString(). The output parameters response and msgContent must be valid pointers to an sxdstring, and their contents should be null. The output parameter result must be a valid pointer to an sxdresult, and its contents should be valid (the constructor guarantees this).

Java Calls

int SxsXMLXQuery (String collection, String query, Result result);

int SxsXMLXql (String collection, String query, StringBuffer response);

int SxsXMLProcess (String collection, String xmlDoc, StringBuffer response);

int SxsXMLDefine (String xmlSchema, StringBuffer response);

int SxsXMLUndefine (String collection, String schema, String doctype, StringBuffer response);

int SxsXMLDelete (String collection, String query, StringBuffer response);

int SxsXMLAdmin (String command, StringBuffer response);

int SxsGetDocument (String collection, String doctype, int inoid, Result result);

int SxsGetDocument (String collection, String doctype, String documentID, Result result);

int SxsXMLGetMessage (StringBuffer msgContent);

The output parameters response and msgContent must be initialized StringBuffer objects, and their content should be the empty string. On return, they contain the response document of the XML request or the Tamino Server message.

Meaning of Parameters (For All Infrastructures)

The parameters used in the syntax descriptions above have the following meanings:

Parameter Meaning
collection The name of the collection upon which the callback operates. For the SxsXMLDefine function, this is the name that is assigned to the newly-created collection. For the other requests, it must be the name of a collection that already exists in the database.
xmlDoc XML document for the command _process.
xmlSchema XML schema document for the command _define.

The syntax of each X-Machine command is defined in the section Requests using X-Machine Commands of the section X-Machine Programming.

collection

The name of the collection upon which the callback operates. For the SxsXMLDefine function, this is the name that is assigned to the newly-created collection. For the other requests, it is the name of an existing collection.

reqContent

The valid input for this parameter can be found in the description of the appropriate X-Machine command in the X-Machine Programming documentation.

The Meaning of sxdresult (Direct) and Result (Java)

The output parameter of the callback functions SxsXMLXQuery and SxsGetDocument is of type sxdresult (Direct) or Result (Java).

In the case of the Direct infrastructure, sxdresult is a class of the form:

class sxdresult
{
    public:

    sxdresult();
    virtual ~sxdresult();

    /* is result a string? */
    sxdbool isString() const;

    /* is result a binary? */
    sxdbool isBinary() const;

    /* get media type of result */
    sxdstring getMediaType() const;

    /* get string value if isString is true else SXD_NULL */
    sxdstring getStringValue() const;

    /* get binary value if isBinary is true else SXD_NULL */
    sxdbinary getBinaryValue() const;
}

In the case of the Java infrastructure, Result is a class:

public class Result
{
    public Result();

    // Reset to an empty but valid result set.
    public void reset();

    // Get the media type of the result.
    public String getMediaType();

    // Is this a string value?
    public boolean isString();

    // Get the result value as a string.
    // @returns the string value or an empty string
    public String getStringValue();

    // Is this a binary value?
    public boolean isBinary();

    // Get the result value as a binary (byte array).
    // @returns the binary value or a zero length byte array
    public byte[] getBinaryValue();
}

Return Values and Output Parameters

For all infrastructures, the return values and output parameters are as follows:

A return code of 0 indicates success; anything else indicates that the call failed. For more information about errors, see the section Callback Error Handling.

After a successful call, the content of the output parameter response is as follows:

Callback function Content of output parameter response
SxsXMLXQuery The node set resulting from the specified XQuery, enclosed in the tags <xq:result> ... </xq:result> as from the Tamino response document.
SxsXMLXql The node set resulting from the specified X-Query, enclosed in the tags <xql:result> ... </xql:result> as from the Tamino response document.
SxsXMLProcess A node <ino:object ino:collection="..." ino:doctype="..." ino:id="..."> containing the collection name, document type and ID of the processed XML document as from the Tamino response document.

If the return value of any callback function is nonzero and SxsGetMsgNo() reports a Tamino Server error (see Callback Error Handling), then the function SxsGetMsgText() should be called. The output parameter msgContent of this function contains a message as it would have appeared in the node <ino:messageline>=...</ino:messageline> of the Tamino response document.

A complete example of the usage of an XML callback including appropriate error handling can be found in the section Callback Error Handling.

Note that XML callbacks can be used recursively. For example, an XML document contains an element that is mapped to a server extension function that uses an XML callback to send an SxsXMLProcess() request to the Tamino Server. The resulting XML document provided by the Tamino Server also contains an element that is mapped to the same server extension function, which is called recursively. In such cases the following points should be taken into consideration:

  • Any data stored in a member variable of the server extension function object or any other object created in the server extension function context can be overwritten during the recursive server extension function call, and may therefore have been changed when the XML request returns.

  • It is the responsibility of the server extension function developer to prevent infinite loops. The SXS infrastructure makes some checks that attempt to prevent excessive recursion.

For SxsXMLXql()

The node set resulting from the passed XML query, enclosed in the tags <xql:result>...</xql:result> as known from the Tamino response document.

For SxsXMLProcess()

A node <ino:object ino:collection="..." ino:doctype="..." ino:id="..."> containing the collection name, document type, and ID of the XML document that was just processed, as known from the Tamino response document.

If the return value of any callback function is non-zero and SxsGetMsgNo reports a Tamino Server error (see Callback Error Handling below), then the function SxsGetMesText() should be called. The out parameter msgContent of this function contains a message as it would have appeared in the node <ino:messageline>=...</ino:messageline> of the Tamino response document.

A complete example of the usage of an XML callback including appropriate error handling can be found in the section Callback Error Handling below.

The callback function SxsXMLXql() can now return namespace-clean results. This means that the results can be passed directly to any standard XML parser. This option is controlled by a parameter that can be accessed using the Tamino Manager: start the Tamino Manager, then in the tree view select Managed Hosts > localhost > Tamino > Databases > database_name > Properties > X-Tension. The option X-Tension callback namespace clean is displayed, and by choosing the command Modify you can display a screen in which you can change the value of this parameter from "yes" to "no" or vice versa. The default value of the X-Tension callback namespace clean parameter for all new databases is "yes". The default value of the X-Tension callback namespace clean parameter for a database that has been converted by using the Tamino Manager Set version command and that has server extensions installed is "no"; this ensures backward compatibility with old server extensions that add namespace declarations to the results returned by the SxsXMLXql() callback function.

Note:

XML callbacks can be used recursively. For example, an XML document contains an element that is mapped to a server extension function which uses an XML callback to send an SxsXMLProcess() request to the Tamino Server. The resultant XML document provided by the Tamino Server also contains an element that is mapped to the same server extension function, which is called recursively. The following points should be taken into consideration in such cases:

  • Any data stored in a member variable of the server extension function object or any other object created in the server extension function context can be overwritten during the recursive server extension function call, and may therefore have been changed when the XML request returns.

  • It is the responsibility of the server extension function developer to prevent infinite loops.

Examples

The following section shows some examples in the various infrastructures. Error handling has been omitted for the sake of clarity.

Direct
sxdstring collection = m_callback->AllocString(L"MyCollection");
sxdstring query = m_callback->AllocString(L"/MyDoctype/Node_A[anyId='5']");
sxdstring response = SXD_NULL;

int ret = m_callback->SxsXMLXql(collection, query, &response);

if (ret != 0)
{
    // do any error handling, see chapter Callback Error Handling
}

// do any work ...
Java
String collection = "MyCollection";
String query = "/MyDoctype/Node_A[anyId='5']";
StringBuffer response = new StringBuffer();

int ret = SxsXMLXql(collection, query, response);

if (ret != 0)
{
    // do any error handling, see chapter Callback Error Handling
}

// do any work ...

ODBC Callbacks

ODBC callbacks support calls to any relational database that can be accessed via the Microsoft Windows ODBC Manager as a system DSN (Data Source Name).

ODBC callbacks are [currently] only available for Microsoft Windows ODBC Manager.

The parameter types used within an ODBC callback are defined in the Sqltypes.h file, which is stored in the directory ...\Microsoft Visual Studio\VC98\Include. This file can be included in a server extension using an ODBC callback.

Character data is given and received as byte arrays in the encoding of the respective data source, which is commonly ASCII. Since Tamino stores XML data as Unicode strings, conversion may be necessary.

The next sections describe how you can allocate a handle and memory, and which ODBC functions are supported for Direct and Java.

Note:
ODBC callbacks cannot be used within event functions. ODBC functions can be used in init functions to establish ODBC connections.

Allocating Handles

Connect Handles

Connect handles are required to access a database. They are allocated as follows:

Direct call:
SQLRETURN SxsSQLGetConnect(SQLTCHAR* dbName,
                           SQLTCHAR* userName,
                           SQLTCHAR* password,
                           sxdint* dbHandle);
Java call:
public int SxsSQLGetConnect(String dbName,
                            String userName,
                            String password,
                            IntRef Handle);
All infrastructures:

This call is used instead of the calls of the common ODBC interface that are used to prepare a connection. This call delivers the connect handle if a valid ODBC database name was provided. Note that this handle is not a valid ODBC handle and cannot be used for ODBC calls (its data type is not SQLHDBC but a simple long integer). The server extension function developer can access an ODBC database using ODBC calls independently of the Tamino Server, but he or she must perform all of the ODBC steps required to set up a connection and to close it again later.

The handle is only valid when using the Tamino Server ODBC callback interface. This interface implements a subset of the functions provided with the ODBC core level, version 3. The common ODBC calls are used with the prefix "Sxs", for example SxsSQLExecute(). The usage and the parameters of the functions are the same as for the original ODBC functions, with the exception of handles, which are long integers.

Statement Handles

Statement handles are allocated as follows:

Direct:

All ODBC callbacks are methods of the callback handle.

SQLRETURN SxsSQLAllocHandle(short hdType,
                            sxdint dbCHandle,
                            sxdint* dbSHandle);

This call does not return an ODBC handle of data type SQLHSTMT; rather, it returns a long integer that can only be used with the Tamino Server ODBC callback interface. This function can only be used with the HandleType SQL_HANDLE_STMT. This also applies to the function SxsSQLGetDiagField.

SQLRETURN SxsSQLFreeHandle(short hdType, sxdint dbCHandle);
Java:
public int SxsSQLAllocHandle(short HandleType,
                             int InputHandle,
                             IntRef OutputHandle);

This call does not return an ODBC handle; rather, it returns an integer that can only be used with the Tamino Server ODBC callback interface. SxsSQLGetDiagField and SxsSQLFreeHandle must also be of the HandleType SQL_HANDLE_STMT.

A statement handle allocated with SxsSQLAllocHandle() must be freed using:

public int SxsSQLFreeHandle(short HandleType,
                            int Handle);

Allocating Memory

Java:

The byte arrays for the result values must be initialized with the length that is also given as a parameter using new byte [BufferLength]. IntRef is an auxiliary class for output parameters as well as for in and out parameters. It represents a reference to an integer with the following methods:

public IntRef(int initVal);

public int getVal();

public void setVal(int newVal);

All parameters of type IntRef must be initialized.

The Other Supported ODBC Functions

Direct:
SQLRETURN SxsSQLPrepare(sxdint StatementHandle,
                        SQLTCHAR* StatementText,
                        SQLINTEGER TextLength);

SQLRETURN SxsSQLBindParameter(sxdint StatementHandle,
                              SQLUSMALLINT ParameterNumber,
                              SQLSMALLINT InputOutputType,
                              SQLSMALLINT ValueType,
                              SQLSMALLINT ParameterType,
                              SQLUINTEGER ColumnSize,
                              SQLSMALLINT DecimalDigits,
                              SQLPOINTER ParameterValuePtr,
                              SQLINTEGER BufferLength,
                              SQLINTEGER * StrLen_or_IndPtr);

SQLRETURN SxsSQLGetData(sxdint StatementHandle,
                        SQLUSMALLINT ColumnNumber,
                        SQLSMALLINT TargetType,
                        SQLPOINTER TargetValue,
                        SQLINTEGER BufferLength,
                        SQLINTEGER *StrLen_or_Ind);

SQLRETURN SxsSQLBindCol(sxdint StatementHandle,
                        SQLUSMALLINT ColumnNumber,
                        SQLSMALLINT TargetType,
                        SQLPOINTER TargetValue,
                        SQLINTEGER BufferLength,
                        SQLINTEGER *StrLen_or_Ind);

SQLRETURN SxsSQLGetDiagField(SQLSMALLINT HandleType,
                             sxdint Handle,
                             SQLSMALLINT RecNumber,
                             SQLSMALLINT DiagIdentifier,
                             SQLPOINTER DiagInfo,
                             SQLSMALLINT BufferLength,
                             SQLSMALLINT *StringLength);

SQLRETURN SxsSQLExecute(sxdint StatementHandle);

SQLRETURN SxsSQLFetch(sxdint StatementHandle);

SQLRETURN SxsSQLCloseCursor(sxdint StatementHandle);
Java:
public int SxsSQLPrepare(int StatementHandle,
                         String StatementText);

public int SxsSQLBindParameter(int StatementHandle,
                               short ParameterNumber,
                               short InputOutputType,
                               short ValueType,
                               short ParameterType,
                               int ColumnSize,
                               short DecimalDigits,
                               byte[] ParameterValuePtr,
                               int BufferLength,
                               IntRef StrLen_or_IndPtr);

public int SxsSQLGetData(int StatementHandle,
                         short ColumnNumber,
                         short TargetType,
                         byte[] TargetValue,
                         int BufferLength,
                         IntRef StrLen_or_IndPtr);

public int SxsSQLBindCol(int StatementHandle,
                         short ColumnNumber,
                         short TargetType,
                         byte[] TargetValue,
                         int BufferLength,
                         IntRef StrLen_or_IndPtr);

public int SxsSQLGetDiagField(short HandleType,
                              int Handle,
                              short RecNumber,
                              short DiagIdentifier,
                              byte[] DiagInfoPtr,
                              short BufferLength,
                              IntRef StringLengthPtr);

public int SxsSQLExecute(int StatementHandle);

public int SxsSQLFetch(int StatementHandle);

public int SxsSQLCloseCursor(int StatementHandle);

Examples

This section shows some examples in the various infrastructures. Error handling has been omitted for the sake of clarity.

Direct
sxdint ConnectHdl = 0;
SQLRETURN sqr = 0;

sqr = m_callback->SxsSQLGetConnect(m_callback->AllocString(L"Meyer"),
                                      m_callback->AllocString(L"secret"),
                                      m_callback->AllocString(L"MySqlDB"),
                                      &Connecthdl);

sxdint StmtHdl = 0;

sqr = m_callback->SxsSQLAllocHandle(SQL_HANDLE_STMT, ConnectHdl, &StmtHdl);
sqr = m_callback->SxsSQLPrepare(StmtHdl,
                                    m_callback->AllocString(L"select * from hotel"),
                                    19);
sqr = m_callback->SxsSQLExecute(StmtHdl);
sqr = m_callback->SxsSQLFetch(StmtHdl);

int ExpectedLength = 1000;
char Result[1000];

sqr = m_callback->SxsSQLGetData(StmtHdl, 1, SQL_C_CHAR,
                                    Result, ExpectedLength, NULL);

// evaluate or copy Result anyway, perform some more calls using StmtHdl ...

sqr = m_callback->SxsSQLFreeHandle(SQL_HANDLE_STMT, StmtHdl);

// ODBC disconnect will be done by Tamino Server
Java
IntRef connectHdl = new IntRef(0);
int sqr = 0;

sqr = SxsSQLGetConnect("MySqlDB", "Meyer", "secret", connectHdl);

IntRef stmtHdl = new IntRef(0);

sqr = SxsSQLAllocHandle(SQL_HANDLE_STMT, connectHdl.getVal(), stmtHdl);

sqr = SxsSQLPrepare(stmtHdl.getVal(), "select * from hotel");
sqr = SxsSQLExecute(stmtHdl.getVal());
sqr = SxsSQLFetch(stmtHdl.getVal());

int bufferLength = 1000;
byte[] resBuffer = new byte[bufferLength];
IntRef resIndicator = new IntRef(0);

sqr = SxsSQLGetData(stmtHdl.getVal(), 1, SQL_C_CHAR, resBuffer,
                        bufferLength, resIndicator);

// evaluate or copy Result anyway, perform some more calls using stmtHdl ...

sqr = SxsSQLFreeHandle(SQL_HANDLE_STMT, stmtHdl.getVal());

// ODBC disconnect will be done by Tamino Server

System Callbacks

System callbacks can be used in all types of server extensions to obtain information about the Tamino Server. The following system callback methods are available:

Callback Method SxsSystem

The following call types are available:

Call Type for Java / Call Type for Direct SysBuf Description
IS_REPLICATION / SX_IS_REPLICATION "YES"/"NO" Flag indicating whether the database is a replication database
JVM_USEROPTIONS / SX_JVM_USEROPTIONS string The server parameter indicating the JVM options in use
USERID / SX_USERID user ID as string  
SESSIONID / SX_SESSIONID session ID as string  
SERVER_READ_ONLY / SX_SERVER_READ_ONLY "YES"/"NO" The server parameter indicating whether the server is in read-only mode
XML_DEF_ENCODING / SX_XML_DEF_ENCODING string The server parameter indicating the XML default encoding (for responses from Tamino)
XML_DEF_TOKENIZER / SX_XML_DEF_TOKENIZER string The server parameter indicating the XML default tokenizer (possible values: "white-space separated", "Japanese")
XNODE_DEF_ENCODING / SX_XNODE_DEF_ENCODING string The server parameter indicating the X-Node default encoding (for external data sources accessed by Tamino)
XTENSION_JAVA_USAGE / SX_XTENSION_JAVA_USAGE "YES"/"NO" The server parameter indicating whether Java server extensions can be used
XTENSION_DIRECT_USAGE / SX_XTENSION_DIRECT_USAGE "YES"/"NO" The server parameter indicating whether Direct server extensions can be used

All call types for the method SxsSystem() of the callback classes CSXSJavaCallback and CSXSDirectCallback are constant enumerations that are inherited from ASXJBase (for Java) or defined in sxenum.h (with prefix SX_, for Direct).

Direct

The following function is available:

sxdint SxsSystem(sxdint callType, sxdstring *ppXMLBuf);

The available call types are defined as constants in the callback interface sxenum.h.

Java

The following method is available:

public int SxsSystem(int callType,
                        StringBuffer pSysBuf);

The call types are defined as constants that are known to the server extension by inheritance from ASXJBase.

Callback Method SxsGetHttpHeaderField

The HTTP header callback function can be used in all types of server extensions to obtain information about the current request's HTTP header. All HTTP header fields specified in the table below can be accessed by this method. String constants, which match the W3C standard HTTP header field name definitions, are defined for these fields. They are available in the language-dependent include files. A non-zero return code is issued if the HTTP header field name cannot be found among the current HTTP header fields. The following string constants are available:

Call String Constants HTTP Header Field (Software AG) Meaning
REQUEST_CLIENT_ADDRESS REMOTE_ADDR The remote IP address of the client's host
REQUEST_DOCUMENT_MEDIATYPE Document-Mime-Type The media type of the document
REQUEST_METHOD REQUEST_METHOD The request method
REQUEST_SERVER_HOST SERVER_HOST The server host name of the HTTP server
REQUEST_STRING QUERY_STRING The request string
REQUEST_URI URI The URI of the request
Call String Constants HTTP Header Field (W3C)
REQUEST_ACCEPTED_CHARSETS Accept-Charset
REQUEST_MEDIATYPE Content-Type
REQUEST_PREFERRED_LANGUAGE Accept-Language

Direct

The following function is available:

sxdint SxsGetHttpHeaderField(sxdstring attrName,
                             sxdstring *ppXMLBuf);

The attrName string is the HTTP header field name. The file sxdinc.h defines constant values for fields in the above tables.

Java

The following method is available:

public int SxsGetHttpHeaderField(String attrName,
                                    StringBuffer pSysBuf);

The attrName string is the HTTP header field name. The constant values for fields in the above tables are known to the server extension by inheritance from ASXJBase.

Callback Method SxsSetProperty

The callback SxsSetProperty allows a value to be set in the Tamino response document. Currently the only value that can be set is the media type.

To set the media type, specify the following parameter:

Parameter property Parameter mediaType Description
SX_PROPERTY_RSP_MEDIATYPE A text string such as "text/xml" representing a media type. This specifies that the media type defined in the response document will be the value given.

For some combinations of media type and server extension return parameter type, Tamino escapes the XML content in the response document according to the standard XML escaping rules ("<" becomes "&lt;" etc.). The rules determining when escaping is used are summarized in the following table:

  Return parameter type is ino:XML-OBJ Return parameter type is xs:string
Media type specifies non-XML text document XML content is escaped XML content is not escaped
Media type specifies XML document XML content is not escaped but the contents must be well-formed XML XML content is escaped

See the section Media Type Requirements in the documentation for X-Machine Programming for a summary of the media type rules used by Tamino.

Notes:

  1. If you set the media type using this callback method, the Tamino response wrapper is suppressed. See also the section Suppressing the Tamino Response Wrapper in the X-Machine Programming Guide for related information.
  2. One of the examples provided with the Tamino distribution kit shows how to construct a document with an arbitrary media type specified in a stylesheet. It is in the directory Examples/Server Extension/Java_Query_XSLT under the Tamino installation directory.

Direct

The following function is available:

sxdint SxsSetProperty(sxdint property,
                      sxdstring value);

Java

The following method is available:

public int SxsSetProperty(int property,
                          String value);

Callback Error Handling

Runtime errors because of callbacks called from server extensions can occur for many reasons. They can result from the communication mechanism between Tamino Server and server extension (a Java error), from the Tamino mechanism for calling server extensions, from the Tamino Server itself (in the case of an XML callback or a system callback), from a database other than a Tamino database, or from the ODBC mechanism (in the case of an ODBC callback). Therefore special error handling is provided for server extension callback functions. Errors produced by callbacks are reported to the calling server extension and can only be evaluated there.

If the callback call is successful, the callback function returns the value 0.

If the return value is non-zero, the following functions can be used to obtain more information:

Direct

sxdint SxsGetMsgNo();

sxdstring SxsGetMsgText();

sxdint SxsGetSqlMsgNo();

sxdint SxsGetInoMsgNo();

Java

int SxsGetMsgNo();

String SxsGetMsgText();

int SxsGetSQLMsgNo();

int SxsGetInoMsgNo();

All Infrastructures

SxsGetMsgNo() always returns a special message code for a server extension callback.

SxsGetMsgText() always returns the corresponding message text.

The messages and codes that can occur are listed in the section Server Extension Messages.

Depending upon the situation, the other callback error functions produce the following results:

Tamino Server Errors (All Infrastructures)

If SxsGetMsgNo() reports a Tamino Server error, an error occurred while processing the XML request in the Tamino Server. SxsGetInoMsgNo() can be used to obtain the Tamino message code. Then the Tamino documentation can be used to find out the reason for the error. Such an error can occur for an XML callback or the system callback. If errors occur in case of an XML callback, SxsXMLGetMessage() should always be called. For the syntax, see the section XML Callbacks. This function returns the content of the "ino:messageline" as it appears in the response document of the Tamino Server.

SQL Errors in ODBC (All Infrastructures)

If SxsGetMsgNo() reports a general SQL error, SxsGetSqlMsgNo() can be used to obtain the return value of the original ODBC function (SQLRETURN). (This value is usually also returned for an ODBC callback.) The ODBC callback function SxsSQLGetDiagField() can be used to retrieve more information from the ODBC driver or foreign database involved. Then the ODBC documentation can be used to find out the reason for the error.

Other Errors (All Infrastructures)

All other messages refer to errors occurring while processing the callback functionality. They have to be interpreted using the messages listed in the section Server Extension Messages.

XML Write Errors (All Infrastructures)

XML callbacks that write to a database [SxsXMLDefine(), SxsXMLProcess(), SxsXMLDelete(), SxsXMLXQuery()] can produce special situations that have to be considered.

If such a callback returns a non-zero value and a subsequent SxsGetInoMsgNo() returns a non-zero error code, then a Tamino Server error has occurred. To ensure database consistency in such cases, the entire server extension call must fail (return non-zero). This causes the enclosing transaction to fail and actions to be rolled back.

In this case, the server extension developer should ensure that the necessary clearing up is done. (It does not make sense to issue more XML callback calls that initiate write operations, because they would be rolled back at the end of the transaction.) Then a server extension exception should be thrown. Its error code and text are returned to the Tamino user in the response document of the current request (see the section Exceptions). If no exception is implemented by the server extension developer, an exception is initiated at the return of the server extension function causing the server extension function and the request to fail containing MessageNo and Text of the original SXGetInoMsgNo(), SXSXMLGetMessage(). The message text of the exception is included in the response document to inform the Tamino user.

Failure of a function and, as a consequence, the failure of the request from which the function was called automatically cause a rollback in the case of an anonymous session. In a user session the user must perform a rollback command explicitly.

Server Extension Messages

The following table shows the error codes [available by calling SxsGetMsgNo()], the error texts [available by calling SxsGetMsgText()] and some explanations:

Error code Direct Error code Java Error text Explanation
SXS_CALLB_NO_MEM_NO - Not enough memory Memory was exhausted during callback call.
SXS_CALLB_INO_ERROR_NO INO_ERROR Tamino Server error when calling a callback A Tamino Server error occurred. Use SxsGetInoMsgNo() to retrieve the message number, then refer to the manual for more information.
SXS_CALLB_SQL_ERROR_NO (ODBC callback only) SQL_CALLB_ERROR (ODBC callback only) SQL error when calling a callback An ODBC error occurred. Use SxsGetSqlMsg() or the return code of the just called ODBC callback function to get the SQLRETURN value, then refer to the ODBC manual for more information.
SXS_CALLB_ILLEGAL_HDL_TYPE_NO (ODBC callback only) ILLEGAL_HANDLE_TYPE (ODBC callback only) Callback used an invalid handle type Wrong use of SxsSQLAllocHandle(). Only statement handles may be allocated in callbacks.
SXS_CALLB_ILLEGAL_SQL_CMD_NO (ODBC callback only) ILLEGAL_SQL_COMMAND (ODBC callback only) Commit or rollback not allowed There was an attempt to perform a commit or rollback. This is not allowed in callbacks.
SXS_CALLB_INVALID_BUFFER_PTR_NO (ODBC callback only) INVALID BUFFER (ODBC callback only) Invalid data buffer pointer An ODBC callback function with a parameter of type StringBuffer (Java) was called, but the passed variable had not been allocated using SxsAlloc() / new StringBuffer.

Examples

Error Handling for an XML Callback Call

Direct

sxdint ret = SxsXMLXql(collection, query, &response);

if (ret)
{
    m_callback->ThrowException(SXS_CALLB_NO_MEM_NO,
                                    m_callback->AllocString(L"xql callback failed"));
}

Java

int ret = SxsXMLXql(collection, query, response);

if (ret != 0) {

    int msgNo = SxsGetMsgNo();                  // identify the callback error

    switch (msgNo) {

        case INO_ERROR:

            StringBuffer msgBuf = new StringBuffer();
            int inoMsgNo = SxsGetInoMsgNo();    // Get the Tamino Server message number
            ret = SxsXMLGetMessage(msgBuf);     // Get the Tamino Server messageline
            SxsException(inoMsgNo, msgBuf);     // Signal exception to the SXS caller
            break;

        default:

            String msg = SxsGetMsgText();       // Get the SXS message corresponding
                                                // to callback error
            SxsException (msgNo, msg);          // Signal exception to the SXS caller

    }
}

Error Handling for an ODBC Callback Call

Java

int ret = SxsSQLExecute(StmtHdl);

if (ret != 0) {

    int msgNo = SxsGetMsgNo();                  // identify the callback error

    switch (msgNo) {

        case INO_ERROR:

            StringBuffer msgBuf = new StringBuffer();
            int inoMsgNo = SxsGetInoMsgNo();    // Get the Tamino Server message number
            ret = SxsXMLGetMessage(msgBuf);     // Get the Tamino Server messageline
            SxsException(inoMsgNo, msgBuf);     // Signal exception to the SXS caller
            break;

        case SQL_CALLB_ERROR:
            int sqlMsgNo = SxsGetSQLMsgNo();    // Get the SQL message number from ODBC
            String msg = SxsGetMsgText();       // Get the SXS message for ODBC error
            SxsException(sqlMsgNo, msg);        // Signal exception to the SXS caller
            break;

        default:
            String msg = SxsGetMsgText();       // Get the SXS message corresponding
                                                // to callback error
            SxsException(msgNo, msg);           // Signal exception to the SXS caller

    }
}

Exceptions

If a server extension function throws an exception, the function call fails and returns with an error to the Tamino Server. The Tamino Server rolls back the current XML transaction and inserts the exception text (error code and error text as far as available) into the response document of the request that called the server extension function.

Direct

Developers can throw their own C++ exceptions. They must be derived from std::exception.

throw MyException ("This is an error");

A pointer to such an exception object can also be thrown:

throw new MyException ("This is an error");

Additionally, the callback method

m_callback->ThrowException (errnr, msg)

can be called.

The following method can be used to generate a warning rather than an exception:

sxdvoid SxsWarning (sxdlong warnNum, sxdstring msg);

Java

Developers can implement their own Java exceptions. These and any standard Java exceptions are handled as described above.

Additionally, the method void SxsException (int errNo, String msg) can be used to signal the caller that an exception occurred in the server extension, but it does not throw a Java exception itself. This ensures that the session is rolled back and that the error number and message appear in the response document, even if the developer does not throw a Java exception or if the corresponding exception is caught later.

The following method can be used to generate a warning rather than an exception:

void SxsWarning (int warnNum, String msg);

All Infrastructures

Note:
Exceptions thrown from event functions do not make sense, because they are only processed when the current request has terminated. They are caught, but they are not shown to the user.

Version Numbers

A two-part version number of the form major.minor is associated with each Tamino server extension. By default, the version number "1.0" is allocated when a server extension is created. You can change the version number at any time during the server extension's lifecycle.

For more information about the relevance of the server extension version number, see Upgrading a Server Extension.

Direct

To change the version number of a Direct server extension, edit a comment in the server extension's header file. Assuming the server extension is called MySXS and its corresponding header file is MySXS.h, you will find a comment in the file MySXS.h of the form:

/**
 * Tamino Server Extension MySXS
 * @version 2.3
 * @author Bob
 */

Edit the comment @version 2.3 as required. The version number is incorporated automatically when this file is processed during compilation to produce the wrapping structures and methods.

Java

To change the version number of a Java server extension, change the constructor of the static field sxsVersion. For example:

static final SXSVersion sxsVersion = new SXSVersion(2, 3); // version now 2.3