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 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).
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.
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.
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.
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.
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");
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.
The information in this section is broken down as follows:
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.
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 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:
open database session
,
close database session
,
commit
and rollback
.
These commands are implicitly handled by the Tamino Server.
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).
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.
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 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(); }
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.
The following section shows some examples in the various infrastructures. Error handling has been omitted for the sake of clarity.
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 ...
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 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.
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 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);
- 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.
- 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);
This section shows some examples in the various infrastructures. Error handling has been omitted for the sake of clarity.
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
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 can be used in all types of server extensions to obtain information about the Tamino Server. The following system callback methods are available:
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).
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.
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.
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 |
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.
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.
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 "<" 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:
The following function is available:
sxdint SxsSetProperty(sxdint property, sxdstring value);
The following method is available:
public int SxsSetProperty(int property, String value);
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:
sxdint SxsGetMsgNo(); sxdstring SxsGetMsgText(); sxdint SxsGetSqlMsgNo(); sxdint SxsGetInoMsgNo();
int SxsGetMsgNo(); String SxsGetMsgText(); int SxsGetSQLMsgNo(); int SxsGetInoMsgNo();
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:
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.
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.
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 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.
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. |
sxdint ret = SxsXMLXql(collection, query, &response); if (ret) { m_callback->ThrowException(SXS_CALLB_NO_MEM_NO, m_callback->AllocString(L"xql callback failed")); }
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 } }
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 } }
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.
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);
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);
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.
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.
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.
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