Sie sind auf Seite 1von 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

5 October 2002

Skipjack Server

Application Development Guide


Skipjack Server is a general-purpose application server that is designed to flexibly support process control applications. Skipjack is based on the public-domain Tomcat Java Application Server developed under the Apache project. Tomcat provides all of the basic HTTP and Servlet processing, including connection and thread management, while Skipjack provides application level services for executing transactions that support one or more applications. This document provides an overview of the Skipjack Server from an Application Developer's perspective, discussing how to define transactions that can be used to support a wide range of application processing tasks. This document assumes that the reader has already installed the Skipjack Server according to the instructions provided in the Installation Guide and is familiar with the operational issues discussed in the Administration Guide.

Table of Contents
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Model-View-Controller Approach Hello World Example Action Processing Database Processing Transaction Response Shell Script Processing Debug Management Error Checking Transaction Security Client Application Support a. Java Client Package b. Perl Client Package c. C++ Client Package 11. Event Listening

1 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

12. 13. 14. 15.

Process Manager Session Management Data Importing HTML Form Macros

2 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 1: Model-View-Controller Approach
The Model-View-Controller (MVC) Approach is a widely-used method for organizing distributed applications that are more easily modified and maintained than previous distributed computing paradigms. In simplest terms, the MVC approach works as follows: One or more data models are created using whatever structure is best suited for the task at hand. Typically, a relational database serves as the primary model, although various models can (and often do) exist in an application at the same time. One or more control tasks are created that can access and manipulate the data models, adhering to the operating rules established by the application requirements. Typically, control tasks are defined by a collection of database server stored procedures, Web-server CGI scripts, Java servlet classes, Enterprise Java Beans, or custom applications, to name just a few. One or more user views are created to allow various types of users to execute the control tasks, providing whatever inputs are required and receiving whatever output is generated. Typically, user-interface views are created using Web-based technology, such as HTML pages, using the HTTP protocol to manage the view-to-controller interaction. Increasingly, programmatic views, such as XML objects, exchanged using the SOAP protocol, are used to access distributed applications. In theory, MVC-based distributed applications can be built with pure components; where each component performs solely in the Model, View or Controller areas. Generally, this is good design goal, since it simplifies application maintainence and increases flexibility, but reality often requires that some application components straddle two of the areas. In the Skipjack Server, the following capabilities are provided in each of the MVC areas: Model The MySQL relational database server is deployed as an integral part of the Skipjack Server, serving as the primary data model. All internal Skipjack Server administration functions use tables in the skipjack database for non-volatile storage. Any database server that supports the Java Data Base Connection (JDBC) standard can be used as a data model, with the server automatically managing all database connections. Furthermore, multiple database servers can be accessed at the same time by any Skipjack Server application. In addition to the relational database, the Skipjack Server supports the use of Memory Tables for application tasks that require fast access to data that is initially loaded from a non-volatile storage location, such as a database table or data file. View

3 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The Skipjack Server uses the HTTP protocol for all view-to-controller interactions, thereby allowing it to support the widest range of applications. As such, the server can accept inputs and generate outputs based on an arbitrary MIME data type. For example, the server can accept inputs using the standard URL-encoded data type and can generate text/html, text/plain, or image/gif formatted outputs, to name just a few. To support such a wide range of output formats, the Skipjack Server uses the Velocity Template Engine as the primary mechanism for formatting output files used to support a user interface view. Velocity supports a small number of easily-learned directives that facilitate formatting tasks, such as generating a tabular display of data or customizing the display for a given user. Since Velocity has a nominal set of logical expressions (such as the if statement) and allows access to Java object methods defined by the application, it could be used for both view and controller purposes. But, in practice, it is more effective to use Velocity solely as a view component whenever possible. In addition to Velocity, the Skipjack Server can use the output of any of transaction response item, operating system executable or custom application code as the output of a transaction. Such an approach is used, for example, to generate a chart image file based on the output of a database query. To facilitate custom application views, Skipjack Client Libraries exist for C++, Java and Perl applications, allowing them to easily interact with one or more Skipjack Servers. The Skipjack Client Library supports an object-based interface to the Skipjack Server, providing a set of method calls that shield the client application developer from all networking and formatting issues. See Client Application Support for more details about the available client libraries. Controller All controller tasks are performed in the Skipjack Server using a collection of transactions that are specified in Transaction Definition Files, which are formatted text files. Transactions typically consist of a collection of input validation, data model processing and output generation steps that result in the desired output file. Skipjack Server transactions are very flexible, require no programming skills, and can be easily modified as an application evolves. Although the Skipjack Server is based on the HTTP protocol, that does not limit it to supporting only browser-based views. In fact, the HTTP protocol is increasingly used to support server-to-server interactions, so-called Web Services. In a Web Services approach, one server sends a request to another server and receives a response. Skipjack Server transactions can be invoked using the HTTP protocol, supplying input parameters as either URL-encoded data (typical for browser-based views) or as XML-encoded objects (typical for Web Services views.)

4 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 2: Hello World Example
Enough theory for now ... let's look at some code. The infamous Hello World application is a good way to see the different capabilities provided by the Skipjack Server. In this section, we demonstrate a number of Skipjack Server features by building a Hello World application in various ways. All of the examples discussed in this section can be found in the following locations: Web URL http://$SKIPJACK_URL/tutorial/helloWorld/ File Path $SKIPJACK_HOME/app/WEB-INF/transaction/tutorial/helloWorld/ where $SKIPJACK_URL is the URL for the Skipjack Server ('localhost:8080' for default installations) and $SKIPJACK_HOME is the root location of the Skipjack Server runtime directory ('/tools/skipjack' for default installations).

Simple Transaction And Template


The simplest Hello World application consists of the following transaction definition file (ex1.tdf):
// // ex1.tdf // include "skipjack-common.tdf" item main extends NOP { templateName = "ex1.vm"; }

and a corresponding template file (ex1.vm):


## ## ex1.vm ## Hello World

The transaction definition file begins with three comment lines that specify the name of the file, followed by the include directive, that causes the item definitions specified in the skipjack-common.tdf file to be included in this transaction. (We'll discuss the common items in detail later.)

5 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Specifically, the NOP item definition (defined in skipjack-common.tdf) is used as the basis for the main item definition for this transaction. (Transaction item definitions can extend other item definitions, thereby inheriting all attribute definitions ... more on that later.) All transactions must define the main action item, which is the starting point for all transaction processing. In this example, since the main action item extends the NOP action, No OPeration is actually performed. After the main has been fully processed, the templateName attribute is used to determine the Velocity template file that will be used to generate the output for the transaction, which in this case is the ex1.vm template file. At that point, Velocity is used to merge the contents of the template file with the current context (as it is called by Velocity), and the resulting file is used as the transaction response. In this example, the ex1.vm template file consists of three initial comment lines (stripped out automatically by Velocity) and a single output line consisting of the words Hello World. When executed from a browser using the following url:
http://$SKIPJACK_URL/tutorial/helloWorld/ex1.tdf

the following output will be seen:


Hello World

It is important to note that even though this example is very simple, it demonstrates a pure Model-View-Controller application layout. In this case, the items defined in ex1.tdf represent the Controller, the formatting defined in ex1.vm represents the View, and no Model is needed.

Velocity Variable Substitution


We can extend the simple Hello World application to display any greeting by using the variable substitution features provided by Velocity. In particular, we can modify the template file as follows (ex2.vm):
## ## ex2.vm ## <body bgcolor=white> <h1 align=center>Hello $input.who</h1>

which allows us to change the specific object/person to be greeted while retaining a uniform HTML format (e.g. white background, centered text, etc.)

6 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

In order to make use of this template, we need to supply a proper value for the $input.who context variable, when Velocity is called. That is, the transaction definition needs to specify a value for $input.who during its processing phase, before calling the Velocity template engine during the response generation phase. The simplest way to specify a value for $input.who is to define it explicity in the transaction definition file as follows (ex2.tdf):
// // ex2.tdf // include "skipjack-common.tdf" item input { who = "World"; } item main extends NOP { templateName = "ex2.vm"; }

where the input item definition has been added, with the who attribute being assigned a value of "World". In fact, any item attribute defined in the transaction file can be accessed by the Velocity template using the syntax $item.attr where item is the item name and attr is the attribute name. For example, the following transaction definition file and corresponding template file allows the background color and font type to be specified in the transaction file instead of being hardcoded in the template file:
// // ex3.tdf // include "skipjack-common.tdf" item input { who = "Fred"; } item myPage { bgColor = "yellow"; font = "h2"; } item main extends NOP { templateName = "ex3.vm"; }

## ## ex3.vm ## <body bgcolor=$myPage.bgColor> <$myPage.font align=center> Hello $input.who </$myPage.font>

7 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

There is nothing magic about the item names input, myPage, or even main with regards to Velocity variable substitution: any item attribute defined in the transaction definition file can be referenced in the Velocity template file used to generate the response for that transaction. The main item must always before defined for transaction processing purposes, even though it may not be referenced for Velocity processing purposes.) By judiciously using variables in Velocity templates that are defined in the transaction definition file, an application author can develop templates that can be used by a wider range of transactions. This directly supports the MVC approach, keeping the view (e.g., template format) separate from the underlying data model (e.g., item definitions). If you mis-type a variable name in a Velocity template or the corresponding attribute is not defined in the transaction definition file, then Velocity will not replace the variable at all and the variable notation will appear in the output file. Finally, it is important to note that Velocity provides a set of directives that allow variables to be defined and manipulated in the template file itself, including macro definition and expansion. A full explanation of such features will not be addressed here, although we will show some more complex Velocity examples where appropriate. Visit the Velocity Home Page (http://jakarta.apache.org/velocity) for complete documentation on all Velocity capabilities. When reading those documents with regard to Skipjack Server, simply remember that all of the items and attributes defined in a transaction definition file serve as the context in which the Velocity template is processed.

Attribute Expressions
Attribute values can be defined in a transaction definition file using simple assignment statements, as seen in the previous examples, or more complex Java-like expressions. For example, the following item definition:
item myPage { greeting = "Hello"; who = "World"; message = greeting + " " + who; }

results in a value of "Hello World" for the myPage.message attribute. In this case, the '+' operator is used to concatenate the values of the greeting and who attributes, with a space in between. No leading '$' notation is used to denote an attribute name in an attribute expression, as is required in a Velocity template.)

8 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

If you need to access an attribute from another item, then simply prepend the attribute name with the name of the item, as in the following example:
item input { who = "World"; } item myPage { greeting = "Hello"; message = greeting + " " + input.who; }

which references the who attribute from the input item while determining the value of the myPage.message attribute. The following operators (derived from C, Java, Perl, SQL, etc) are supported for attribute expressions: Operator +, -, *, / =, +=, -=, *=, /= <, >, <=, >=, !=, == =~, !~ ?: !, &&, || in, contains func(x,y,z) Meaning Arithmetic Assignment Comparison Regular Expression Match Conditional Unary Negation Boolean Comparison Membership Function Call

object->method(x,y,z) Object Method Call ; End of Expression

In addition to these operators, a list of values can be specified by surrounding them with the '[' and ']' symbols and separating each list value by a comma. For example, the following attribute expression defines a list of colors:
colorMap = ["red", "white", "blue"];

The various conditional operators, including the Comparison, Boolean Comparison, Regular Expression, and Membership operators, can be used in

9 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

conjunction with the ternary conditional operator '?:' to selectively assign a value to any attribute. For example, the following item definition:
item myPage { bgColor = (input.who == "Fred") ? "yellow" : "red"; }

defines the background color based on the current value of the input.who attribute. See TDF Operators for a complete description of all attribute expression operators and examples that make use of them. Attribute expressions can invoke a function with a variable set of input values and make use of the value returned in subsequent expression evaluation. For example, the following item definition:
item myPage { colorMap = ["red", "white", "blue"]; bgColor = element (colorMap, 1); }

extracts the second value "white" (zero-based indexing) from the colorMap attribute and assigns it to the bgColor attribute. See TDF Functions for a complete description of all currently supported functions and instructions for creating and installing new functions as needed. In some cases it is necessary to use the extensive power of Java objects and the Java runtime library to effectively determine the value of an attribute expression. Accordingly, attribute expressions can invoke arbitrary object and class methods, much like a function call. For example, the following item definition:
item myPage { colorMap = ["red", "white", "blue"]; colorIndex = integer(3 * class("java.lang.Math")->random()); bgColor = element(colorMap, colorIndex); }

will result in the background color being selected randomly from the colorMap list of colors, as can be seen by executing the ex4.tdf transaction. In this case, the class() function is used to access the "java.lang.Math" class and the -> operator is used to invoke the random() static class method to generate a random decimal number between 0 and 1. Then, the integer() function is used to convert the decimal number to an integer, so that it can be used by the element() function to extract the desired color from the colorMap list. See TDF Method Calls for a discussion of object and class method invocation in attribute expressions.

Input Parameters
It most cases it is beneficial to replace hard-coded variables in a Velocity template, with references to item attributes in the transaction definition

10 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

file. Similarly, it is usually beneficial to replace or overwrite hard-coded item attribute values with values that are provided by either the user or client application. That is, we want to allow the user or client to specify the input parameters for the transaction. Since Skipjack uses the HTTP protocol to invoke transactions, it is very easy for users to enter input parameters from a browser, simply by appending each parameter to the transaction URL as follows:
http://$SKIPJACK_URL/tutorial/helloWorld/ex4.tdf?who=Sally

which specifies the value "Sally" for the who input parameter. When the ex4.tdf transaction is executed by the Skipjack Server, it will automatically store any HTTP input parameter as a String attribute value in the input item, overwriting any similarly named attribute value that was defined in the TDF file itself. In this example, since the ex4.tdf transaction was defined as follows:
// // ex4.tdf // include "skipjack-common.tdf" item input { who = "World"; } item myPage { colorMap colorIndex bgColor font } = = = = ["red", "white", "blue"]; integer(3 * class("java.lang.Math")->random()); element(colorMap, colorIndex); "h2";

item main extends NOP { templateName = "ex3.vm"; }

then the value "World" will be overwritten by the value "Sally" when the transaction is executed. In this way, transaction authors can specify hard-coded default values for all input parameters, allowing users or client applications to selectively overwrite any or all of them. All input parameter encoding must adhere to the standard HTTP encoding scheme in order to be properly processed when executing transactions from a browser or client application. In general, since the input item is used to automatically store all input parameters for a transaction, it shouldn't be used to store other internal attributes that may be needed to perform certain actions. Any appropriate HTML form can also be used to submit input parameters to a transaction. The Skipjack Server supports both the GET and POST

11 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

methods commonly used when submitting an HTML form from a browser.

Input Validation
Any time a user or client application is allowed to submit input parameters, it is generally prudent to perform some type of syntax and/or semantic validation on those inputs. To that end, the inputSchema item can be defined for a transaction that specifies the name, type and mode of each input parameter supported by that transaction. For example, consider the following transaction definition (ex5.tdf):
// // ex5.tdf // include "skipjack-common.tdf" schema inputSchema extends BaseSchema { attrs = [ ["who", "string", "default", "World"], ["fontSize", "integer", "default", 2], ["bgColor", colorMap, "default", "white"] ]; colorMap = ["red", "white", "blue"]; } item myPage { bgColor font } = input.bgColor; = "h" + input.fontSize;

item main extends NOP { templateName = "ex3.vm"; }

By default, if no parameters are given, then this transaction produces a result similar to the previous examples, printing "Hello World" on a white background. However, this transaction also allows the user or client application to define the who, fontSize and bgColor input parameters to control the type of output that is generated. All aspects concerning the supported input parameters are defined in the inputSchema item, which we will now explain in detail.

Schema Attribute Definitions


It is important to note that the inputSchema item is defined as a schema item, not a generic item. This tells the Skipjack Server to process the attrs attribute, which should be defined as a list of lists, where each list entry defines an input parameter for the transaction. Other attributes may also be defined in the inputSchema to make parameter definitions easier to understand (such as the colorMap attribute which will be explained shortly). Each entry in the attrs list should be formatted as follows:
["name", "type", "nonempty | default | optional", "default value"]

12 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

where "name" is the parameter name and "type" is the parameter type. (See Schema Class for a list of all parameter types supported.) The third element indicates if the parameter must be specified (ie. "nonempty") or is optional. If "default" is specified, then the "default value" will be used automatically if the user or client application doesn't specify a value for that parameter. If "optional" is specified, then no value is specified automatically. (The "optional" setting is used primarily for documentation purposes as will be discussed later.) In the example above, the first input parameter is defined with the name "who" and a type of "string". That is, the who input parameter can consist of an arbitrary string for which no syntax checking will be performed. Since the who parameter is marked as a "default" parameter, it will be assigned the value of "World" if it is not otherwise defined by the user or client application. The fontSize input parameter is defined as an "integer" value, which means that a syntax check will be performed automatically before the transaction is executed and that the value will be converted to a Java Long object after successful validation. Finally, the bgColor input parameter type is a reference to the colorMap attribute, which itself is defined as a list of values. Any time that a list of values is specified as the input parameter type (either as an embedded list in the parameter definition tuple or a reference to a list value attribute), then the input parameter value must be contained in that list to be valid. Based on the inputSchema definition, all of the following transaction URLs are valid:
ex5.tdf ex5.tdf?who=Sally ex5.tdf?bgColor=red ex5.tdf?who=Sally&bgColor=blue&fontSize=1 ex5.tdf?ignore=this

and all of the following URLs will result in an error message being generated:
ex5.tdf?bgColor=green ex5.tdf?fontSize=not-a-number

Attribute Storage Format


A Storage Format Expression can be specified for each attribute defined in the attrs table, which can be used to convert a validated attribute input value before storing it in the input item. This can be used to perform routine conversion, such as trimming white space from around a String value or ensuring that a value falls within a given range, just to name a few examples. Storage format expressions are specified by defining the fooFormat schema attribute, where foo is the name of the attribute being converted. The storage format expression may reference the _srcItem schema attribute to access the item currently being validated. The storage format expression may also reference any other schema or item attributes as needed to perform its task. That is, any valid TDF expression can be specified as the format expression.

13 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

For example, the following format expression could be used to ensure that the fontSize parameter is not greater than 32:
fontSizeFormat = _srcItem.fontSize < 32 ? _srcItem.fontSize : 32;

Non-Validated Input Attributes


Input parameters that are not defined by the inputSchema are simply ignored for validation purposes. This allows transaction authors to perform more complex parameter validation for some parameters, while using the easily specified inputSchema for other parameters.

Input/Output Separation
Note how the myPage item attributes have been re-defined in terms of the input item attributes so that they can be referenced by the same Velocity template as before. In general, it is prudent to create separate items like myPage that are used to specify formatting or data values referenced within a Velocity template file, even if they need to trivially reference values from other items, like the input.bgColor reference. By defining a separate item, the transaction author is clearly differentiating between the transaction input parameters and the attribute values required by the template being used. Essentially, the myPage item defines the "inputs" specifically used by the template. This allows templates to be easily used across a number of transactions simply by defining the myPage item (or any name of your choosing) in each such transaction, specifying the attribute value mappings appropriate for that transaction. For example, some transactions may pass the values through from the input item, like the example above, while others hard-code myPage values or extract them from the database. (Later, we will discuss how the TDF "include" and "overrides" directives can be used to create a single item that is shared across all such transactions, requiring only individual attributes to be overwritten.)

Default Input Form


Given that the inputSchema item defines all of the input parameters supported by a given transaction, it is possible to generate input forms for any transaction. In fact, the Skipjack Server includes a feature that automatically generates an input form for any transaction for which an inputSchema is defined. The input form displays a field for input parameters, indicates which inputs are required and displays the default value for an input field if specified. For input parameters defined by enumerated lists, the input form displays a set of radio buttons or a choice list (depending on the number of items in the list). A default transaction input form can be generated by replacing the normal .tdf transaction suffix by the .form suffix. For example, the following URL:
http://$SKIPJACK_URL/tutorial/helloWorld/ex5.form

14 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

which will result in the following form being displayed:

The default form displays the transaction name, the input fields, and a set of buttons to submit, reset or cancel the transaction. The default form is based on a collection of Velocity macros that are deployed as part of the standard Skipjack components and there are a number of attributes that can be specified to alter the appearance of the form and individual fields. See HTML Form Macros for more details. Clearly, the default input form is no substitute for a well-designed HTML-based user interface, where form fields and buttons are properly placed to reduce screen clutter and make it easier for the user to enter critical information. Nonetheless, when developing and/or trouble-shooting transactions and applications, the default form provides a very convenient mechanism for executing any transaction.

15 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 3: Action Processing
The Hello World examples demonstrate how input parameters, item attributes and Velocity templates can be combined into a simple transaction. Notably, however, none of the Hello World examples actually performed any actions (they all extended the NOP action), nor did they make use of any data store. In this section, we discuss how transactions can be defined using a collection of action items, each of which performs one of the steps required by the transaction, such as retrieving data from a database or memory table. The primary mechanism for performing tasks within a transaction is to extend one or more action items and then execute them as part of the main action item. Action classes (e.g., the Java code used to implement an action item) are relatively easy to implement and can be installed in the Skipjack Server simply by placing the Java class file in the appropriate directory. See TDF Actions for a complete list of actions that are available, including descriptions of the attributes that are supported for each action item. Action items exist to perform a wide range of functions, serving as the interface between the transaction definition file and custom Java code. This separation means that transaction authors do not need to have any Java programming experience to effectively develop a wide range of transactions. If a person can read and understand the description for a given action item, then they can easily make use of such action items in their transaction definitions. The most common way to use an action item is to extend the item defined in the skipjack-common.tdf, thereby assigning it a new name in the current transaction file. Then, appropriate action item attribute values can be defined in the extended item for the task at hand. For example, the CopyAction is very simple action that copies all of the attributes defined in the source item defined by the _srcItem attribute to the destination item defined by the _destItem attribute. So, if you wanted to copy all input parameters to the output item, the following item definition would suffice:
include "skipjack-common.tdf" item copyInputToOutput extends CopyAction { _srcItem = "input"; _destItem = "output"; }

Note, we need to include the skipjack-common.tdf file before extending the CopyAction item, because it is defined in that file. After defining the copyInputToOutput action, we only need to "execute" it as part of the main action. In the Hello World examples, the main item extended the NOP action, which doesn't do anything. Therefore, if we want to execute the copyInputToOutput action, we need to extend a different action. Generally, the main item extends the BaseAction as in the following definition:

16 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

item main extends BaseAction { actions = ["copyInputToOutput"]; templateName = "output.vm"; }

The BaseAction executes all of the action items listed by the actions attribute, which in this case is only the copyInputToOutput action. Actions are executed sequentially by the BaseAction until all actions are done or an exception is thrown. If all actions complete successfully, then the
main.templateName

attribute is used to determine which Velocity template to use to generate the transaction response. In this case, we can assume that the "output.vm" template references the output item attributes to format an appropriate response. (Otherwise, why else did we copy them there?) In simplest terms, actions embody the essential Unix concept of using pipelines of small, flexible, building blocks to perform complex functions. Over time, evolution yields a powerful set of actions that can handle most application needs with little additional programming. Transaction definition files simply define what actions are required and what inputs to provide to them, while the actions actually perform the work. As in many tutorials, we have a "chicken-and-egg" problem in that we need to discuss action processing before we can describe the actual actions themselves. So, for the remaining examples in the section, all of the actions referenced are "abstract actions" (ie. they don't really exist.) In subsequent sections, we will discuss the real actions provided by Skipjack for various processing tasks.

Undo Actions
If an error occurs while processing any of the action items referenced by the actions attribute, then all subsequent actions defined in that list will be automatically ignored. In such cases, if the undoActions attribute references one or more actions, then each of those actions will be processed sequentially. Undo actions can be used to restore partially completed changes, execute custom error processing, record custom debug information or perform any task that is required to compensate or handle the original action error. For example, the following action item attempts to insert records into two different tables:
item insertRecords extends BaseAction { actions = ["insertOne", "insertTwo"]; undoActions = ["deleteOne", "deleteTwo"]; }

If either insert action fails, then the undo action is called to remove both records. If one of the undo actions fail, then the remaining undo actions are ignored and the original exception is used to generate the transaction status and error message.

17 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The actions referenced by the "undoActions" attribute don't necessarily have to "undo" anything, they can be used, for example, to simply log a problem or inform an operator about something that needs to be examined. Prior to executing any undo actions, the tx.errorMsg, tx.errorClass and tx.errorAction attributes will be assigned values that can be used by any of the undo actions to determine what failed in the action list. The tx.errorMsg and tx.errorClass attributes will contain the message and class name of the Java exception that was generated by the action that failed, while the tx.errorAction attribute will reference the Java Item object for the action that failed. For example, the following undo action generates a message based on the name of the action that failed and the error message generated by that action:
item genMessage extends BaseAction { msg = "Action " + tx.errorAction->getName() + " Failed With The Message '" + tx.errorMsg + "'"; }

In addition to the transaction attributes described above, undo actions may also be able to use the tx.status attribute to determine the appropriate processing to be performed. The tx.status attribute is defined by most, but not all, actions when they throw an exception.

Done Actions
Regardless of the success or failure of the actions referenced by both the actions and undoActions attributes, one or more actions can be specified by the doneActions attribue that are executed after the other actions. Generally, such actions are used to release resources or record processing information despite failures. Done actions can be used with or without undo actions, depending on the current task to be performed. For example, the following action locks a table before inserting two records and then unlocks the table:
item insertRecords extends BaseAction { actions = ["lockTable", "insertOne", "insertTwo"]; undoActions = ["deleteOne", "deleteTwo"]; doneActions = ["unlockTable"]; }

The table lock is released by an action specified in the doneActions attribute to ensure that the table is unlocked regardless of the outcome of the insert and/or delete actions.

18 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

As with the actions and undoActions attributes, all of the actions listed by the doneActions attribute are processed sequentially. If an error is generated by one of the doneActions then all remaining actions will be ignored. If no error was previously generated by one of the actions defined by the actions attribute, then the error generated by the action in the doneActions list will be used as the error result for the overall action, causing the transaction to be aborted in normal operation. Developers familiar with the Java "try-catch-finally" language construct may note the similarity between that construct and the actions, undoActions and doneActions attributes. Although the specific semantics are slightly different, the overall concepts are the same.

Action Locks
In any multi-threaded server such as Skipjack, certain types of concurrent processing tasks may result in inconsistent behaviors, depending on the order in which they are performed or other types of race conditions. In order to help eliminate such problems, Skipjack allows transaction authors to allocate one or more resource locks to any action. Once allocated, a resource lock prevents all other actions from accessing the same lock until it is released by the original action. Resource locks are allocated simply by listing the name of each lock required and are automatically released when the action has been completed. Resource locks remain allocated for all sub-actions performed by a given action. The following attributes can be defined for any action to specify which resource locks are needed and how to handle any locking errors: Attribute
_locks

Description Optional list of resource lock names that must be acquired before action processing begins. This can be used to prevent other actions or transactions from interfering with the processing of the current action. Lock acquisition is attempted after any background thread is created (see Background Actions below for details), but before any preCondition check that may be specified (see Action Pre-Conditions below for details). All resource locks acquired by the current action will be automatically released after all action processing is complete, including any exception processing. Optional timeout (in milliseconds) to be used when attempting to acquire one or more resource locks as specified by the _locks attribute. If any of the locks cannot be acquired in the specified time period, then an exception will be thrown and the action will be aborted, releasing any locks that were actually acquired. If a zero or negative value is defined, then no timeout will occur. The default value is 60 seconds. Optional error message to be used if the _lockTimeout expires. Prior to accessing this attribute, the values of the _lockTimeoutLock, _lockTimeoutThread and _lockTimeoutAction attributes will be assigned the name of the lock that caused the timeout, as well as the name of the thread and action that currently holds that lock. These attributes can be used to generate a custom timeout message and/or to check for deadlock conditions. Optional error status to be used if the _lockTimeout expires.

_lockTimeout

_lockTimeoutMsg

_lockTimeoutStatus

19 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

For example, the following action definition requires the Device12 and ChangeStatus resource locks to be allocated before the configDevice and resetDevice actions are executed. If either of the locks cannot be allocated within 10 seconds, then a custom error message is generated.
item doWork extends BaseAction { _locks = ["Device12", "ChangeStatus"]; _lockTimeout = 10000; _lockTimeoutMsg = "Unable To Get Lock " + _lockTimeoutLock + " Because It Is Currently Owned By " + _lockTimeoutAction; actions } = ["configDevice", "resetDevice"];

Action Errors
In normal operation, if any action generates an error then all subsequent action processing is aborted and an unsuccessful transaction response is generated. This is done to prevent non-deterministic side-effects from subsequent actions that may depend on the outcome of the failed action and to make it easier for transaction authors to trouble-shoot transaction failures. In some situations, however, it may be necessary or desirable to ignore any error generated by a given action. For example, an action may attempt to update a record that may or may not exist. In such cases, a transaction author may override the normal error processing behavior for that action by setting the _ignoreError attribute to true. When set to true, any error generated by that action will be ignored and transaction processing will continue with the next action to be processed. When the error is ignored, the current values of the tx.status and tx.errorMsg attributes will be copied into the tx.ignoredStatus and tx.ignoredErrorMsg attributes, respectively, for subsequent use by the transaction. Then, the tx.status and tx.errorMsg attributes will be reset to the values that were set just prior to the action being processed. If the _ignoreError attribute is used for an action that is inside of a loop, the transaction author is responsible for clearing the tx.ignoredStatus and tx.ignoredErrorMsg attributes as needed. The _ignoreError attribute does not affect the way that errors are handled while processing the actions, undoActions, and doneActions lists, only the way the overall action error is handled by the transaction. If a transaction author wants to ensure that a list of actions are performed regardless of errors generated by any of those actions, then the _ignoreError attribute should be set to true in each of those actions, not in the action that defined the list of actions. For example, the following action defines the same behavior as in the previous example, but uses the _ignoreError attribute to continue transaction processing regardless of any error generated by this action:
item insertRecords extends BaseAction {

20 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

_ignoreError = true; actions undoActions doneActions } = ["lockTable", "insertOne", "insertTwo"]; = ["deleteOne", "deleteTwo"]; = ["unlockTable"];

Alternatively, the following action attempts to delete two records, ignoring errors generated by either action:
item deleteRecords extends BaseAction { actions = ["lockTable", "deleteOne", "deleteTwo", "unlockTable"]; } item deleteOne extends MyDeleteAction { _ignoreError = true; .... } item deleteTwo extends MyDeleteAction { _ignoreError = true; .... }

In this example, the _ignoreError attributes of the underlying delete actions are set to true, causing any errors generated by those actions to be ignored. Consequently, the actions performed by the higher level deleteRecords action can be specified solely within the actions list, since the delete actions can not cause the list processing to be aborted.

Action Pre-Conditions
There are times when an action should be executed only if a certain pre-condition is true. All Skipjack actions support this feature through the use of the preCondition boolean attribute. Specifically, if the preCondition expression evaluates to "true", then the action will be executed. Otherwise, the action will not be executed and the transaction will continue processing the next action, if any exists. For example, suppose in the previous example that we want to delete the second record only if the input parameter RecordCount is greater than one. That could be specified using the following preCondition expression:
item deleteRecords extends BaseAction { actions = ["lockTable", "deleteOne", "deleteTwo", "unlockTable"]; } item deleteTwo extends MyDeleteAction { preCondition = integer(input.RecordCount) > 1; .... }

21 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Alternatively, if the records should only be deleted if the RecordCount is greater than zero, then we could add a preCondition expression to the top-level action as follows:
item deleteRecords extends BaseAction { preCondition = integer(input.RecordCount) > 0; actions = ["lockTable", "deleteOne", "deleteTwo", "unlockTable"]; } item deleteTwo extends MyDeleteAction { preCondition = integer(input.RecordCount) > 1; .... }

In this case, the deleteRecords.preCondition expression determines if any of the sub-actions should be performed, while the deleteTwo.preCondition expression determines if the deleteTwo sub-action should be executed.

Action Argument Lists


All of the examples discussed so far have shown action lists that consist of one or more action names. For each action specified, the action item is processed using the current value of all attributes defined in that action. This generally leads to well-structured and well-understood transaction definition files, since each action item is relatively self-contained. However, there are situations where the requirement to define all action attributes in the action item itself becomes onerous. For example, consider the following transaction that needs to log three different debug messages while the transaction is being processed:
item logMsg extends Severity = LogFile = Message = } LogAction { "INFO"; "navius.skipjack.errorlog"; "Unknown";

item logMsg1 extends logMsg { Message = "Transaction Started"; } item logMsg2 extends logMsg { Message = "Transaction Still Running"; } item logMsg3 extends logMsg { Message = "Transaction Completed"; } item main extends BaseAction { actions = [ "logMsg1", ..., "logMsg2",

22 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

..., "logMsg3" ]; }

In this case, an action item must be created for each message, with the Message attribute being overwritten in each case. Although item inheritance makes this a relatively straight-forward process, it still requires the author to invent unique names for each item and it otherwise clutters up the transaction definition file. To alleviate such problems and to allow action items to be easily re-used, actions can be invoked using an action argument list, An action argument list consists of a Vector of values, where the first value is interpreted as the action name, followed by one or more (attribute, value) pairs. For each pair of values specified, the action item attribute will be temporarily overwritten with the value given for the duration of the action execution. After the action processing has been completed, the overwritten attribute values will be restored. Essentially, this allows actions to be executed as "subroutines" or "methods" with certain values supplied as "input" parameters. For example, the previous example could be re-written as follows using action arguments:
item logMsg extends Severity = LogFile = Message = } LogAction { "INFO"; "navius.skipjack.errorlog"; "Unknown"; { "Message", "Transaction Started"), "Message", "Transaction Still Running"), "Message", "Transaction Completed")

item main extends BaseAction actions = [ ("logMsg", ..., ("logMsg", ..., ("logMsg", ]; }

In this case, the logMsg action itself is invoked three times, overwriting the Message attribute of that action item every time. Any Vector value specified in an action list will be interpreted as an action argument list, using the first element as the action name and all subsequent pairs of elements as the (attribute, value) pairs. Any number of attribute value pairs can be specified when executing an action, provided that the attributes already exist in the action item. For example, the Severity attribue may be overwritten for the second message using the following definition:
item logMsg extends Severity = LogFile = Message = LogAction { "INFO"; "navius.skipjack.errorlog"; "Unknown";

23 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

} item main extends BaseAction { actions = [ ("logMsg", "Message", "Transaction Started"), ..., ("logMsg", "Severity", "DEBUG", "Message", "Transaction Still Running"), ..., ("logMsg", "Message", "Transaction Completed") ]; }

Since all of the logMsg attributes are automatically restored after being invoked by each action argument list, the third message will still be assigned a Severity level of "INFO", which is the value defined for that attribute in the logMsg action item. Action items that have their _readonly attribute set to "true" cannot by invoked using an action argument list. Furthermore, all of the attribute names specified in the action argument list must already exist in the action item and an attribute value must be specified for each attribute name given (ie. the argument list must have an odd number of entries). If any of these conditions fails, an appropriate error will be generated.

Background Actions
In most transactions, all of the actions defined in the main.actions are sequentially executed to completion before the transaction response is generated. However, there are times when it is desirable to execute one or more actions in independent threads, thereby allowing them to be processed concurrently while the rest of the transaction is being processed or well after the transaction has generated its response. The Skipjack Server supports such a processing style through the use of background actions, which can be configured using the following collection of attributes that are supported for all actions: Attribute
_bgAction

Description Optional boolean value that indicates if the action should be processed as a background thread. If true, a background thread is created, the action is processed by that thread and the transaction continues processing all subsequent actions. The Process ID for the background thread is stored as the value of the _bgProcessID attribute of the destination item for this action, which can be

24 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

used to manage the process using the ProcessAction action.


_bgErrorLog

By default, any exception thrown by a background action will be printed to the navius.skipjack.errorlog. If this attribute is defined, it specifies the name of the log file to be used. By default, the status of the background process will be automatically updated as it proceeds. If this attribute is set to false, then no status updates will be performed. In either case, transactions can use ProcessAction to update the process status as needed, given the _bgProcessID attribute value. Optional string value that will be assigned as the name of the background thread in the process table. If this attribute is not defined, the action identifier will be used. Specifies how action processing should be triggered, including types 'REPEAT' or 'ALARM'. If 'REPEAT' is specified, the action will be processed one or more times depending on the _bgRepeatCount attribute, with an optional delay between each processing cycle, as specified by the _bgRepeatDelay attribute. If 'ALARM' is specified, the action will be processed for each chronological alarm specified by the _bgAlarm* attributes. The default value is 'REPEAT'.

_bgAutoStatus

_bgProcessName

_bgTrigger

_bgRepeatCount

Specifies the number of times that the action should be executed when _bgTrigger is 'REPEAT', with a default value of 1. If a negative or zero value is specified, then the action will be repeated until the background action process is stopped via the Process Manager. Prior to each execution of the action, the _bgCount attribute of the action's destination item will be set to the current iteration count (if the destination item is writable). The iteration count starts with 1 and automatically rolls over after Integer.MAX_VALUE is reached.

_bgRepeatDelay

Specifies an optional sleep time (in seconds) between repeated action executions. If the value is less than or equal to zero, no delay will be inserted between action executions. The default value is 2.

25 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

_bgAlarmDays

An optional Vector of integers from 1 to 31 that designates each day of the month that an action should be executed when 'ALARM' is specified for the _bgTrigger attribute. If this attribute is not defined or the Vector is empty, then the action will be executed every day of the month. This attribute should not be specified if the _bgAlarmWeekdays attribute is specified.

_bgAlarmWeekdays

An optional Vector of integers from 1 to 7 (1=Sunday, 2=Monday, ...) that designates each day of the week that an action should be executed when 'ALARM' is specified for the _bgTrigger attribute. If this attribute is not defined or the Vector is empty, then the action will be executed every day of the week. This attribute should not be specified if the _bgAlarmDays attribute is specified.

_bgAlarmHours

An optional Vector of integers from 0 to 23 that designates each hour of the day that an action should be executed when 'ALARM' is specified for the _bgTrigger attribute. If this attribute is not defined or the Vector is empty, then the action will be executed every hour of the day. An optional Vector of integers from 0 to 59 that designates each minute of the hour that an action should be executed when 'ALARM' is specified for the _bgTrigger attribute. If this attribute is not defined or the Vector is empty, then the action will be executed every minute of the hour.

_bgAlarmMinutes

One-Time Actions
By default, if the _bgAction attribute is set to 'true', then the current action will be processed once as a background action. As soon as the background action is launched, the transaction will continue processing any subsequent actions and/or will generate the transaction response. Such an approach is commonly used for actions that may require a significant amount of time to complete and the transaction author does not want the client to wait until it is done. Any type of action can be executed as a background action. For example, the following action item definitions results in a background action that simply appends a message to the error log (using the LogAction):
item myBackgroundAction extends BaseAction { _bgAction = true; actions = ["logMsg"]; } item logMsg extends LogAction {

26 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Severity LogFile Message }

= "INFO"; = "navius.skipjack.errorlog"; = "Background Processing Performed";

After myBackgroundAction has been processed, the background will be terminated.

Repetitive Actions
Background actions can be repeated 2 or more times, by specifying the _bgRepeatCount attribute, or indefinitely by setting that attribute to zero or a negative value. A delay (in seconds) between each action execution can be specified using the _bgRepeatDelay attribute. For example, the following modification to the previous example results in myBackgroundAction being executed a total of 20 times, with a 5 second delay in between each execution:
item myBackgroundAction extends BaseAction { _bgAction = true; _bgRepeatCount = 20; _bgRepeatDelay = 5; actions = ["logMsg"]; } item logMsg extends Severity = LogFile = Message = } LogAction { "INFO"; "navius.skipjack.errorlog"; "Background Processing Performed";

Such an approach might be used for delivering information to an external system, attempting delivery only a certain number of times before eventually giving up, as in the following example:
item myDeliveryAction extends BaseAction { _bgAction = true; _bgRepeatCount = 3; _bgRepeatDelay = 60; doneFlag preCondition actions } item doDelivery extends DeliveryAction { _formatType = "FILE"; fileInputFile = "/tmp/myData.txt"; _transportType ftpOutputHost ftpOutputUsername ftpOutputPassword ftpOutputFile } = "FTP"; = "somewhere.com"; = "somebody"; = "easy to guess"; = "remoteFile.txt"; = false; = !doneFlag; = ["doDelivery", "setDoneFlag"];

27 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

item setDoneFlag extends ComputeAction { _destItem = "myDeliveryAction"; doneFlag = true; }

Notice how the preCondition attribute of the myDeliveryAction action is used to abort subsequent action processing after the setDoneFlag action has been executed, which can only happen if the doDelivery is successfully executed. In this example, even if the doDelivery is successful the first time, the myDeliveryAction will be repeated two more times over the next two minutes. However, it won't actually do any processing because the preCondition will be false.

Periodic Actions
Background actions can be performed on a periodic basis (e.g., hourly, daily, weekly, etc.) by setting the _bgTrigger attribute to 'ALARM' and by specifying one or more alarm times using the _bgAlarm* attributes. The action will be performed once for every time specified and will be repeated indefinitely until the action is stopped by the Process Manager (see below for details). For example, the following background item definition causes the logMsg action from the previous example to be executed every quarter hour:
item myPeriodicAction extends BaseAction { _bgAction = true; _bgTrigger = "ALARM"; _bgAlarmMinutes = [00, 15, 30, 45]; actions = ["logMsg"]; }

If such action processing is only desired during normal business hours (9am-5pm), then the _bgAlarmHours attribute can be specified as in the following example:
item myPeriodicAction extends BaseAction { _bgAction = true; _bgTrigger = "ALARM"; _bgAlarmHours = [9, 10, 11, 12, 13, 14, 15, 16]; _bgAlarmMinutes = [00, 15, 30, 45]; actions = ["logMsg"]; }

In this case, the action will be executed 32 times per day, 4 times each hour, from 9:00am to 4:45pm. Since the _bgAlarmDays and the _bgAlarmWeekdays attributes were not specified, the action will be executed every day of the month.

Managing Background Actions

28 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Background actions are processed by server threads that are dynamically created as needed. If the background action terminates normally, such threads will also terminate normally, releasing any server resources that have been used by the transaction from which the action was launched. However, since repetitive and periodic background actions may never terminate, it may be necessary to monitor their progress and/or terminate them manually. In general, it is best to design periodic or repetitive background actions to print information to an appropriate log for trouble-shooting purposes, but that is not a requirement. All background action threads are automatically registered in the Skipjack Server's Process Table when they are created and un-registered when they are terminated. The Process Table can be viewed using the Skipjack console to monitor the status of a background action and/or to terminate the process manually. (An error message will be appended to the error log associated with any background action that is terminated manually.) See Process Manager for more information about the Process Manager and the Process Table.

29 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 4: Database Processing
In this section we discuss a set of transaction examples that retrieve data from a database server based on a set of input parameters and generate different types of results using Velocity templates. All of the examples discussed in this section can be found in the following locations: Web URL http://$SKIPJACK_URL/tutorial/dbQuery/ File Path $SKIPJACK_HOME/app/WEB-INF/transaction/tutorial/dbQuery/ where $SKIPJACK_URL is the URL for the Skipjack Server ('localhost:8080' for default installations) and $SKIPJACK_HOME is the root location of the Skipjack Server runtime directory ('/tools/skipjack' for default installations). In general, database processing is performed using the standard set of action items defined in skipjack-common.tdf, which includes the following: SQLTableAction SQLRecordAction SQLColAction SQLMapAction SQLUpdateAction SQLAction The SQLTableAction is the primary action used to retrieve information from the database. The SQL expression itself is defined in a SQL template file which is processed through Velocity before being sent to the database server. This allows the SQL script to reference item attributes defined in the transaction definition file, thereby increasing the flexibility of such scripts. The resulting table generated by the query is stored as a collection of attributes in the action item itself or in any item designated by the _destItem attribute. The other SQL actions have similar capabilities, but generally store the results in different ways to accomodate subsequent transaction processing needs.

Static Database Query

30 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Consider the following database transaction (ex1.tdf):


// // ex1.tdf // include "skipjack-common.tdf" item getDBList extends SQLTableAction { sqlFile = "getDBList.sql"; } item main extends BaseAction { actions = ["getDBList"]; templateName = "ex1.vm"; }

that retrieves the current list of databases defined on the database server. The actual SQL expression is defined in the "getDBList.sql" as follows:
## ## getDBList.sql ## show databases

which is processed as a Velocity template file (even though this specific script doesn't really use any Velocity features). After the getDBList action is executed, the following attributes will be automatically defined:
getDBList.sqlExpr getDBList.table getDBList.rowCount getDBList.rows getDBList.cols getDBList.xxxCol = = = = = = SQL expression sent to database server query results number of rows in table Vector of TableRow objects in table Vector of TableCol objects in table TableCol object for column xxx

which can then be referenced by the response template as follows (ex1.vm):


## ## ex1.vm ## <body bgcolor="white"> <h2>Database List</h2> <pre> #foreach ($row in $getDBList.rows) $row.getValue(0) #end </pre>

to yield the following results:

31 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Database List
authority mysql pls security skipjack test

The template file used in this example demonstrates how the #foreach() directive can be used in Velocity to easily iterate over a Vector of data. (Actually, any enumerable Java object can be iterated over using the #foreach() directive.) Velocity assigns each TableRow object defined in that list to the $row variable, which is then used to access the getValue() method defined by the TableRow object. The ability to execute any public method allows Velocity templates to handle a wide variety of formatting problems, as well as make decisions about the content that should be displayed. Clearly, such power can be quickly abused, turning Velocity templates into mind-boggling, hard-to-read, coding nightmares if you are not careful. But, when used in moderation, it can make complex formatting tasks much simpler. The primary drawback of such an approach is the need to understand which Java methods are available, requiring access to the Java documentation for key objects. For that reason, a complete set of Java documentation for all objects used by Skipjack and the underlying toolkit can be found at:
http://$SKIPJACK_URL/apidoc/

including the table-related objects defined in the navius.toolkit.table package. When executing Java methods from Velocity templates, it is important to remember that any exception generated by such methods are "consumed" by Velocity without notification. In such cases, the corresponding variable substituion is aborted, resulting in the variable expression itself being passed to the output stream. See Debug Management for Skipjack mechanisms that can be used to trouble-shoot such problems.

Parameterized Database Query


We can extend the previous example to allow the user or client application to supply input parameters that determine the specific query that is executed. For example, the following transaction definition (ex2.tdf):
// // ex2.tdf // include "skipjack-common.tdf" schema inputSchema extends BaseSchema {

32 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

attrs = [ ["dbName", dbList, "default", "mysql"] ]; dbList = ["mysql", "skipjack", "test"]; } item getTableList extends SQLTableAction { sqlFile = "getTableList.sql"; } item main extends BaseAction { actions = ["getTableList"]; templateName = "ex2.vm"; }

allows the user to specify a database name and then it retrieves the list of all tables in that database using the following SQL script (getTableList.sql):
## ## getTableList.sql ## use $input.dbName; show tables;

In this case, the input.dbName attribute is used to dynamically construct the desired SQL expression. In subsequent examples, we'll see how the #foreach() directive can be used to easily generate a series of SQL insert statements. We can exercise this transaction using the default input form: http://$SKIPJACK_URL/tutorial/dbQuery/ex2.form which will show the list of database tables, as well as the actual SQL expression used based on the following template file (ex2.vm):
// // ex2.tdf // include "skipjack-common.tdf" schema inputSchema extends BaseSchema { attrs = [ ["dbName", dbList, "default", "mysql"] ]; dbList = ["mysql", "skipjack", "test"]; } item getTableList extends SQLTableAction { sqlFile = "getTableList.sql"; } item main extends BaseAction {

33 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

actions = ["getTableList"]; templateName = "ex2.vm"; }

In this template, we used a more complicated variable reference: $getTableList.table.getCol(0).getName() to access the getCol() method of the Table object, and then the getName() method of the resulting TableCol object to get the name of the column.

Multiple SQL Statements


The getTableList.sql script demonstrates how multiple SQL statements can be executed within a single script file by using ';' to separate them. Any delimiter string (1 or more characters) can be used by defining it on the first line of the script file using the following syntax: DELIM=mydelim For each statement defined, the statement will be executed by the database server and the results will be processed by the Skipjack server. If multiple query results are returned by a multi-statement SQL script, then only the last table result returned by the database server will be stored as the result of the SQL action. If all of the table results are needed, then separate SQL actions should be executed, one for each result.

Table Formatting
As we've seen, it is relatively easy to create a transaction that accepts a number of different input parameters, executes a dynamic SQL expression and returns the results. Once such a transaction exists, it can be used by GUI and non-GUI applications alike to perform that function. For GUI applications, however, more sophisticated output formatting is usually needed, and that is where Velocity begins to shine. Consider the following transaction definition file (ex3.tdf):
// // ex3.tdf // include "skipjack-common.tdf"

34 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

schema inputSchema extends BaseSchema { attrs = [ ["dbName", dbList, "default", "mysql"], ["tblName", "string", "nonempty"] ]; dbList = ["mysql", "skipjack", "test"]; } item getTableSchema extends SQLTableAction { sqlFile = "getTableSchema.sql"; } item main extends BaseAction { actions = ["getTableSchema"]; templateName = "ex3.vm"; }

and SQL script that retrieves a database table schema:


## ## getTableSchema.sql ## describe ${input.dbName}.${input.tblName}

Such a database query returns a table with multiple rows and columns that we would like to format using a standard HTML table tag. The following Velocity template file performs such a formatting task:
## ## ex3.vm ## <body bgcolor="white"> <center> <h2>Table Schema For '${input.dbName}.${input.tblName}'</h2> <table> <tr bgcolor=#efefef> #foreach ($col in $getTableSchema.cols) <th>$col.getLabel()</th> #end </tr> #foreach ($row in $getTableSchema.rows) <tr> #foreach ($col in $getTableSchema.cols) #if($row.getValue($col.getName())) <td>$row.getValue($col.getName())</td> #else <td>NULL</td> #end #end </tr> #end </table> </center>

35 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Clearly, this template is more complicated than we've seen before, but is still constructed from only a couple of directives. Specifically, the #foreach() directive is used to loop over all column labels to create the table column headers. Then, nested #foreach() directives are used to loop over each row and each column therein, to display each of the table cells. Finally, the #if() directive is used to determine when a NULL value exists in a table cell, replacing it by the string "NULL". (If Velocity generates a NULL value while performing a variable substitution, then it assumes that the variable is not defined and does not replace it in the output stream. The #if() directive can be used to detect such a situation and generate an appropriate output string.)

HTML Table Macro


Since typical database applications generate a large number of tabular results, Skipjack Server includes a set of Velocity macros that can easily generate standard HTML table displays. Clearly, such macros can't solve all problems for all applications, but they can be used as starting point or rapid-prototype to get the ball rolling. The #listShow() macro formats any Table object based on a set of formatting attributes defined in the transaction definition file. For example, consider the following tblFormat item that could be added to the previous example (ex4.tdf):
item tblFormat { table = getTableSchema.table; rowColorMap = ["lightblue", "bisque"]; }

which references the table retrieved by the getTableSchema action item and defines a color map for the rows that are displayed in the table. By defining that item in the transaction definition file, we can replace the previous template file by the following template file (ex4.vm):
## ## ex4.vm ## <body bgcolor="white"> <center> <h2>Table Schema For '${input.dbName}.${input.tblName}'</h2> #listShow($tblFormat) </center>

which uses the #listShow() macro to display the table. The #listShow() macro is defined in the following files:
$SKIPJACK_HOME/app/macros/list-macros-01.vm $SKIPJACK_HOME/app/macros/html-macros-01.vm

which is a self-documenting file. The documentation for all the macros defined in that file can be viewed using the following URL:

36 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

http://$SKIPJACK_URL/MACROS/list-macros-01.vm http://$SKIPJACK_URL/MACROS/html-macros-01.vm

which also has the side-effect of reloading the macro definitions, if you need to make modifications to the macros without rebooting the server. A number of macros defined in those files are useful for generating common HTML displays, such as a shaded box surrounding other text, titles, section headers or error messages. There is also a macro for generating an HTML-based barchart for a table with numeric columns, using item attributes defined in the transaction definition file, much like the #listShow() macro.

Database Record Retrieval


Since it is often necessary to retrieve a single row of data from the database, the SQLRecordAction is provided to extract one row of data and store each column/cell of that row in an item attribute named for that column. In that way, a transaction can easily reference individual values in subsequent actions. For example, consider the following database table:
UserName -------Fred Sally Jim Password -------asdasd8a 45&efXzw AAj8dygz

and the following transaction excerpt that uses the getUserRecord action to retrieve the data record associated with a given user:
item getUserRecord extends SQLRecordAction { sqlFile = "getUserRecord.sql"; UserName = "Fred"; _destItem = "userRecord"; }

Since the _destItem attribute is defined, the resulting values will be stored in the "userRecord" item. If no such item exists when the action is executed, it will be created automatically. After the getUserRecord action is executed, the following item attributes might hold the values retrieved from the database for user "Fred":
userRecord.UserName = "Fred" userRecord.Password = "asdasd8a"

Such information could then be used by another action, such as the following:

37 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

item getUserAccount sqlFile = UserName = Password = _destItem = }

extends SQLRecordAction { "getUserAccount.sql"; userRecord.UserName; userRecord.Password; "userRecord";

that might retrieve corresponding information from another table, using the UserName and Password values returned by the previous action as input parameters for the getUserAccount.sql script. Note again how the _destItem attribute is used to store the results of the second SQL query in the same item as before, resulting in the following attributes being defined:
userRecord.UserName userRecord.Password userRecord.Salary userRecord.Bonus userRecord.ExpenseLimit

Clearly, the results of the SQLRecordAction, like any other item, can be used by an output template to format the detailed information for a given user.

Database Column Retrieval


It is often desirable to retrieve a column of data and iterate over it for subsequent processing or pass the entire column of data to the template file. For example, the database query may select a column of data based on a given input, which is then used to populate an HTML choice list as part of an input form. In such cases, the SQLColAction can be used to retrieve a table of data and then to store one column as a Vector of data assigned to a given item attribute. For example, the following transaction excerpt:
item getUserList extends SQLColAction { sqlFile = "getUserList.sql"; _destItem = "userList"; }

would retrieve all of the user names and store them as a list of values assigned to the userList.UserName attribute:
userList.UserName = ["Fred", "Sally", "Jim"];

which could then be referenced in a Velocity template as follows:


<select size=5> #foreach ($user in $userList.UserName)

38 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

<option>$user #end </select>

to generate an HTML selection list.

Database Update/Insert
All of the examples so far have focused on retrieving data from the database, but the SQLTableAction can also be used to execute one or more SQL update, delete and insert statements in a SQL script. In such cases, the resulting rowCount will reflect the number of updates performed, not the number of rows in the table, which will be empty. There are also situations when a record needs to be added to a database table or updated if it already exists. To easily support such operations, the
SQLUpdateAction

action can be used to specify separate update and insert SQL scripts, defined as the "updateSql" and "insertSql" attributes (instead of the "sqlFile" attribute used for other SQL actions). The SQLUpdateAction first attempts to execute the "updateSql" script. If that succeeds and more than one row is updated, then no further processing is done. If the "updateSql" fails to update any rows in the table, then the "insertSql" script is executed. In either case, if an exception is generated, the action is aborted. For example, the following action:
item updatePassword extends SQLUpdateAction { updateSql = "password-update.sql"; insertSql = "password-insert.sql"; UserName = "Fred"; Password = "changethis"; }

// // // update set where

password-update.sql UserTable Password = '$updatePassword.Password' UserName = '$updatePassword.UserName'

// // // insert values )

password-insert.sql UserTable ( '$updatePassword.UserName', '$updatePassword.Password'

39 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

attempts to update the password for 'Fred' using the password-update.sql. If no such record exists, the password-insert.sql script is executed to create the user record and set the password.

Database Connection Re-Use


For each of the SQL actions described above, the Skipjack Server automatically creates (or re-uses) a connection to the database server when the action begins and releases that connection when the action is done. Consequently, if a transaction executes a series of SQL actions, there is a possiblity that each action is performed using a different connection. Since some database servers base their locking and/or transactional services on a per-connection basis, it is possible that the use of multiple connections by a given Skipjack transaction may result in unusual behavior of the corresponding database transaction. To facilitate the processing of multiple actions using the same database connection, the SQLAction can be used to execute a list of actions. For example, the following excerpt would perform the same actions as in the previous example:
item getUser extends SQLAction { actions = ["getUserRecord", "getUserAccount"]; } item getUserRecord extends SQLRecordAction { sqlFile = "getUserRecord.sql"; UserName = "Fred"; _destItem = "userRecord"; } item getUserAccount sqlFile = UserName = Password = _destItem = } extends SQLRecordAction { "getUserAccount.sql"; userRecord.UserName; userRecord.Password; "userRecord";

When the getUser action is executed, it will acquire a single database connection that is then shared by all of the actions executed by that action. When the getUser action is done, the database connection will be released. In databases such as MySQL, this approach can be used to lock one or more tables, and then to release the locks after all actions have been performed.

SQL Script Variables


In all of the SQL processing examples, we've shown how the SQL script file can reference arbitrary transaction item attributes in order to dynamically generate SQL expressions. In general, it is beneficial to write such references in a way that allows the SQL script file to be used by the widest range of transaction definition files, thereby isolating database commands as much as possible.

40 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

To support such an approach, the $curAction Velocity variable can be used to reference the action item that caused this template to be processed. For example, consider the following SQL template file (getUser.sql):
select * from myUsers where UserName = '$curAction.UserName'

and the following action item definitions:


item getFred extends SQLRecordAction { sqlFile = "getUser.sql"; UserName = "Fred"; _destItem = "userRecord"; } item getSally extends SQLRecordAction { sqlFile = "getUser.sql"; UserName = "Sally"; _destItem = "userRecord"; }

Both action items reference the same SQL script file, while defining different UserName attributes. When the getFred action is executed, the $curAction variable in the SQL script file will reference the getFred item and the value of $curAction.UserName will be "Fred". On the other hand, when the getSally action is executed, the $curAction variable will reference the getSally item and the value of $curAction.UserName will be "Sally". By using the $curAction variable in SQL script files as much as possible, and by defining all required SQL input attributes in the same action item, the mapping between SQL action items and SQL script files is greatly simplified and there is a greater chance that scripts (as well as SQL action items) can be re-used by other transactions. When generating SQL expressions, it is important to remember the string quote conventions used by SQL and to use the proper quote symbols for each data value. To facilitate such processing, the #sqlString() macro can be used to properly quote a string value. For example, the previous example script file is best written as follows:
select * from myUsers where UserName = #sqlString($curAction.UserName)

to ensure that the $curAction.UserName value is properly quoted. The #sqlString() macro is designed to support the string quoting conventions used by MySQL and other ANSI SQL database servers. Different servers may require different quote conventions.

41 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Column Labels
Since database column names are often cryptic and may appear in a wide-range of displays, the SQL actions are designed to automatically determine column labels that are more appropriate for user displays. We've already seen an example of this when using the getLabel() method from the TableCol object as the column label in an HTML table. By default, the column label is defined to be the same as the table column when a table is retrieved from the database. If, however, the guiLabel item exists and an attribute is defined in that item with the same name as a column label, then the corresponding value will be used as the column label when the table is retrieved. For example, if the following items are defined:
item guiLabel { UserName = "User Name"; Street = "Street Address"; CityState = "City, State"; } item getData extends SQLTableAction { sqlFile = "getUserData.sql"; }

then the labels defined in the guiLabel item will be assigned to each of the corresponding columns in the table returned by the getData action item. In most cases, it is beneficial to define a single guiLabel item containing all of the labels used for a given application and then to include that item in all transactions. In fact, the skipjack-labels.tdf already defines the labels used by the internal Skipjack transactions and that file is automatically included whenever the skipjack-common.tdf file is included. Consequently, if you want to add or modify labels to the guiLabel you need only overwrite the default guiLabel item as follows:
include "skipjack-common.tdf" item guiLabel overrides guiLabel { _readonly = true; UserName = "User Name"; Street = "Street Address"; CityState = "City, State"; }

Note, the "overrides" directive is used instead of the common "extends" directive because both items have the same name and the overrides directive tells the compiler that you really want to re-use the name. You can also use the "replaces" directive, which effectively erases all attributes defined by the original guiLabel item, using only the attributes defined in this item definition. You should also note the use of the "_readonly" attribute, which tells the server that the guiLabel item defined here will not be updated during transaction processing. This information allows the server to optimize the internal processing of items, decreasing the overall time needed to initialize a transaction. See Performance Tuning for more details.
5/11/2007 10:14 AM

42 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

SQL Exception Handling


Life would be peachy if database statements never failed, but that is not the case. In fact, a wide range of exceptions can be generated depending on the specific database server being used. In order to gracefully handle such exceptions, all SQL actions support the optional definition of the sqlErrorMap attribute, as follows:
sqlErrorMap = [ (".*Duplicate entry.*", "301 Invalid Entry", "Entry Already Exists"), (".*", "500 Database Error", "Internal Database Failure") ];

The sqlErrorMap defines a list of tuples, where each entry specifies how a matching set of exceptions should be handled. When a database exception is generated, the resulting error message is compared against the GNU regular expressions defined as the first element of each tuple. If the message matches one of the expressions (processed from top to bottom) then the second element in that tuple is assigned to the tx.status attribute and the third element in the tuple is assigned to the tx.errorMsg attribute. At that point, the action is aborted, which causes the transaction to be aborted and the tx.status and tx.errorMsg are sent back to the user or client application as part of the failed transaction's response. In general, it is not necessary to specify the sqlErrorMap for most SQL actions, since the database error message is probably sufficient to explain the source of the problem. However, in some cases, it is desirable to hide the details from the user, supplying a more application-specific error message. (See Error Response for more details.)

43 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 5: Transaction Response
Skipjack Server is an HTTP-based server that generates an output file for every transaction that is processed, which is a fundamental characteristic of any HTTP server. The actual output type is specified by the MIME Content-Type header which is transmitted before the file itself. Typically, the text/html MIME type is used, since most applications are designed for browser-based client access. However, any MIME type can be used depending on the type of transaction and/or client software. In fact, Skipjack Server supports the ability to generate multiple output files for the same transaction, allowing different types of clients to use the same transaction. NOTE: All of the examples discussed in this section can be found in the following locations: Web URL http://$SKIPJACK_URL/tutorial/txResponse/ File Path $SKIPJACK_HOME/app/WEB-INF/transaction/tutorial/txResponse/ where $SKIPJACK_URL is the URL for the Skipjack Server ('localhost:8080' for default installations) and $SKIPJACK_HOME is the root location of the Skipjack Server runtime directory ('/tools/skipjack' for default installations).

Default Transaction Response


Consider the following transaction from the previous section (ex1.tdf):
// // ex1.tdf // include "skipjack-common.tdf" item getDBList extends SQLTableAction { sqlFile = "getDBList.sql"; } item main extends BaseAction { actions = ["getDBList"]; templateName = "ex1.vm"; }

44 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

that retrieves the list of databases from the database server, referencing the following response template file (ex1.vm):
## ## ex1.vm ## <body bgcolor="white"> <h2>Database List</h2> <pre> #foreach ($row in $getDBList.rows) $row.getValue(0) #end </pre>

In this case, the response template is written as an HTML file, which displays the list of databases using standard HTML tags. For most transactions, this is all that is needed and the template filename can simply by specified using the main.templateName attribute.

Common Response Templates


Many transactions are used simply to update the database or cause some action to be performed, requiring little or no output. In those cases, the following common response templates may be useful: COMMON/tx-status.vm Displays only the transaction status as a plain text string. COMMON/tx-summary.vm Displays a single plain text line that contains the transaction completion time, transaction ID, remote user ID, client ID and the transaction response time. COMMON/tx-output.vm Extends the COMMON/tx-summary.vm template to include all of the output item attributes generated by the transaction. COMMON/tx-success.vm Generates an HTML display based on main.successMsg and main.successTitle attributes that indicates the outcome of the transaction. The resulting display also includes an "OK" button that executes a subsequent transaction or accesses an arbitrary URL when the user presses the button. See Common Success Response for more details concerning the use of the COMMON/tx-success.vm response template. Such templates can be used for debug purposes, when developing transactions before a GUI is developed, or as part of a production system.

Common Success Response


5/11/2007 10:14 AM

45 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The COMMON/tx-success.vm template allows a transaction author to easily generate output for transactions that only need to display a simple message and then branch to another URL when the user acknowledges the message.

Success Message and Title


The message is specified using the main.successMsg and main.successTitle attributes. If either of those attributes is not defined, a default value of "Transaction Successful" will be used.

Success URL
If the main.successURL or input.successURL attributes are defined, then it will be used as the URL invoked by the "OK" button that is displayed beneath the message. That is, when a browser user presses that button to acknowledge the message, the browser will go to that URL as the next step in the user interaction. To facilitate sending input parameters to the successURL, all of the input attributes defined when the transaction response is generated are defined as hidden HTML form parameters, which will cause them to be submitted when the successURL is invoked by the "OK" button. If no main.successURL attribute is defined, the "OK" button will function just like the "Back" button provided by the browser. For example, if we modify the previous transaction as follows (ex2.tdf):
// // ex2.tdf // include "skipjack-common.tdf" item getDBList extends SQLTableAction { sqlFile = "../dbQuery/getDBList.sql"; } item main extends BaseAction { actions = ["getDBList"]; successTitle = "Database List Retrieval"; successMsg = "Found "+getDBList.rowCount+" Databases"; templateName = "/COMMON/tx-success.vm"; }

then it will display the following HTML output when executed from within a browser:

46 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

If we define the main.successURL attribute as follows (ex3.tdf):


item main extends BaseAction { actions = ["getDBList"]; successTitle = "Database List Retrieval"; successMsg = "Found "+getDBList.rowCount+" Databases"; successURL = "/test/showInput.tdf"; templateName = "/COMMON/tx-success.vm"; }

then the /test/showInput.tdf transaction will be executed when the "OK" button is pressed, displaying any input parameters from the ex3.tdf transaction passed as hidden parameters to the showInput.tdf transaction. For example, if you enter the following URL in a browser:
http://$SKIPJACK_URL/tutorial/txResponse/ex3.tdf?name=Fred&salary=123

then the "name" and "salary" input attributes will be displayed (along with some internal attributes) when the "OK" button is pressed. The tx-success.vm template uses the input.successURL attribute value if the main.successURL is not defined. Therefore, it is possible for a high-level transaction to specify the URL (as a hidden form field, for example) that should be used by a lower-level transaction. In this way, the low-level transaction can be called from different high-level transactions and can automatically branch to different destinations when the user acknowledges the message.

Success Redirect
If the main.successRedirect or input.successRedirect attributes are defined as "true", then the HTML output generated by the tx-success.vm template will automatically cause the client browser to be redirected to the success URL. In such cases, the success message and button will not be displayed, but all hidden input fields will be sent to the success URL as if the user had pressed the button themselves. Such a mechanism is usually used when executing a low-level transaction to perform a server-side function, such as deleting a record in the database, and then re-executing the high-level transaction, such as a list of all records in the database, without requiring the user to acknowledge the successful outcome. For example, if the following URL is entered:

47 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

http://$SKIPJACK_URL/tutorial/txResponse/ex3.tdf?name=Fred&salary=123&successRedirect=true

then after the ex3.tdf transaction is executed, the browser will immediately proceed to the ex2.tdf transaction which will display all the input parameters that were copied from the original transaction URL.

Response Map
The main.templateName attribute is actually the default value used by the transaction's "response map" which is used to determine the specific template to be used based on the desired MIME type. The response map is defined by the main.responseMap attribute, which uses the following default setting for all transactions:
responseMap = ("transaction/map", (".*", TransMapResponse), templateName);

templateName = "/COMMON/tx-status.vm";

The main.responseMap is processed from top to bottom, using the first entry in each tuple as a GNU regular expression that is compared to the
response.contentType

attribute. If a match is found, the second entry in the tuple indicates either the name of a Velocity file to be processed or the name of an action to be performed. The response.contentType can be defined statically in the TDF file by the transaction author or can be defined dynamically using attribute expressions or actions. Furthermore, if the input.contentType is defined when the transaction is executed, it will be used to overwrite the
response.contentType

attribute. This allows users and client applications to specify the desired output content type. If no value is specified, a default value of "text/html" is used. As can be seen in the default definition above, if the transaction/map MIME type is set, then the TransMapResponse action will be executed, which generates a data output stream that encodes the attribute values for the input, output and tx items. (See Client Application Support for more details about processing transaction output using the transaction/map MIME type.) Otherwise, the wildcard expression .* will match and the template file name (or action name) specified by the templateName attribute will be processed. This provides a convenient mechanism for transaction authors to specify the most common response mapping (a single template), while allowing them to override the responseMap itself for more involved situations. For example, if we modify the previous example as follows (ex4.tdf):
item main extends BaseAction { actions = ["getDBList"]; successTitle = "Database List Retrieval"; successMsg = "Found "+getDBList.rowCount+" Databases"; successURL = "/test/showInput.tdf";

48 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

responseMap = ("transaction/map", "TransMapResponse"), ("text/plain", "/COMMON/tx-status.vm"), (".*", "/COMMON/tx-success.vm"); }

then the same HTML success message will be generated by default using the /COMMON/tx-success.vm template. However, if the following URL is executed:
http://$SKIPJACK_URL/tutorial/txResponse/ex4.tdf?contentType=text/plain

then plain text output will be generated using the /COMMON/tx-status.vm template file.

Error Response
When an exception is generated by a transaction, all action processing is immediately aborted and a transaction response is generated based on the value of the response.contentType attribute. Such processing is controlled by the main.errorMap attribute, which is defined as follows by default:
errorMap = (".*ResourceNotFoundException", guiStatus.ResourceNotFound, "/COMMON/NotFoundException.vm"), (".*SQLException", guiStatus.DatabaseException, "/COMMON/SqlException.vm"), (".*UserException", guiStatus.UserException, "/COMMON/UserException.vm"), (".*SecurityException", guiStatus.SecurityException, "/COMMON/SecurityException.vm"), (".*", errorStatus, "/COMMON/UnknownException.vm"); errorStatus = guiStatus.UnknownException + " - " + tx.errorClass;

Much like the main.responseMap attribute, the main.errorMap is processed from top to bottom, looking for a match using the first entry in each tuple as a GNU regular expression. However, unlike the responseMap the regular expression is compared with the Exception Class as designated by the
tx.errorClass

attribute, which is automatically defined when the exception is generated. When a match is found, the second entry in the tuple is assigned to the tx.status attribute and the third entry is used to generate the transaction response, which may consist of an action name or Velocity template file. The main.errorMap attribute is defined for all actions in the COMMON/skipjack-common.tdf file, referencing a set of default HTML template files for various

49 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

common exceptions. Transaction authors can override that definition to specify custom error handling information. Typically, even when custom error maps are defined, it is prudent to assign a standard Skipjack or application status value. The standard Skipjack status values are defined by the guiStatus which is specified in the COMMON/skipjack-status.tdf file. Transaction authors are free to override or extend the guiStatus item as needed.

Response Actions
A transaction response can be generated using either a Velocity template file, a generic response action or a custom response action. In all cases, response processing occurs after all other actions referenced by the main action item are processed. The following response actions are provided by the Skipjack Server: FileResponse Retrieves a given file from the server's file system and uses it as the transaction response. See Shell Script Processing for more details and an example of how it can be used. ShellResponse Executes an operating system/application shell script/executable and uses the output of that script as the response for the current transaction. See Shell Script Processing for more details. TxResponse Executes a sub-transaction on any Skipjack Server, local or remote, and uses the response from that transaction as the response of the current transaction. See TxResponse Class for more details. TransMapResponse Generates a data stream by encoding all of the attribute values defined by one or more transaction items using an encoding scheme defined by the navius.toolkit.format.TransactionMap Java class. See TransMapResponse Class for more details. TransPropResponse Generates a data stream by encoding all of the attribute values defined by one or more transaction items as a Java properties file. See TransPropResponse Class for more details. In all cases, the response action is responsible for setting an appropriate value for the Content-Type HTTP header that is sent back to the client application. In some cases, such as the TransMapResponse response action, the content type is statically defined, while in other cases, such as the FileResponse and ShellResponse response actions, the transaction author can specify the proper type using the mimeType attribute.

50 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 6: Shell Script Processing
Truly powerful server applications can be built simply by combining the vast number of tools, scripts and applications that already exist within modern operating systems and public-domain warehouses. Since the Skipjack Server itself depends on various packages provided by the operating system, a number of actions are provided to allow transaction authors to easily tap such resources as well. In particular, the following actions can be used to access resources outside of the server: ShellResponse ShellAction FileResponse These actions can be used separately or combined with other actions as needed.

ShellResponse Action
In many cases, the output generated by a shell script can be directly used as the output of the transaction and the shell script input can be fully specified using command line options. In such cases, the ShellResponse response action can be used to execute the script and use the output directly as the transaction response. For example, the following transaction (test/sysConfig.tdf):
item genResponse extends ShellResponse { shellCmd = skipjack.BINDIR + "SystemConfig.pl"; mimeType = "text/plain"; } item main extends NOP { templateName = "genResponse"; }

executes the standard SystemConfig.pl script that is provided by the Skipjack Server, using the resulting output as a plain text transaction response. In this case, the templateName attribute references an action, not a Velocity template filename, as is typical. The transaction engine automatically detects this situation and it uses the specified action to generate the transaction response, instead of using the Velocity template engine.

51 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

In this example, the main action extends the NOP action because it doesn't need to perform any actions other than the genResponse action, which is automatically executed after the main action is done (doing nothing). The ShellResponse response action provides a simple and effective mechanism for integrating the Skipjack Server with existing scripts or executables that generate an output stream that does not require additional processing.

ShellAction
The ShellAction allows a transaction author to execute a given shell command and then continue transaction processing. If an optional input file is defined, then that file will be processed using Velocity and sent to the standard input stream of the shell command when it is executed. This allows a transaction to dynamically construct shell input scripts or control files. Any output required from the shell command can be saved directly to a file by the shell script, saved to a file by the transaction, appended to a server log file or processed directly by the transaction itself. For example, the following transaction definition provides a way to restart the Skipjack Server:
// // restart.tdf // include "skipjack-common.tdf" item main extends ShellAction { shellCmd = "/tools/skipjack/bin/skipjack.sh restart"; }

In this case, the shell command is fully specified and there is no need to define the inputFile attribute because the shell script doesn't accept any input. Note that no templateName attribute is defined in the main item. In this case, the default template file /COMMON/tx-status.vm is used, which simply displays the transaction status when it has completed. (In this specific case, however, the transaction will never finish because the server will be restarted by the shell script.)

Server Environment Variables


Generally it is not a good idea to hard-code paths in transaction definitions if possible, because that may cause problems if the server runtime directory is moved in its entirety to another location. To help eliminate such problems, the server automatically defines a set of transaction item attributes with the current value for various environmental variables. In particular, the skipjack.BINDIR attribute is defined to be $SKIPJACK_HOME/bin. Such environmental attributes can be used to remove hardcoded paths related to the Skipjack Server, as in the following modification of the previous transaction:
5/11/2007 10:14 AM

52 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

// // restart.tdf // include "skipjack-common.tdf" item main extends ShellAction { shellCmd = skipjack.BINDIR + "skipjack.sh restart"; }

Note, the paths stored in the skipjack attributes already include a trailing path delimiter. The test/showRequest.tdf transaction can be executed to display a list of all skipjack attributes defined by the server, as well as all request attributes that are defined as the result of the transaction request being processed.

Shell Input File Processing


As with the database processing actions, the Velocity template engine is used to process any shell input file that is specified. This means that the transaction author can prepare the input data needed by the shell command in the transaction itself (using attribute expressions or other actions) and then use Velocity to dynamically construct the actual shell input commands or configuration data. For example, suppose that we want to generate a chart using the standard gnuplot utility available for most operating systems. The following action item definition might be used to control such a process:
item genChart extends ShellAction { shellCmd = "/usr/bin/gnuplot -"; inputFile = "chart.vm"; chartFile = "/tmp/gnuplot." + processID; }

The "-" command line argument to the gnuplot utility instructs it to accept a stream of plotting commands from its standard input stream. Since the inputFile attribute is defined, the "chart.vm" file:
set output '$curAction.chartFile' set terminal png small color set xrange [0:10] set yrange [0:10] set xlabel "X Axis" set ylabel "Y Axis" set title "Test Chart" set size 1.0,0.8 plot '-' title "" with lines 0 0 1 1 2 2 3 3 4 4

53 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

5 5 6 4 7 3 8 2 9 1 10 0

will be processed by Velocity and the resulting output will be sent to the gnuplot command. Although the input file may look a little cryptic, anyone familiar with gnuplot could easily write such a script. Note how the $curAction.chartFile attribute is referenced in the input file to specify the output file to be generated by gnuplot. Furthermore, by examining the item definition above, we see that the chartFile attribute is constructed from a temporary path prefix and the processID attribute, which is automatically defined to be a unique value whenever a ShellAction is performed. In this way, we can ensure that concurrent executions of the genChart action don't interfere with each other.

Shell Output File Processing


In some cases, a shell script executed using the ShellAction action will generate an output file that is needed as the response of the current transaction, perhaps after some other processing has been performed. To facilitate such processing, the FileResponse response action can be used in conjunction with the ShellAction action to achieve the same results as the ShellResponse response action. For example, a complete chart rendering transaction might be defined as follows:
// // test/chart.tdf // include "skipjack-common.tdf" item genChart extends ShellAction { shellCmd = "/usr/bin/gnuplot -"; inputFile = "chart.vm"; chartFile = "/tmp/gnuplot." + processID; } item genResponse extends FileResponse { outputFile = genChart.chartFile; mimeType = "image/png"; deleteFile = true; } item main extends BaseAction { actions = ["genChart"]; templateName = "genResponse"; }

The genResponse action extends the FileResponse action, specifying the file to be used as the transaction response as the outputFile attribute. Note the reference to genChart.chartFile which ensures that the genResponse action references the same output file generated by the genChart action. The mimeType

54 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

attribute is also used to define the MIME type sent to the user or client application as part of the HTTP response. Finally, the deleteFile attribute is used to remove the output file when the action is done. Since the purpose of the FileResponse action is to generate the transaction response, we need to reference it from the main.templateName attribute (or override the main.responseMap attribute). See Transaction Response for details about generating a custom transaction response.

Shell Working Directory


Some shell scripts require that they be executed in a specific working directory, which may need to be dynamically determined at run time. To facilitate such processing, the shellDir attribute can be used to specify the working directory in which the shell script will be executed. The shellDir value should be specified as an absolute path in the server's file system. If the shellDir attribute is not defined, then the directory containing the transaction definition file of the current transaction will be used as the shell working directory. If the shellCmd specifies a relative pathname for the shell script to be executed, it will be interpreted relative to the current working directory, as specified by the shellDir attribute.

Shell Working Environment


In order to maintain the highest levels of installation portability, when a shell script is executed the ShellAction automatically defines a collection of operating system environment variables that can be used by the shell script as needed. Specifically, the following primary environment variables are defined: PATH a collection of common system executable directories, including the Java bin directory used by the Skipjack Server JAVA_HOME the current value of the 'java.home' System property for the Skipjack Server CLASSPATH the current value of the 'java.class.path' System property for the Skipjack Server PERL5LIB the Skipjack Server directory containing Transaction.pm, allowing Perl scripts to easily refer to that module With those variables defined, the shell script will have access to the same executables and Java resources used by the Skipjack Server.

55 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

In addition to the environment variables listed above, all of the transaction attributes defined for the "input", "request", "tx", and "skipjack" items will be defined as environment variables, using the format "item_attr" for the variable names. For example, the "skipjack.ROOTDIR" transaction attribute can be accessed by the shell script as the "skipjack_ROOTDIR" environment variable and the "input.X" transaction attribute as the "input_X" environment variable. Because of operating system environment variable name restrictions, all '-' (dash) characters in the original transaction attribute name will be replaced by '_' (underscore) characters. For example, the "request.Accept-Encoding" transaction attribute will be defined as the "request_Accept_Encoding" environment variable.

Shell Exit Status


By convention, shell scripts return an integer exit status that can be used to determine if it succeeded or failed. Usually, a zero value is returned if successful and all other exit codes are considered as failures. In order to support the widest range of exit status processing, the ShellAction makes use of the following attributes:
_shellStatus exceptionOnError exceptionStatus exceptionMsg

Shell Status Attribute


After a shell script has terminated, the ShellAction stores the resulting numeric exit status in the _shellStatus attribute of the destination item named by the _destItem attribute. If the _destItem is not defined, then the ShellAction item itself will be used as the destination item. The destination item is supported by almost all Skipjack Server actions, allowing the transaction author to store the results for that action in another item. This helps to maintain a clear design distinction between an 'action item' and a 'data item', which usually makes transaction definition items easier to debug.

Automatic Error Handling


The exceptionOnError, exceptionStatus and exceptionMsg attributes can be used to easily control the generation of an exception for an unsuccessful exit status (ie. non-zero). Specifically, if the exceptionOnError attribute is "true" (the default value) then an exception will be raised whenver the exit status is non-zero. The exceptionStatus and exceptionMsg attributes can be used to specify the status and message associated with the exception, with default

56 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

values of "705 Shell Action Failed" and "Shell Exit Value = xxx", respectively. For example, the following action specifies a custom error message, depending on the _shellStatus value:
item doScript extends ShellAction { shellDir = "/my/working/directory"; shellCmd = "myScript -x 12 -y 23"; exceptionOnError = true; exceptionMsg } = _shellStatus > 0 ? "Bad Shell Status = "+_shellStatus : "Really Bad Shell Status = "+_shellStatus;

The exceptionOnError attribute supported by the ShellAction should not be confused with the _ignoreError attribute that is supported for all actions. The _ignoreError attribute causes the action processing engine to ignore any exception raised by a given action, thereby allowing the transaction to continue. The exceptionOnError attribute determines if an exception should be raised because of a non-zero shell exit status, it does not prevent other types of exceptions from being thrown.

Custom Exit Status Processing


If the exceptionOnError attribute is "false", then no exception will be raised automatically based on the shell exit status. This allows subsequent actions in the transaction to use the _shellStatus as needed to determine how to proceed after a possible shell script failure. The _shellStatus attribute can also be referenced by one or more error checks defined as the postErrorCheck attribute of the shell action item, as in the following example:
item doScript extends ShellAction { shellDir = "/my/working/directory"; shellCmd = "myScript -x 12 -y 23"; exceptionOnError = false; postErrorCheck = [ (_shellStatus < 0, guiStatus.ShellActionFailed, "Bad Status From 'myScript' = "+_shellStatus) ]; }

In this case, an exception is raised only if the status is less than zero. Clearly, more complex evaluation criteria can be used and more advanced failure recovery is possible, based solely on the exit status.

57 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Shell Output Processing


In the previous gnuplot example, the output of the shell script was written to a file and then the file was used as the transaction response. Such an approach is typical for shell scripts that generate output files as a normal part of their processing task. Other scripts, however, may generate output only for debug purposes or to describe an error condition. In such cases, it may be necessary to capture the output of such scripts and store it in an appropriate place or even process the output of the script as part of the current transaction. For example, the script may generate a sequence of database record identifiers that should be deleted for a particular reason. To support such a wide range of possible alternatives, the ShellAction allows the following attributes to be defined to control how shell script output is processed: Attribute outputDest Description Specifies how the STDOUT output for the process should be processed, with the following values supported: NONE - all output lines are ignored (default) LOG - each output line is appended to the log file designated by the outputFile attribute FILE - each output line is saved in the file designated by the outputFile attribute ACTION - all actions listed in the outputAction attribute will be called just before the shell script is executed, after completion of the shell script, and once for each output line outputFile If outputDest is 'LOG', the name of the Skipjack Server log file to be appended by each output line If outputDest is 'FILE', the name of the file to which all output lines are written

outputSeverity If outputDest is 'LOG', this specifies the severity of the log record that is generated (default = DEBUG) outputPrefix outputAction If outputDest is 'LOG', this specifies the prefix for each log record that is generated (default = action name) If outputDest is 'ACTION', this specifies the name of an action (or a vector of action names) which should be executed just before the shell command, just after completion of the shell command, and once for each output line. The following attributes are defined in the destination item before each action is executed:
_curStep

- one of (PRE, POST, LINE) where 'PRE' indicates that the shell command is about to be run; 'POST' indicates that the shell command has just completed; 'LINE' indicates that an output line was generated - the current output line - the shell exit status (only valid when _curStep = POST)

_curLine _shellStatus

errorDest

Same functionality as outputDest for STDERR output lines

58 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

errorFile errorSeverity errorPrefix errorAction

Same functionality as outputFile for STDERR output lines Same functionality as outputSeverity for STDERR output lines (default = ERROR) Same functionality as outputPrefix for STDERR output lines Same functionality as outputAction for STDERR output lines

Basic Error Logging


Typically, shell scripts generate output lines on STDERR only when something is wrong. Therefore, it is usually advantageous to append such output directly to one of the Skipjack Server logs for trouble-shooting purposes, as in the following example:
item doScript extends ShellAction { shellDir = "/my/working/directory"; shellCmd = "myScript -x 12 -y 23"; errorDest } = "LOG";

Simply by specifying the errorDest attribute as "LOG", all lines printed to the shell script's STDERR output stream will be appended to the Skipjack Server error log (the default errorFile value). By default, the log entries will be assigned an errorSeverity of 'ERROR' and an errorPrefix of 'myTrans.doScript', where 'myTrans' is the name of the current transaction.

Generating Output Files


In some circumstances, it is more advantageous to print the output lines from either STDERR or STDOUT (or both) to a file for subsequent processing or trouble-shooting. In such cases, the 'FILE' type can be specified for the errorDest or outputDest attributes, as in the following example:
item doScript extends ShellAction { shellDir = "/my/working/directory"; shellCmd = "myScript -x 12 -y 23"; errorDest = "LOG";

outputDest = "FILE"; outputFile = "/tmp/myScript.out"; }

In this case, the STDERR output lines are appended to the Skipjack Server error log, while the STDOUT output lines are written to the "/tmp/myScript.out" file.

59 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Keep in mind that multiple transactions can be executing concurrently, which usually requires dynamically generated unique filenames to keep different transactions from using the same file. Review the chart example above to see how the processID can be used in such cases.

Processing Output Lines


It is often desirable to process each line generated by a shell script, either on STDERR or STDOUT, within the same transaction. For example, it may be necessary to generate an alarm for the operator, send an email to a supervisor or otherwise handle one or more failures indicated by the shell script. Alternatively, the shell script may be used to prepared imported data that then needs to be inserted into the database. To support arbitrary line-by-line processing of shell script output, the 'ACTION' type can be specified for the outputDest or errorDest attributes, along with one or more actions in the outputAction and errorAction attributes, respectively. For example, the consider the following action definitions:
item doScript extends ShellAction { shellDir = "/my/working/directory"; shellCmd = "myScript -x 12 -y 23"; errorDest errorAction = "ACTION"; = ["genAlarm"];

outputDest = "ACTION"; outputAction = ["deleteRecord"]; } item genAlarm extends TxAction { preCondition = doScript._curStep == "LINE"; _transName Severity Message } item deleteRecord extends SQLTableAction { preCondition = doScript._curStep == "LINE"; sqlFile ID } = "deleteMyRecord.sql"; = doScript._curLine; = "alarmMgr/insert.tdf"; = "ALARM"; = doScript._curLine;

In this example, an operator alarm is created for every STDERR output line by the genAlarm action. The genAlarm action uses the preCondition attribute to indicate that it should only be executed when the doScript._curStep attribute is "LINE", not for the "PRE" or "POST" action processing steps. It then uses the output line generated by the shell script as the alarm message. The deleteRecord action is used to process each line generated on STDOUT by the shell script. In this example, each line consists of a single database record identifier, which is simply passed to the "deleteMyRecord.sql" database script. Here again, the deleteRecord action specifies a preCondition attribute so

60 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

that it is not executed for the "PRE" and "POST" steps. Clearly, by defining additional processing actions most output processing tasks can be performed in this way. If not, the output information can always be added to a table by the processing actions, for subsequent processing by other transaction actions executed after ShellAction processing is complete.

Background Shell Script Execution


Depending on the amount or type of processing performed by the shell script, it may be necessary to launch the script as a background task, allowing the current transaction to continue processing or respond to the client before the shell script is done. Background processing is easily specified using the background boolean attribute of the ShellAction. If the background attribute is "true", then the ShellAction will immediately return after launching the shell script as a background task. All of the output processing options described above are supported for both foreground and background shell script execution. That is all logging, file generation and output processing actions can still be defined even for background shell executions. In fact, error logging and processing is even more important for background shell scripts, since they may complete well after the humans have gone home. Since background shell scripts are not associated with any current HTTP request, the exceptionOnError attribute is ignored when background is "true". If the 'LOG' destination type is specified for either the outputDest or errorDest, then the shell exit status will be automatically recorded in the log.

Shell Script Process Management


Since shell scripts are executed as an operating system process outside of the transaction engine, it may be necessary to abort them if they are not working properly. The Skipjack Server's internal Process Manager is designed to support the analysis and management of all processing tasks within the server, including shell script processes (see the Process Manager section for more details). When any ShellAction action is executed at least one "process" is registered with the Process Manager, associated with the current transaction and action. The process remains registered with the Process Manager until the shell script has terminated. At that point, the process is unregistered and the ShellAction returns control to the transaction for subsequent processing. Depending on the processing being performed by a given ShellAction, one or more "processes" may be registered with the Process Manager for the same ShellAction; one each for the STDOUT and STDERR output handler threads, if defined, and another for the thread that checks the shell script exit status, which is always created. A complete list of the unique process identifiers assigned to the ShellAction is stored as the _pidList attribute of the destination item for that action. In the event that a shell script "hangs" or otherwise should no longer be executed, the Process Manager can be used to abort the shell script, using

61 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

the associated process registration. In such cases, the shell exit status will be set to "666" to signify that the shell script was aborted by the Process Manager. All ShellAction actions, regardless of the background attribute setting, have at least one process registered with the Process Manager. This means that even a "foreground" shell script execution can be aborted using the Process Manager. In that case, an exception will be generated by the ShellAction and the transaction can react accordingly.

62 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 7: Debug Management
Skipjack provides a number of mechanisms that allow both developers and operators to manage the generation of transaction debug information in the logs. This section describes the general type of debug information available when a transaction is executed and the mechanisms for controlling the generation of that information.

Transaction Debug Information


The following debug information is available for every Skipjack transaction: HTTP Request Information HTTP Response Information Input Parameters Output Parameters Session Attributes Action Processing Velocity Processing The information for all of the items listed above can be found in the $SKIPJACK_HOME/logs/trans.log file, except for the Action Processing information, which can be found in the $SKIPJACK_HOME/logs/action.log file, and Velocity Processing information, which can be found in the $SKIPJACK_HOME/logs/velocity.log file. Debug information can be enabled by defining certain item attributes in the transaction definition file (or included definition file) or by adding entries to the server-wide DebugControl memory table. Generally, the first approach is used by developers focused on a specific transaction or action, while the second is used by operators focused on monitoring the behavior of a user, transaction or action. By default, all debug information is disabled.

63 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Transaction Definition File Attributes


The following item attributes within a transaction definition file control the generation of debug information: debug.requestDebug If true, HTTP Request information is generated. debug.responseDebug If true, HTTP Response information is generated. debug.inputDebug If true, all transaction input parameters are printed to the log file. debug.outputDebug If true, all transaction output parameters are printed to the log file. debug.sessionDebug If true, all transaction session parameters, both incoming and outgoing, are printed to the log file. debug.velocityDebug If true, Velocity processing information is generated in the velocity.log file for all templates processed by the current transaction. *.actionDebug If true, action processing information is generated in the action.log file for the current action. The attributes listed above control the generation of specific information about a transaction or action. Additionally, the following item attributes may be defined to generate debug based on the current user, transaction name or action name(s): debug.users If the current user name is contained in this list of names, then debug information will be generated for each action processed in the current transaction. debug.transactions If the current transaction identifier is contained in this list, then debug information will be generated for each action processed in the current transaction. debug.actions If the current action name is contained in this list, then debug information will be generated for the current action.

64 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Generally, these attributes serve as convenient ways to specify a collection of actions, transactions or users to be monitor for a group of transactions, in which case the 'debug' item may be defined in a common file and included into all transactions in the group.

Velocity Debug Settings


If the debug.velocityDebug attribute is "true", then Velocity processing errors will be generated for all templates processed by the current transaction. If one or more processing errors occur, an exception will be thrown (thereby terminating the transaction) and an HTML error display will be generated. The types of processing errors to monitored are specified by the following additional attributes: debug.velocityNullMethodDebug If true, generate debug information for calls to methods that don't exist or return a null value. Default is "true". debug.velocityNullVariableDebug If true, generate debug information for non-silent references to null-valued variables. Default is "true". debug.velocityNullSilentVariableDebug If true, generate debug information for silent references to null-valued variables. Default is "true". debug.velocityLogErrors If true, print the debug information to the velocity.log file. Default is "true". debug.velocityAccumulateErrors If true, then all of the errors generated while processing a template are accumulated before an exception is thrown. Default is "true". debug.velocityErrorTemplate The name of the Velocity template to be used to display any exception that is generated while monitoring template processing. Default is "/COMMON/velocity-error.vm".

Server-Wide DebugControl Settings


Independent of attributes that can be set within a transaction definition file, operators can specify a collection of users, transactions or actions to be monitored by the server. This information is maintained in the DebugControl memory Table, which is automatically loaded from the skipjack.DebugControl database table. The debugMgr/showList.tdf

65 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

transaction can be used to display the current lists of users, transactions and actions being monitored, and to add or remove entries from each list. Whenever the lists are updated in this way, the server will automatically start monitoring transactions accordingly. During the execution of a given transaction, if the current username is contained in the user list or the current transaction identifier is contained in the transaction list, then all debug information associated with the transaction will be generated in the trans.log and action.log files. If no user or transaction match is found, then the settings within the transaction definition file will be used to control debug generation. During the execution of a given action within a given transaction, if the current action name is contained in the action list, then the action debug information will be generated in the action.log file. The action name entered in the DebugControl action list should always be prefixed by the name of the transaction. For example, if you wanted to monitor the 'genChart' action defined by the 'test/chart' transaction, then you should add an entry for 'test/chart.genChart' to the action list.

LogAction
The LogAction can be used by a transaction to append a log message to any of the log files supported by the Skipjack Server. The log message itself is generated by concatenating the values assigned to the following action item attributes: GroupID ElementID EventTraceID ErrorCode Message which are processed as strings. The exact meaning and usage of each field is application-specific and if a given field is not defined, it will be ignored. If the LogFile attribute is defined, then it will be interpreted as the Log4j Category name for the log file to be appended. The default value is "navius.skipjack.errorlog", which is the Category associated with the $SKIPJACK_HOME/logs/error.log log file. See the $SKIPJACK_HOME/app/WEB-INF/conf/log.cfg configuration file for a list of all Category names supported by the server. If the Severity attribute is defined using one of the following values: ERROR

66 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

WARNING INFO DEBUG then it will be used as the severity level of the resulting message when it is written to the log file. If the severity is lower than the filter level currently set for that log file, the message will be ignored. The default severity level is "INFO".

67 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 8: Error Checking
So far, we have discussed how the inputSchema can be used to perform syntax validation on the input parameters and how the errorMap and sqlErrorMap attributes can be used to processed any exceptions thrown during transaction processing. However, it is also possible to define one or more semantic error checks that can be performed either before or after any action is processed. This allows actions to be defined with their own self-defense mechanisms. That is, if the current value of key attributes are semantically invalid then the transaction can be aborted. Similarly, if the attribute results of the action don't meet a given criteria, the transaction can be aborted.

Pre-Processing Error Check


The preErrorCheck attribute can be defined for any action to specify one or more criteria used to determine if the transaction should be aborted prior to executing the action. For example, the following definition:
item getTable extends SQLTableAction { sqlFile = "getTable.sql"; ID = input.ID; Color = input.Color; preErrorCheck = [ (ID < 0 || ID > 99, guiStatus.InvalidParameter, "The ID must be between 1 and 99"), (Color in ["red", "white", "blue"] == false, guiStatus.InvalidParameter, "Invalid Color '" + Color +"'") ]; }

ensures that the ID attribute is between 1 and 99, and that the Color attribute is either "red", "white", or "blue" before the database action is executed. The preErrorCheck attribute can consist of one or more tuples, with the first entry in each tuple used as the error criteria. That is, if the first entry evaluates to "true", then an error exists. In that case, the second entry is assigned as the value of tx.status attribute and the third entry is assigned as the value of the

68 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

tx.errorMsg

attribute. Error criteria are evaluated from top to bottom until one of the criteria is "true" or until the bottom of the list is reached.

Post-Processing Error Check


The preErrorCheck is used primarily for input validation, while the postErrorCheck is used primarily for result validation. For example, the following action item definition:
item getTable extends SQLTableAction { sqlFile = "getTable.sql"; ID = input.ID; Color = input.Color; postErrorCheck = [ (rowCount == 0, guiStatus.NoRowsFound, "No Color Table Rows Were Found For ID '"+ID+"' and Color '"+Color+"'") ]; }

ensures that at least one row is returned by the database action, by checking the value of the rowCount attribute that is automatically defined by the SQLTableAction action after the SQL query is processed. As with the preErrorCheck attribute, multiple error criteria can be defined, accessing local attributes or attributes defined in other items to determine if transaction processing should be aborted.

Custom Error Messages


The preErrorCheck and postErrorCheck attributes provide a convenient mechanism to detect transaction processing errors and to generate an appropriate error message. As in the examples above, standard error status strings should be used whenever possible for consistency, while custom error messages should be defined to precisely explain the error that was encountered. As seen above, it is relatively easy to generate an error message by concatenating text and attribute values, thereby providing as many details as needed. If transactions are being executed from a browser, then it may be beneficial to include HTML tags in the error message to better format the message shown to the user via the standard exception templates. On the other hand, if the transaction is primarily used by non-HTML client applications, then it is probably best to generate simple text string error messages so that they can be easily processed by the client application as needed.

69 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 9: Transaction Security
The Skipjack Server provides a range of security features to prevent unauthorized execution of transactions and access to controlled resources. All the security mechanisms are based on User identities and operational Roles, which are assigned to both Users and Transactions.

User Authentication
By default, all resources and transactions provided by Skipjack require the client or user to provide authentication information for every HTTP or HTTPS request. When connecting to Skipjack via a browser, the information is acquired by the browser using either a standard login pop-up window or by the server application using a custom login screen (see Custom Login Screens for details). When connecting to Skipjack using the C++, Java or Perl Client Library, the user authentication information is provided using the setAuthInfo() method defined by the Transaction class. (See Client Application Support for more details). Regardless of how the authentication information is provided, it is used by Skipjack for two security purposes. First, the username and password provided are validated against the Access Control List (ACL) maintained by the server. If the username or password are invalid, access is denied and an error response is generated accordingly. If the username and password are valid and the user is attempting to access a static file (such as a GIF or HTML file) then no further access control is performed and the resource is returned to the client. If the client is attempting to execute a transaction, then Skipjack retrieves the list of one or more roles that has been assigned to that user (the User Role List) and the list of one or more roles that are required by the transaction (the Tx Role List). If the User Role List and the Tx Role List intersect, then transaction execution is allowed to proceed. If not, an appropriate error message is generated.

Transaction Authorization
Transaction authors can assign one or more required roles to a transaction simply by defining the security.roles action item in the transaction definition file. For example, the following definition:
item security { roles = ["Operator", "Supervisor"]; }

70 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

requires that the user be assigned the "Operator" or "Supervisor" role in order to execute the current transaction. If the security.roles attribute is not defined, then no security check is performed and every user is allowed to execute the transaction.

Guest Resources
In many cases, access to certain files and/or transactions need not be controlled and shouldn't require the user or client to provide a valid username or password. Such resources are called "Guest Resources" and are supported in Skipjack using a set of wildcard definitions. If a requested file or transaction path matches one of the wildcard expressions (defined as a GNU regular expression), then access will be granted to the user, regardless of the validity of the username and password supplied, if any. By default, the user will be granted the "_GUEST" username and the "_Guest" role during such accesses, but operators and developers may assign other usernames with different roles as needed.

Standard ACL Tables


The standard Access Control List (ACL) mechanism provided by Skipjack is based on the following set of database tables: skipjack.ACLUser skipjack.ACLRole skipjack.ACLUserRole skipjack.ACLGuest skipjack.ACLLogin The ACLUser table contains a list of all usernames and passwords supported by the server, while the ACLRole table contains all valid roles. The ACLUserRole table maps users to roles, while the ACLGuest table defines all wildcard expressions and usernames for Guest Resources. The ACL database tables are automatically created during the Skipjack Installation process and are populated with default usernames and passwords. *** SYSTEM OPERATORS SHOULD CHANGE THE PASSWORDS BEFORE A SYSTEM GOES OPERATIONAL *** User information can be added, removed and/or updated using User Admin Tool Roles and guest resources can be added or removed from the system by modifying the skipjack.ACLRole and skipjack.ACLGuest database tables.

71 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

ACLAction Processing
The ACL memory tables are not intended to be accessed directly by transactions. Instead, the ACLAction action item may be used to retrieve data from the ACL memory tables. The ACLAction performs a specific function based on the setting of the cmd attribute, with the following valid values: getRoleList getUserList getUserRoles getUserTable getGuestTable validateRole reloadACL In most cases, the requested data is stored in an attribute with an appropriate name. See ACLAction Class for more details. The "reloadACL" command is used to reload the ACL memory tables from the corresponding ACL database tables as defined by the tableACL.cfg configuration file. This command is executed by the User Admin Tool whenever the ACL database tables are updated.

ACL Configuration
The Skipjack ACL is configured using the security.cfg and tableACL.cfg configuration files found in the $SKIPJACK/app/WEB-INF/conf directory. The security.cfg file defines the names of the ACL tables, while the tableACL.cfg file defines the standard table definitions for the ACL Memory Tables listed above. Application developers may overwrite one or both of these files to install custom ACL tables. For example, an application may overwrite the security.cfg file provided by Skipjack and specify different names for the tables to be used from another table definition file. (See Memory Table Processing for more details.) Alternately, an application may only overwrite the tableACL.cfg file, to define a different set of source database tables or delimited data files, while still using the same names defined in security.cfg. This is most commonly done when the ACL tables will be retrieved from a database other then the standard "skipjack" database. (See Database Processing for more details about using connections to multiple database servers.) Finally, applications can simply append their own default authentication information to the standard Skipjack ACL tables when the application is initially installed.

72 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Applications should refrain from automatically reloading the ACL tables if they already exist, since the operators may have modified their contents and probably don't want to type it all back in again! To facilitate the sharing of the ACL tables between applications, each of the ACL tables has an 'AppName' column that may be used to identify the application that loaded that entry. For example, all of the default Skipjack entries are marked with an AppName of 'SKIPJACK'. Installation scripts can make use of the AppName column to determine how existing data should be handled.

Custom Login Forms


By default, user authentication via a browser is handled using the "Basic" HTTP authentication mechanism, which results in a small pop-up login window being displayed automatically by the browser whenever authentication information is required. This is the simplest and most universally supported approach, although the pop-up windows lack visual appeal in most browsers. Skipjack supports the use of custom login forms, allowing application developers to generate arbitrarily complex forms, with lots of bells and whistles. Login forms can be generated using a login form transaction or can be defined as static HTML files. If a login form transaction is used, forms can be customized as needed depending any information available to that transaction when it is executed, such as the specific URL being requested by the user. A specific login form can be assigned to one or more URLs by using GNU regular expressions to define the URLs to be matched. Furthermore, multiple login forms can exist within the same server, servicing different parts of the application URL name space as needed.

ACLLogin Table
Forms-based authentication is configured in Skipjack by inserting one or more records into the ACLLogin database table, which is normally done at installation time. The Skipjack Server defines the following default record: Resource LoginURL AppName

/test/formLogin/.* /skipjack/login-form.tdf SKIPJACK which specifies that the /skipjack/login-form.tdf transaction should be executed whenever login information is needed to execute any file in the /test/formLogin/ directory. Application developers may add one or more additional records to define the login transactions (or static files) to be used for other individual transactions or groups of transactions. For example, the following definition:

73 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Resource

LoginURL

AppName

/test/formLogin/.* /skipjack/login-form.tdf SKIPJACK /myapp/.* /myapp/login.tdf MYAPP

would cause the /myapp/login.tdf transaction to be executed for all access attempts in the /myapp/ directory. Application installation scripts may use the AppName column in the ACLLogin table to determine which records can be overwritten during re-installation without adversely affecting the settings required by the Skipjack Server or another application.

ACLGuest Table
For every LoginURL defined in the ACLLogin, a corresponding entry should also be made in the ACLGuest table to indicate that any user can access that resource and to specify the internal username associated with that resource. In normal applications, the _GUEST username can be used for this purpose. For example, the following entry in the ACLGuest table Resource UserName AppName MYAPP

/myapp/login.tdf _GUEST

allows any user to access the login form transaction specified by the previous example.

Login Form Transaction


When a login form transaction is executed, the following session item attributes are defined: Attribute session.skipjackUsername session.skipjackPassword session.skipjackRealm Description last username provided, if any last password provided, if any realm name as specified in web.xml

74 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

session.skipjackOrigURL

original URL requested

session.skipjackLoginURL login servlet URL (ie. "/skipjack/login") The skipjackOrigURL attribute will include a query string that defines all of the input parameters that were provided (using either the GET or POST methods) for the URL that was originally requested. Login form transaction authors can use these attributes in any way that they want to display the login form, as well as any other attribute normally available to a transaction. (See Session Management for more details about the session item and related session processing features.) The default login form is defined by the "/skipjack/login-form.tdf" transaction and the "/skipjack/login-form.vm" and "/skipjack/login-page.vm" templates. If you want to make a custom login form, you can use those files as examples to build your own or can include those files and override attributes as needed to build your own login forms and/or pages. In normal practice, there is no need to define the security.roles attribute for a login form transaction, because it should be accessible to everyone in order to allow them to log into the server.

HTML Login Form


The HTML form generated by a login form transaction or defined by a static login file can be as simple or as ornate as desired. The only requirements are as follows: Use the POST method for the form tag Define the Action URL to be "/skipjack/login" (an internal Skipjack Servlet) Define an input field named "skipjackUsername" (the user's login name) Define an input field named "skipjackPassword" (the user's password) For example, the following form could serve as a valid (albeit ugly) login form:
<form method="POST" action="/skipjack/login"> <INPUT name="skipjackUsername" TYPE=text SIZE=20 MAXLENGTH=17><br> <INPUT name="skipjackPassword" TYPE=password SIZE=20 MAXLENGTH=17><br> <INPUT name="loginButton" TYPE=submit VALUE="Login"><br> </form>

See the /skipjack/login-form.vm and /skipjack/login-page.vm templates for an example of a more useful login form and page layout.

75 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 10: Client Application Support
The Skipjack Server is an HTTP-based server that can be used to provide Web-services to client applications, other servers or users via a browser. In this section, we describe a number of approaches that can be used to rapidly develop client applications for the Skipjack Server.

Raw HTTP Request


Since the Skipjack Server is based on a standard HTTP server framework, any client or server application can interact with Skipjack simply by opening a connection to the appropriate TCP port and sending a valid HTTP Request. Skipjack will process the HTTP request and will return a standard HTTP Response that includes an output file conforming to a given MIME type. For example, the following HTTP Request:
GET /test/nop.tdf HTTP/1.0 Host: localhost:8080 Authorization: Basic YWRtaW46YWRtaW4=

will execute the test/nop.tdf transaction and return the result as a text/html file, which is the default response MIME type for any transaction. The Authorization header shown above is the encoding for a username and password of "admin/admin". If a different login is required, a different Authorization header should be used.

Transaction Map Response


As discussed in the Transaction Response section, Skipjack transactions can generate different output files dynamically based on the contentType input parameter. This allows client applications to specify the type of output format that is best suited for their purposes. Transaction authors are free to define as many or as few supported types for each transaction. By default, the text/html MIME type is used to generate the response. In many cases, client applications simply need to check the status of a transaction that was executed and possibly process one or more output
5/11/2007 10:14 AM

76 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

parameters. To that end, the transaction/map MIME is supported by the Skipjack Server for all transactions. The transaction/map file format consists of a small number of formatted record types that can be used to encode the following types of data: Scalar Value An arbitrary string that represents a single value, representing strings, numbers, dates, etc. List Value An ordered list of scalar values, where each string may represent a different type of value. Table Value A two dimensional set of data represented as rows and columns. Each column has an associated name and default value and each row contains a value, possibly empty, for each column defined. Map Value A hashtable of key/value pairs. Although the number of record types is small, they are sufficient to transfer all of the output values that can be generated by standard Skipjack transactions. The transaction/map format is designed to be easily processed by client applications and/or read directly by humans for debugging purposes. Client applications that require different encoding schemes can be easily supported by creating a Velocity template that encodes the necessary transaction results as needed and then assigning that template to a custom MIME type in the responseMap for one or more transactions. See Transaction Response for more details. A transaction/map can be generated for any transaction simply by specifying that MIME type as the value of the contentType input parameter. For example, the following raw HTTP request:
GET /test/nop.tdf?contentType=transaction/map HTTP/1.0 Host: localhost:8080 Authorization: Basic YWRtaW46YWRtaW4=

executes the test/nop.tdf transaction, setting the contentType to transaction/map, causing the following server response to be generated:
K|input.contentType V|transaction%2Fmap K|tx.statusHistory L|0 K|tx.stopTime V|1019597119992 K|tx.startTime V|1019597119966

77 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

K|tx.respTime V|26 K|tx.status V|100+Transaction+Successful K|tx.clientID V|UNKNOWN K|tx.errorMsg V| K|tx.TXDIR V|%2Fhome%2Ftools%2Fskipjack%2Fapp%2FWEB-INF%2Ftransaction%2Ftest%2F K|tx.errorClass V| K|tx.identifier V|test%2Fnop K|tx.errorTrace V| K|tx.basename V|nop K|tx.actionTrace L|2 V|main V|TransMapResponse

See the navius.toolkit.format.TransactionMap class for details concerning the encoding scheme.

Skipjack Client Support


Although it is possible to access the Skipjack Server via the raw HTTP interface and process the output accordingly, in most applications it is more effective to use one of the Skipjack Client Packages to access the server. Each package provides a convenient set of methods for setting transaction parameters, executing one or more transactions and processing the results. For the most part, a client application need only create a transaction object, set the transaction input parameters, execute the transaction, and process transaction results as needed. The packages are implemented using the standard capabilities provided in the chosen language so that they can be readily added to any application. Java Client Package Client applications developed using Java can use the Skipjack Java Client Package to access the Skipjack Server. The Java Client Package provides complete control over the execution of transactions and the processing of results, using either the HTTP or HTTPS protocols. See Java Client Package for more details. In addition to synchronous transaction processing, the Java Client Package provides support for the asynchronous processing of Transaction Events generated by the Event Listening feature provided by the Skipjack Server. Perl Client Package Client applications developed using the Perl scripting language can use the Transaction.pm Perl module as an interface to the Skipjack Server. The Transaction.pm module allows Perl scripts to execute one or more transactions, process the results and generate status information through a single Perl object. The Perl Client Package supports both the HTTP and HTTPS protocols

78 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

when accessing the server. See Perl Client Package for more details. C++ Client Package Client applications developed using C++ can use the Skipjack C++ Client Package to access the Skipjack Server. The C++ Client Package provides complete control over the execution of transactions and the processing of results, using the HTTP protocol to access the server. See C++ Client Package for more details.

79 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Java Client Package
The Skipjack Server is an HTTP-based server that can be used to provide Web-services to client applications, other servers or users via a browser. In this section, we describe how to access the Skipjack Server using the Skipjack Java Client Package. The navius.skipjack.client.Transaction class implements a client-side mechanism for accessing the Skipjack Server. It insulates the client application from all HTTP request and response encoding and decoding issues, providing a easy-to-use mechanism that is similar to a Remote Procedure Call. The Transaction class is provided as part of the standard Skipjack Server release and is located in the $SKIPJACK/classes/navius/skipjack/client directory, where $SKIPJACK is the root directory for the Skipjack Server installation. For developers who don't have direct access to the Skipjack Server directory, the Transaction class is also provided as part of the Skipjack Client Package, located in the $CLIENT/lib/skipjack.jar JAR file, where $CLIENT is the root directory for the Skipjack Client Package. The Transaction object provides the following basic methods for managing transaction processing: Configuration
public void setAuthInfo (String authinfo)

Specifies the authentication information (in the form "username:password") to be used when submitting each transaction for execution. By default, no authentication information is provided.
public void setClientID (String clientID)

Specifies the client ID for this application, which is used in the Skipjack Server logs to determine the client that executed a given transaction. By default, a client ID based on the current process ID and the hostname is used.
public void setServerURL (String serverURL)

Specifies the base URL to be used when a relative URL is provided as an input parameter to the execute() method. By default, no server URL is defined.
public void debugEnable (boolean enabled)

80 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Enables/disables debug output generation for the Transaction object. Disabled by default.

Input Parameters

public void setParam (String key, String val)

Sets the value of the given input parameter


public String getParam (String key)

Returns the value of the given input parameter


public Hashtable getParamMap ()

Returns a hash table containing all of the input parameters that are currently defined

81 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Transaction Processing

public void execute (String url)

Executes the given transaction and processes all of the results returned. If a relative URL is given, then it will be prepended by the current base server URL as specified by the setServerURL() method. This method automatically clears all existing transaction results before executing the new transaction. After this method is called, the tx.status result will contain the transaction status, which should be checked by the client application before accessing any other results. If a transaction/map response is returned by the Skipjack Server, then all of the results will be automatically stored in the result map. Otherwise, the entire file returned by the Skipjack Server will be stored as a string in the respData result.

Results Processing

public Object getResultItem (String key)

Returns the value of the given result.


public String getResultString (String key)

Returns the value of the given result as a String.


public int getResultInt (String key)

Returns the value of the given result as an integer.


public Hashtable getResultMap ()

Returns a hash table containing all of the results that are currently defined.

Additional methods are supported for more advanced processing, as described in the Java API documentation for the Transaction class.

Basic Transaction Execution


The following code segment shows how a transaction can be executed using the Transaction object with only a few method calls:
import navius.skipjack.client.*; Transaction tx = new Transaction(); tx.setAuthInfo ("admin:admin");

82 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

tx.execute ("http://localhost:8080/test/nop.tdf"); int status = tx.getResultInt("tx.status"); if (status < 100 || status > 199) throw new Exception ( tx.getResultString("tx.status") + " - " + tx.getResultString("tx.errorMsg"));

In this case, the test/nop.tdf transaction is executed, using "admin:admin" to authenticate this client application. After the transaction is executed, the
tx.status

result is examined as an integer to determine if the transaction was successful. (By convention, status values between 100 and 199 inclusive are considered successful.) If not, the tx.status and tx.errorMsg results are used as strings to generate an exception message.

Specifying Input Parameters


For transactions that require input parameters or that generate results, the setParam() and getResultXXX() methods are used accordingly. For example, the following code segment:
import navius.skipjack.client.*; Transaction tx = new Transaction(); tx.setAuthInfo ("admin:admin"); tx.setClientID ("myClient"); tx.setParam ("message", "Hello World"); tx.execute ("http://localhost:8080/test/ping.tdf"); int status = tx.getResultInt("tx.status"); if (status < 100 || status > 199) throw new Exception ( tx.getResultString("tx.status") + " - " + tx.getResultString("tx.errorMsg")); System.out.println ("message = "+tx.getResultString("output.message"));

executes the test/ping.tdf which accepts the message input parameter, specified using the setParam() method, and returns the output.message result, which is accessed using the getResultString() method. In this example, the setClientID() method is used to specify a string that can be used to identify this client application in the server logs. If not specifically defined, a default client ID is generated based on the current process ID and host name.

Processing Results
5/11/2007 10:14 AM

83 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

In the following example, the sqlUtil/adhocSql transaction is executed to retrieve a table containing the names of all databases currently defined:
import navius.skipjack.client.*; import navius.skipjack.table.*; Transaction tx = new Transaction(); tx.setAuthInfo ("admin:admin"); tx.setClientID ("myClient"); tx.setParam ("sqlExpr", "show databases"); tx.execute ("http://localhost:8080/sqlUtil/adhocSql.tdf"); int status = tx.getResultInt("tx.status"); if (status < 100 || status > 199) throw new Exception ( tx.getResultString("tx.status") + " - " + tx.getResultString("tx.errorMsg")); Table tbl = (Table)tx.getResultItem("output.table"); for (int i=0; i<tbl.size(); i++) System.out.println (tbl.getValue(i,"Database"));

In this case, the sqlExpr input parameter is defined, as required by the sqlUtil/adhocSql transaction and the output.table result is accessed. Since database queries can return multiple rows and columns, the result is accessed using the getResultItem() method, which returns the object that is actually stored in the result map. In this case, it is known to be a Table object, so that result is cast accordingly and each value in the "Database" column of that table is printed.

84 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Result Content Type


By default, the Transaction object specifies a contentType of transaction/map so that the results of the transaction can be easily processed. If, however, a different output type is required, it can be easily specified using the setParam() method, as in the following example:
import navius.skipjack.client.*; Transaction tx = new Transaction(); tx.setAuthInfo ("admin:admin"); tx.setParam ("contentType", "text/html"); tx.execute ("http://localhost:8080/test/showTx.tdf"); int status = tx.getResultInt("tx.status"); if (status < 100 || status > 199) throw new Exception ( tx.getResultString("tx.status") + " - " + tx.getResultString("tx.errorMsg")); System.out.println (tx.getResultString("respData"));

In this case, the text/html content type is specified, which causes the entire output file generated by the server to be stored as the "respData" result. Note, the tx.status value can still be accessed to determine if the transaction was successful, but no other transaction output parameters will be available.

85 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Perl Client Package
The Skipjack Server is an HTTP-based server that can be used to provide Web-services to client applications, other servers or users via a browser. In this section, we describe how to access the Skipjack Server using the Skipjack Perl Client Package. Client applications that are developed using the Perl scripting language can make use of the Transaction.pm Perl module as a convenient interface to the Skipjack Server. The Transaction.pm module allows Perl scripts to easily specify one or more input parameters, execute one or more transactions, and process transaction results. Additionally, convenience methods exist to allow Perl client applications to append entries to the Skipjack Server error log and/or generate Skipjack Server Operator Console alarms or alerts. The Transaction.pm module is provided as part of the standard Skipjack Server installation and is located in the $SKIPJACK/lib directory, where $SKIPJACK is the root directory for the Skipjack Server. For developers who don't have direct access to the Skipjack Server directories, the Transaction.pm module is also included in the Skipjack Client Package and is located in the $CLIENT/lib directory, where $CLIENT is the root directory of the Skipjack Client Package. The Transaction.pm module depends on the wget-1.8.1 public-domain utility for communication with the server, using either the HTTP or HTTPS protocols. Accordingly, a wget executable suitable for RedHat 7.1 is provided as part of the Skipjack Server Package, located in the $SKIPJACK/bin directory, and as part of the Skipjack Client Package, located in the $CLIENT/bin directory. If a more recent version of wget is installed on the system or a different operating system is being used, those executables should be replaced accordingly. The Transaction.pm module provides the following basic methods for managing transaction processing: Configuration
$tx = new Transaction()

Creates a new Transaction object and returns a reference to it


$tx->setSkipjackRoot (path)

Specifies the root directory for the Skipjack Server or Skipjack Client Package where the wget executable can be found. Default is "/tools/skipjack".
$tx->setAuthInfo (authinfo)

86 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Specifies the authentication information (in the form "username:password") to be used when submitting each transaction for execution. By default, no authentication information is provided.
$tx->setClientID (clientID)

Specifies the client ID for this application, which is used in the Skipjack Server logs to determine the client that executed a given transaction. By default, a client ID based on the current process ID and the hostname is used.
$tx->setServerURL (url)

Specifies the base URL to be used when a relative URL is provided as an input parameter to the execute() method. By default, "http://localhost:8080" is used.
$tx->debugEnable (enabled)

Enables/disables debug output generation for the Transaction object. Disabled by default.

87 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Input Parameters

$tx->setParam (key, val)

Sets the value of the given input parameter


$tx->getParam (key)

Returns the value of the given input parameter


$tx->clearParam (key)

Clears the given input parameter (ie. makes it undefined)


$tx->getParamMap ()

Returns an associative array containing all of the input parameters that are currently defined

Transaction Processing

$tx->execute (url)

Executes the given transaction and processes all of the results returned. If a relative URL is given, then it will be prepended by the current base server URL as specified by the setServerURL() method. This method automatically clears all existing transaction results before executing the new transaction. After this method is called, the tx.status result will contain the transaction status, which should be checked by the client application before accessing any other results. If a transaction/map response is returned by the Skipjack Server, then all of the results will be automatically stored in the result map. Otherwise, the entire file returned by the Skipjack Server will be stored as a string in the respData result.

Results Processing

$tx->setResult (key, type, val)

Sets the type and value of the given result. This method is called automatically by the execute() method whenever a transaction/map response is returned by the Skipjack Server.
$tx->getResult (key)

Returns the value of the given result.


$tx->getResultType (key)

Returns the data type of the given result (V=value, L=list, T=table). The result type can be used to determine how the result should be processed by the client.

88 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

$tx->getResultMap ()

Returns an associative array containing all of the results that are currently defined.
$tx->printAllResults (FILE)

Prints all results to the given FILE descriptor.


$tx->printResult (FILE, key)

Prints the given result to the given FILE descriptor.

Client Status

$tx->log (severity, msg)

Sends the given message to the Skipjack Server log based on the given severity (ERROR, WARNING, INFO, DEBUG)
$tx->alarm (severity, gid, eid, tid, code, msg)

Generates an alarm or alert on the Skipjack Server with the given information. The severity may be ALARM or ALERT.

89 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Basic Transaction Execution


The following code segment shows how a transaction can be executed using the Transaction object with only a few method calls:
# # PerlClient-ex1.txt # $SKIPJACK_ROOT = "/tools/skipjack"; require "$SKIPJACK_ROOT/lib/Transaction.pm"; $tx = new Transaction(); $tx->setSkipjackRoot ($SKIPJACK_ROOT); $tx->setAuthInfo ("admin:admin"); $tx->execute ("http://localhost:8080/test/nop.tdf"); $status = $tx->getResult("tx.status"); if ($status ne "100 Transaction Successful") { print "STATUS: $status\n"; print "ERROR: ",$tx->getResult("tx.errorMsg"),"\n"; exit -1; }

In this case, the test/nop.tdf transaction is executed, using "admin:admin" to authenticate this client application. After the transaction is executed, the tx.status result is examined to determine if the transaction was successful. If not, the tx.status and tx.errorMsg results are used to generate an error message. In this example, the $SKIPJACK_ROOT variable is used to specify the location of the Transaction.pm module in the Perl require statement (which loads the named module) and the setSkipjackRoot() method (which specifies the location of the wget executable). The pathname specified for $SKIPJACK_ROOT should be either the Skipjack Server root directory or the Skipjack Client root directory, depending on which packages are installed on the same machine as the Perl client application. In both cases, the Transaction.pm module is located in the lib subdirectory and the wget executable is located in the bin subdirectory.

Scripts Executed By The Skipjack Server


If a Perl client script is being executed directly the Skipjack Server (usually via the ShellAction or ShellResponse actions) then most of the configuration settings are automatically handled by the Skipjack Server and the Transaction.pm module. Specifically, the following conveniences are provided: the Perl environment is automatically configured to search the Skipjack Server lib directory for the Transaction.pm, the Skipjack Server root directory is used to locate the wget executable,
5/11/2007 10:14 AM

90 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

the Skipjack Server URL is used as the default serverURL for all transactions that are specified using relative transaction names, and the authentication information for the user who executed the transaction that executed the current script is used as the default authentication information for any transactions executed by this script. As a result of these conveniences, if the previous script example were executed directly by the Skipjack Server it could be written as follows:
# # PerlClient-ex2.txt # require "Transaction.pm"; $tx = new Transaction(); $tx->execute ("test/nop.tdf"); $status = $tx->getResult("tx.status"); if ($status ne "100 Transaction Successful") { print "STATUS: $status\n"; print "ERROR: ",$tx->getResult("tx.errorMsg"),"\n"; exit -1; }

Note how the require statement and the execute() method make use of relative names, and that no other configuration methods need to be called before executing the transaction.

Specifying Input Parameters


For transactions that require input parameters or that generate results, the setParam() and getResult() methods are used accordingly. For example, the following code segment:
# # PerlClient-ex3.txt # $SKIPJACK_ROOT = "/tools/skipjack"; require "$SKIPJACK_ROOT/lib/Transaction.pm"; $tx = new Transaction(); $tx->setSkipjackRoot ($SKIPJACK_ROOT); $tx->setAuthInfo ("admin:admin"); $tx->setClientID ("myClient"); $tx->setParam ("message", "Hello World"); $tx->execute ("http://localhost:8080/test/ping.tdf"); $status = $tx->getResult("tx.status");

91 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

if ($status ne "100 Transaction Successful") { print "STATUS: $status\n"; print "ERROR: ",$tx->getResult("tx.errorMsg"),"\n"; exit -1; } print "message = ",$tx->getResult("output.message"),"\n";

executes the test/ping.tdf which accepts the message input parameter, specified using the setParam() method, and returns the output.message result, which is accessed using the getResult() method. In this example, the setClientID() method is used to specify a string that can be used to identify this client application in the server logs. If not specifically defined, a default client ID is generated based on the current process ID and host name.

Processing Results
In the following example, the sqlUtil/adhocSql transaction is executed to retrieve a table containing the names of all databases currently defined:
# # PerlClient-ex4.txt # $SKIPJACK_ROOT = "/tools/skipjack"; require "$SKIPJACK_ROOT/lib/Transaction.pm"; $tx = new Transaction(); $tx->setSkipjackRoot ($SKIPJACK_ROOT); $tx->setAuthInfo ("admin:admin"); $tx->setClientID ("myClient"); $tx->setParam ("sqlExpr", "show databases"); $tx->execute ("http://localhost:8080/sqlUtil/adhocSql.tdf"); $status = $tx->getResult("tx.status"); if ($status ne "100 Transaction Successful") { print "STATUS: $status\n"; print "ERROR: ",$tx->getResult("tx.errorMsg"),"\n"; exit -1; } print "Database List\n"; print "-------------\n"; @rows = @{$tx->getResult("output.table")}; foreach $row (@rows) { %row = %{$row}; print $row{"Database"},"\n"; }

In this case, the sqlExpr input parameter is defined, as required by the sqlUtil/adhocSql transaction and the output.table result is accessed. Since database queries can return a table of results, the result is referenced as an array of table rows. Each table row is implemented as an associative array, using
5/11/2007 10:14 AM

92 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

the name of each table column as the key. The last loop in the example iterates over all rows, printing the value of the "Database" column, which is a known result column for the given query. The printAllResults() and printResult() methods can be used to print all currently defined results or a given result for debug purposes.

Result Content Type


By default, the Transaction.pm module specifies a contentType of transaction/map so that the results of the transaction can be easily processed. If, however, a different output type is required, it can be easily specified using the setParam() method, as in the following example:
# # PerlClient-ex5.txt # $SKIPJACK_ROOT = "/tools/skipjack"; require "$SKIPJACK_ROOT/lib/Transaction.pm"; $tx = new Transaction(); $tx->setSkipjackRoot ($SKIPJACK_ROOT); $tx->setAuthInfo ("admin:admin"); $tx->setParam ("contentType", "text/html"); $tx->execute ("http://localhost:8080/test/showTx.tdf"); $status = $tx->getResult("tx.status"); if ($status ne "100 Transaction Successful") { print "STATUS: $status\n"; print "ERROR: ",$tx->getResult("tx.errorMsg"),"\n"; exit -1; } print $tx->getResult("respData");

In this case, the text/html content type is specified, which causes the entire output file generated by the server to be stored as the "respData" result. Note, the tx.status value can still be accessed to determine if the transaction was successful, but no other transaction output parameters will be available.

93 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


C++ Client Package
The Skipjack Server is an HTTP-based server that can be used to provide Web-services to client applications, other servers or users via a browser. In this section, we describe how to access the Skipjack Server using the Skipjack C++ Client Package. The C++ Transaction class implements a client-side mechanism for accessing the Skipjack Server. It insulates the client application from all HTTP request and response encoding and decoding issues, providing a easy-to-use mechanism that is similar to a Remote Procedure Call. The Transaction class is provided as part of the Skipjack Client Package, located in the $CLIENT/lib/libTransaction.a library file, where $CLIENT is the root directory for the Skipjack Client Package. The associated header definition files are located in the $CLIENT/include directory and the source files for all of the library classes are located in the $CLIENT/src directory. The Transaction object provides the following basic methods for managing transaction processing: Configuration
void setAuthInfo (const char *authinfo)

Specifies the authentication information (in the form "username:password") to be used when submitting each transaction for execution. By default, no authentication information is provided.
void setClientID (const char *clientID)

Specifies the client ID for this application, which is used in the Skipjack Server logs to determine the client that executed a given transaction. By default, a client ID based on the current process ID and the hostname is used.
void debugEnable (int enabled)

Enables/disables debug output generation for the Transaction object. Disabled by default.

Input Parameters

void setParam (const char *key, const char *val)

94 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Sets the value of the given input parameter.


const char *getParam (const char *key)

Returns the value of the given input parameter.


TransactionMap *getParamMap ()

Returns a TransactionMap object containing all of the input parameters that are currently defined. The keys(), set(), and get() methods of the TransactionMap object can be used to process specific parameters contained in the map.

Transaction Processing

void execute (const char *url)

Executes the given transaction and processes all of the results returned. This method automatically clears all existing transaction results before executing the new transaction. After this method is called, the tx.status result will contain the transaction status, which should be checked by the client application before accessing any other results. If a transaction/map response is returned by the Skipjack Server, then all of the results will be automatically stored in the result map. Otherwise, the entire file returned by the Skipjack Server will be stored as a string in the respData result.

95 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Results Processing

TransactionItem *getResultItem (const char *key)

Returns the value of the given result as a TransactionItem (single string value), TransactionList (list of values) or TransactionTable (table of values).
const char *getResultString (const char *key)

Returns the value of the given result as a String, automatically converting single values, list values and table values to a string.
int getResultInt (const char *key)

Returns the value of the given result as an integer, if possible.


TransactionMap *getResultMap ()

Returns a TransactionMap object containing all of the results that are currently defined. The keys(), set(), and get() methods of the TransactionMap object can be used to process specific parameters contained in the map.

Basic Transaction Execution


The following code segment shows how a transaction can be executed using the Transaction object with only a few method calls:
#include "Transaction.hh" try { Transaction *tx = new Transaction(); tx->setAuthInfo ("admin:admin"); tx->execute ("http://localhost:8080/test/nop.tdf"); int txStatus = tx->getResultInt ("tx.status"); if (txStatus < 100 || txStatus > 199) tx->error ("Tx Failure: %s\n%s\n", tx->getResultString("tx.status"), tx->getResultString("tx.errorMsg")); delete tx; } catch (TransactionException ex) { printf ("ERROR: %s\n", ex.getMessage()); exit (-1); }

In this case, the test/nop.tdf transaction is executed, using "admin:admin" to authenticate this client application. After the transaction is executed, the

96 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

result is examined as an integer value to determine if the transaction was successful. (By convention, tx.status values between 100 and 199 inclusive are considered successful.) If the status is not succesful, then an exception is thrown and the application exits.
tx.status

97 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Specifying Input Parameters


For transactions that require input parameters or that generate results, the setParam() and getResultXXX() methods are used accordingly. For example, the following code segment:
#include "Transaction.hh" try { Transaction *tx = new Transaction(); tx->setAuthInfo ("admin:admin"); tx->setClientID ("myClient"); tx->setParam ("message", "Hello World"); tx->execute ("http://localhost:8080/test/ping.tdf"); int txStatus = tx->getResultInt ("tx.status"); if (txStatus < 100 || txStatus > 199) tx->error ("Tx Failure: %s\n%s\n", tx->getResultString("tx.status"), tx->getResultString("tx.errorMsg")); printf ("message = %s\n", tx->getResultString("output.message")); delete tx; } catch (TransactionException ex) { printf ("ERROR: %s\n", ex.getMessage()); exit (-1); }

executes the test/ping.tdf which accepts the message input parameter, specified using the setParam() method, and returns the output.message result, which is accessed using the getResultString() method. In this example, the setClientID() method is used to specify a string that can be used to identify this client application in the server logs. If not specifically defined, a default client ID is generated based on the current process ID and host name.

Processing Results
In the following example, the sqlUtil/adhocSql transaction is executed to retrieve a table containing the names of all databases currently defined:
#include "Transaction.hh" #include "TransactionTable.hh" try { Transaction *tx = new Transaction(); TransactionTable *tbl;

98 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

int

rowCount, i;

tx->setAuthInfo ("admin:admin"); tx->setClientID ("myClient"); tx->setParam ("sqlExpr", "show databases"); tx->execute ("http://localhost:8080/sqlUtil/adhocSql.tdf"); int txStatus = tx->getResultInt ("tx.status"); if (txStatus < 100 || txStatus > 199) tx->error ("Tx Failure: %s\n%s\n", tx->getResultString("tx.status"), tx->getResultString("tx.errorMsg")); printf ("Database List\n"); printf ("-------------\n"); tbl = (TransactionTable *) tx->getResultItem ("output.table"); rowCount = tbl->getRowCount(); for (i=0; i < rowCount; i++) { printf ("%s\n", tbl->getValue(i,"Database")); } delete tx; } catch (TransactionException ex) { printf ("ERROR: %s\n", ex.getMessage()); exit (-1); }

In this case, the sqlExpr input parameter is defined, as required by the sqlUtil/adhocSql transaction and the output.table result is accessed. Since database queries can return multiple rows and columns, the result is accessed using the getResultItem() method, which returns the object for the output.table result. In this case, it is known to be a TransactionTable object, so that result is cast accordingly and each value in the "Database" column of that table is printed.

Result Content Type


By default, the Transaction object specifies a contentType of transaction/map so that the results of the transaction can be easily processed. If, however, a different output type is required, it can be easily specified using the setParam() method, as in the following example:
#include "Transaction.hh" try { Transaction *tx = new Transaction(); tx->setAuthInfo ("admin:admin"); tx->setClientID ("myClient"); tx->setParam ("contentType", "text/html");

99 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

tx->execute ("http://localhost:8080/test/showTx.tdf"); int txStatus = tx->getResultInt ("tx.status"); if (txStatus < 100 || txStatus > 199) tx->error ("Tx Failure: %s\n%s\n", tx->getResultString("tx.status"), tx->getResultString("tx.errorMsg")); printf ("%s", tx->getResultString("respData")); delete tx; } catch (TransactionException ex) { printf ("ERROR: %s\n", ex.getMessage()); exit (-1); }

In this case, the text/html content type is specified, which causes the entire output file generated by the server to be stored as the respData result. Note, the tx.status value can still be accessed to determine if the transaction was successful, but no other transaction output parameters will be available.

100 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 11: Event Listening
Skipjack Server provides a low-level mechanism, called Event Listening, that allows applications to easily monitor and/or react to the activity of one or more transactions. This capability can be used to support a wide range of system requirements, such as system monitoring applications, automated decision making, and adhoc reporting, to name a few.

Event Listening Process


The event listening process is performed by the Event Manager component as depicted by the following diagram:

The process begins with the Event Listener registering itself with the Event Manager (step 1), providing a Filter Criteria, an optional Event Handler Transaction and an optional Delivery Address. If a Delivery Address is specified, then the Event Listener waits to receive one or more Transaction Events from the Event Manager as they are processed. In normal operation, a Transaction Client submits a Transaction Request to the Transaction Servlet (step 2) and a Transaction Response is returned to the Transaction Client (step 3), allowing the Transaction Client to continue processing. Regardless of the number of Transaction Listeners registered for a given transaction, the transaction will be processed entirely and a response returned to the Transaction Client before any listener processing is begun. If the transaction was successful (as indicated by a status code of the form '1xx'), then the Transaction State is sent to the Event Manager for subsequent processing (step 4). The Transaction State consists of all TDF item attributes defined at the time that the transaction was completed.

101 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

For each Transaction State received, the Event Manager compares the transaction identifer to the Filter Criteria defined for each Transaction Listener that is currently registered. For each match found, an Event Worker thread is launched to process the event on behalf of the Event Listener. A fixed number of Event Worker threads are created when the Event Manager is initialized and are used on a first-come-first-served basis to process events on behalf of Event Listeners. If an Event Handler Transaction was specified when the Event Listener was registered, then it is executed by the Event Worker in order to process the event. The Event Handler Transaction can perform whatever processing is necessary based on the contents of the event, as will be discussed below. After the Event Handler Transaction has been processed, the Event Worker delivers the event to the Event Listener (step 5). The delivery mechanism, address and format are all specified by the Event Listener at registration time. At that point, the Event Listener application can perform additional processing as needed based on the event information. Unsuccessful transactions may also be delivered to the listener as needed by setting the ReceiveFailures parameter to "true" when registering the listener. That allows applications to monitor and optionally react to failure conditions for critical transactions.

Listener Registration
The eventMgr/add-listener.tdf transaction is used to register an event listener with the Event Manager, with the following input parameters supported: TxFilter GNU regular expression that is compared against the transction identifier to determine if the transaction event should be processed. TxName Optional name of the Event Handler Transaction to be executed when an event is processed. If no TxName attribute is defined, or it is the empty string, then no event handler transaction processing is performed. TxInput<XXXX> Optional input parameter for the Event Handler Transaction, which is used to define the input.<XXXX> attribute when the Event Handler Transaction is executed (i.e., the leading "TxInput" prefix is stripped). Any number of Event Handler Transaction input parameters can be specified by changing the value of <XXXX>.

102 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

AddrType Specifies the delivery mechanism to be used to send the event to the Event Listener application, with the following types supported: TCP (default) PROXY NONE The specific processing performed for each address type is described below. Host If AddrType is 'TCP' or 'PROXY', this attribute specifies the TCP host name or IP address at which the Event Listener resides. Port If AddrType is 'TCP', this attribute specifies the TCP port number to at which the Event Listener is waiting. MaxWait If AddrType is 'PROXY', this attribute specifies the maxium time that the Event Worker will wait for the Transaction Listener to connect before closing the server socket. OutputType, OutputFormat MIME type that indicates the output format of the Transaction Event sent to this listener, with the following values supported: transaction/map (default) template/file template/string The specific processing performed for each output type is described below. RemoveOnFailure If "true", then the Listener Registration will be deleted whenever the Event Manager fails to properly deliver a Transaction Event. Normally, such a failure indicates that the Event Listener application has been halted, so there is little reason to try again with subsequent events. The default value is "true". RemoveOnRestart If "true", then the Listener Registration will not be stored in the database and will not be automatically re-loaded when the server restarts. Normally, this is used by Event Listener applications that are automatically restarted when the Skipjack Server restarts (such as the internal Process Manager). The default value is "true". ReceiveFromSelf If "true", then the Event Listener application will receive Transaction Events that were originated from the same application, as

103 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

determined by the ClientID. The default value is "false". ReceiveFailures If "true", then the Event Listener application will receive Transaction Events for all transactions that match the filter criteria, even if they have an unsuccessful status. The default value is "false".

If the registration transaction is successful, a unique ListenerID is returned to the Event Listener application as the output.ListenerID attribute, which can be used to track the registration information while viewing the Event Monitor, Event Table, or Event Log.

Event Handler Transactions


An Event Handler Transaction can be specified for any Event Listener using the TxName input parameter of the eventMgr/add-listener.tdf transaction. Other than a small set of internal limitations (as noted below), event handler transactions can be written to perform a wide range of processing tasks. For example, if detailed, application-level logging is required, an event handler transaction can be registered that listens for all of the key application transaction events. For each event processed, the event handler transaction can extract the key information (possibly pulling additional data from the database or other data structures) and generate an appropriate log record in the database or append the information to a file. Alternately, the event handler transaction can be written to determine if a "critical" event has occurred, sending an email notification to a list of subscribers defined in the database. Finally, an event handler transaction may be written to summarize processing at various intervals or whenever a given limit is reached.

Event Items
Prior to executing the event handler transaction, the following items are copied from the event being processed into the event handler transaction: Event Item Handler Item request input output tx eventRequest eventInput eventOutput eventTx

This allows the event handler transaction to reference all of the key state values from the original event as needed. For example, the event handler transaction may want to use the output and transaction status values of the event as input values, as in the following "input" item definition:

104 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

item input { status myX myY }

= eventTx.status; = eventOutput.X; = eventOutput.Y;

or they can be referenced directly in any attribute expression as needed, as in the following action definition:
item summarizeAsNeeded extends BaseAction { actions = eventOutput.X > 10 && eventOutput.Y > 20 ? ["doSummary"] : []; }

Finally, the event item attributes can be referenced directly by a Velocity template in order to generate a custom SQL expression or a detailed message that is emailed to someone, to name a few examples.

Event Handler Input Parameters


In addition to the event items described above, the event handler transaction can use it's own set of input parameters to control processing. Input parameters for the event handler transaction are specified when the event handler is registered using the add-listener transaction. Specifically, any input parameter defined for the add-listener transaction of the form TxInputXXXX will be provided to the event handler transaction as the input.XXXX attribute whenever it is executed. For example, if the add-listener transaction is executed with the following input parameters:
TxFilter TxName TxInputMode TxInputErrorCode AddrType ReceiveFailures = = = = = = ".*" "eventMgr/handler/genAlarm.tdf" "ONFAILURE" "s915" "NONE" "true"

then the genAlarm transaction will be executed for every transaction event, with the following input parameters:
Mode = "ONFAILURE" ErrorCode = "s915"

In this case, the genAlarm transaction processes only failed transaction events based on the Mode input parameter and uses an error code of "s915" whenever an alarm is generated based on the ErrorCode input parameter. The exact number and meaning of event handler transaction input parameters depends on the implementation of each event handler transaction. Generally, event handler transactions should be designed to use default values for all expected inputs, but the client application is ultimately responsible for specifying the appropriate event

105 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

handler input parameters for the process being performed.

Event Handler Processing Context


When the event handler transaction is executed by the Event Manager, it will be executed using the Client ID, Username and Password that were provided when the event handler transaction was registered. This allows more-privileged users to register event handler transactions that process transaction events generated by less-privileged users. For example, a "Supervisor" level event handler transaction may be registered to approve a specific change after two other "Operator" level transactions have been executed. Since event handler transactions are executed directly by the Event Manager, there are no HTTP request or response objects associated with them. Consequently, when the event handler transaction is executed, the "request" and "response" items that are normally defined for every transaction will only contain a subset of the normal request and response information. Specifically, the "request" item will contain a copy of the attributes from the HTTP request the generated the transaction event, except for the user related properties as stated above. Since no HTTP response is associated with an event handler transaction, no transaction response (either template-based or action-based) is generated for the event handler transaction. Any error generated by the transaction will be recorded by the Transaction Manager in the trans.log log file and by the Event Manager in the event.log log file. Event Listeners that need to generate output should either do so directly by executing an appropriate action in the Event Handler Transaction (e.g., ShellAction, LogAction, DeliveryAction, etc.) or specify an appropriate delivery address and format in the listener registration.

Event Handler Initialization


It is often desirable to register one or more event handler transactions when the Skipjack Server is started, allowing them to process all events generated while the server is running. This can be easily accomplished using the mechanism provided by the Process Manager.

Event Delivery
Independent of any Event Handler Transaction processing performed for a given event, the event can be delivered to a user or client application at a given address specified using the AddrType input parameters of the eventMgr/add-listener.tdf transaction. The AddrType parameter defines the type of delivery mechanism to be used and other address-specific parameters are used to define the delivery address itself.

TCP Event Delivery

106 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

When the 'TCP' address type is specified in a listener registration, the Event Worker will attempt to connect to a given IP address and port in order to deliver the event, based on the Host and Port registration parameters. If a successful connection is made, the Event Worker will format the event based on the OutputType and OutputFormat attributes and will send the resulting output stream to the Event Listener via the connection. After the output has been sent, the Event Worker shuts down the TCP connection. If an error occurs at any time during the delivery process, the RemoveOnFailure is used to determine if the listener registration should be retained or removed.

PROXY Event Delivery


There are times when the 'connection-per-event' approach used for 'TCP' delivery is not appropriate, either because of excessive network overhead caused by too many connections or because security constraints prevent the server from connecting to the client (which is the case for Java applets running inside of a browser). To support these situations, the 'PROXY' address type can be used to create a Proxy Listener that resides on the server and maintains a single open connection to the client, over which all Transaction Events are sent, as depicted by the following diagram:

When the eventMgr/add-listener.tdf transaction is executed, it creates a new server thread, called the Proxy Listener, that opens a TCP Server Socket and stores the corresponding port in the Transaction Response that is returned for the add-listener.tdf transaction. The Proxy Listener then waits for a connection from the Transaction Listener application (the reverse of the approach described above). When the Proxy Listener receives a Transaction Event for delivery from an Event Worker, it relays it to the Event Listener application over the open connection. When registering a proxy listener, the MaxWait parameter can be used to specify the maximum time period in seconds that the Proxy Listener will wait for a connection from the Event Listener before aborting the process.

Custom Event Delivery

107 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The TxFilter parameter provides the basic mechanism for specifying by name the transaction events that are desired by a given listener. However, in addition to that filtering, an event handler transaction can be used for customized or more advanced event transaction filtering. Specifically, if the event handler transaction determines that the given event should not be delivered to the listener, then it need only set the tx.abortEvent attribute to true to abort event delivery. For example, the following event handler transaction aborts delivery if the user who generated the transaction event is not "fred":
item abortEvent extends preCondition = _destItem = abortEvent = } ComputeAction { eventRequest.RemoteUser != "fred"; "tx"; true;

item main extends BaseAction { actions = ["abortEvent"]; }

In this case, a preCondition is used to determine if the tx.abortEvent flag should be set to true to abort delivery of the event. Alternatively, the event handler transaction can simply throw an error, using an ErrorAction or main.preErrorCheck, which will also abort event delivery, as in the following example:
item main extends NOP { preErrorCheck = [ (eventRequest.RemoteUser != "fred", guiStatus.InvalidParameter, "The Event Was Not Generated By Fred") ]; }

The only difference between this approach and the previous one is that the error is appended to the event log, whereas the use of the tx.abortEvent flag aborts the event delivery without recording any log information.

Event Formatting
Whenever an event is delivered to an Event Listener, the Event Worker formats the event in the manner specified by the OutputType and OutputFormat attributes defined in the listener registration. This allows different applications to receive the same event in whatever format is convenient for that application. If the OutputType is 'template/map', then the "input", "output", and "tx" event items will be encoded using the TransMapResponse class, which generates an ASCII encoding of scalar values, lists and tables. This is useful for applications that want to perform additional processing based on the transaction item

108 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

attributes and are using one of the Skipjack Client libraries discussed below. If the OutputType is 'template/file', then the OutputFormat attribute is interpreted as the name of a Velocity template which is used to format the Transaction Event output stream. This is commonly used by applications that are generating event reports or that require a standard output format. If the OutputType is 'template/string', then the OutputFormat attribute is processed directly by Velocity as the template expression used to format the Transaction Event output stream. This allows applications to specify custom event formatting templates. If an Event Handler Transaction is specified for a given listener then the "input", "output", and "tx" items of the Event Handler Transaction are used for output formatting, not the corresponding items from the original transaction event. This allows Event Handler Transactions to generate appropriate values as needed. If the items from the original event are required for output formatting, then either the output template should referenced the "eventInput", "eventOutput" and "eventTx" items or the Event Handler Transaction should copy the necessary item attributes into its own "input", "output" and/or "tx" items.

Removing Listener Registrations


The following transactions are provided to remove one or more event listener registrations associated with a given Event Listener: eventMgr/remove-listener.tdf Removes all registrations that are associated with the current clientID and that match the given filter criteria and delivery address. eventMgr/remove-client.tdf Removes all registrations that are associated with the current clientID. Normally, this transaction is executed when the Event Listener is being terminated, cleanly removing all associated registrations.

Note, in all cases, the clientID associated with the Event Listener application is used to identify the corresponding listeners. Therefore, it is important for applications to use the same clientID when adding and removing listeners. By default, the Java, Perl and C++ Client Packages adhere to this approach.

Java Event Listener Support

109 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The TransactionMonitor class (provided as part of the Java Client Package) implements a background thread that monitors transactions executed by the Skipjack Server and supports a collection of methods that allow client applications to easily register event listeners and process events as they are received. When a Transaction Event is received by the TransactionMonitor it is automatically converted into a Transaction object and passed to one or more TransactionObserver objects that have been registered with the TransactionMonitor. The TransactionMonitor object isolates the client application from all of the network and encoding tasks required to monitor one or more transactions executed on a given Skipjack Server. For example, the following Java application uses the TransactionMonitor to print the transaction identifier for every transaction that is executed for a period of two minutes.
import navius.skipjack.client.*; import navius.toolkit.util.*; import org.apache.log4j.*; public class SimpleMonitor implements TransactionObserver { public void transactionCompleted (Transaction tx) { System.out.println ("Tx = "+tx.getResultString("tx.identifier")); } public static void main (String[] args) { try { BasicConfigurator.configure(); TransactionMonitor tm = new TransactionMonitor ("tm.cfg"); SimpleMonitor sm = new SimpleMonitor(); tm.addObserver (sm); tm.start(); tm.addEventRequest (".*"); Thread.sleep(120000); } catch (Exception e) { e.printStackTrace(); } } } // End of Class

The main method begins by initializing the Log4j properties using the BasicConfigurator, which is used internally by the TransactionMonitor for debug generation. It then creates a TransactionMonitor object, based on the "tm.cfg" configuration file, which is defined as follows:
_debugEnabled: _transMapDebug: _serverURL: _authInfo: _clientID: _useProxy: false false http://localhost:8080/ test:PASSWORD test.SM false

110 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

RemoveOnRestart: RemoveOnFailure: ReceiveFromSelf:

true true true

The "tm.cfg" file specifies the server to be monitored, along with the authentication information needed. It also defines the listener registration parameters that are used when each addEventRequest() method is executed. The SimpleMonitor class implements the TransactionObserver interface, which allows it to be added as an observer of the TransactionMonitor object. In this case, it simply prints the transaction identifier when each transaction event is received.

C++ Event Listener Support


The C++ Client Package does not provide a TransactionMonitor class similar to that provided by the Java Client Package. Therefore, if C++ client applications need to listen to transaction events, they must create their own TCP socket to receive those events and manage them accordingly. However, once a connection has been made to the TCP socket, the client can execute the Transaction::loadResultMap() method to process the transaction/map data stream that is sent for every transaction event. The loadResultMap() method accepts a file/socket descriptor and reads in all of the data until the end of the file or the end of the transaction/map data is found. After the loadResultMap() method has completed, the client application can access any or all of the results defined for the received transaction event using the getResultXXX() methods. The loadResultMap() method does not automatically clear the result map prior to processing the new results. This allows it to be used to accumulate results from multiple transaction events as needed. If the client application does not want the results from different transaction events to be merged, it should clear the result map before calling the loadResultMap() method.

Event Monitor Java Applet


The eventMgr/event-monitor.tdf transaction executes a Java applet in the browser that displays event information based on a set of user configurable parameters. By default, it listens for all events and uses the eventMgr/event-summary.vm template to display a line of information for each event received. The Event Monitor is based on the TransactionApplet class which provides a convenient mechanism for generating a scrolling output list based on transaction events. The Event Monitor uses the template formatting feature supported by the Event Manager to format the event information on the server, allowing the TransactionApplet to simply copy the output received into a text display. This keeps the client code relatively simple, while still providing flexible formatting.

Event Table HTML Display


5/11/2007 10:14 AM

111 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The eventMgr/show-table.tdf transaction can be used to display the current contents of the Event Listener Table in a browser for trouble-shooting purposes. The display shows the ListenerID, ClientID, Address and Criteria associated with each active listener.

Event Log File


The Event Manager generates log information that is stored in the $SKIPJACK_HOME/logs/event.log. The event log shows listener registration activities, event processing activities and proxy activities based on the debug settings defined in the Event Manager Configuration File.

Event Manager Configuration File


The $SKIPJACK_HOME/app/WEB-INF/event.cfg configuration controls various aspects of the Event Manager, including debug generation, thread activity and the database table and fields used to store listener registrations. By default, most debug output is disabled.

112 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 12: Process Manager
The Process Manager is an internal component of the Skipjack Server that performs a set of functions primarily concerned with initializing server applications and managing background threads created for various purposes. Specifically, the Process Manager provides the following services: registers Transaction Event Handlers for one or more applications when the server is started, executes Startup Transactions for one or more applications when the server is started, maintains a server-wide Process Table that can be used to monitor and/or terminate background server threads.

Process Definition Files


The Process Manager is responsible for performing all application-specific startup processing whenever the Skipjack Server is started. This provides a convenient mechanism for all application initialization and a single point of control for server initialization. The Process Manager determines the startup processing to be performed by processing all of the Process Definition Files found in a directory specified in the Process Manager's configuration file (see Process Manager Configuration below for configuration details). Each Process Definition File can specify one or more of the following types of items: Event Handler Items Transaction Items to define the startup processing needed by a given application. Usually, a single Process Definition File suffices for a given application, but any number of Process Definition Files can be specified for a given application or group of applications, and each Process Definition File can define any number of event handler transactions. No restrictions are placed on the specific distribution of event handler definitions across the collection of Process Definition Files, allowing application developers to organize them as needed.

Event Handler Items


As described in the Event Listening section, one or more Event Handler Transactions can be registered to process a given set of transaction events. Event

113 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

handler transactions can be used for a wide range of application purposes, including application-level logging, database maintenance, operator notification, and application process constraints, to name a few. In many cases, such event handler transactions need to be registered when the Skipjack Server is started, thereby allowing them to process all transaction events whenever the server is running. This is easily done by specifying one or more Event Handler Items in a Process Definition File. Each Process Definition File can define one or more Event Handler Items that are referenced by name in the main.processList attribute. For every item name found in that list, the Process Manager will register a Transaction Event Handler using the eventMgr/add-listener.tdf transaction based on the attributes defined in the Event Handler Item. That is, each event handler is specified as an item that defines a set of input parameters for the eventMgr/add-listener.tdf transaction, with the following attributes supported: Attribute
TxFilter

Description Defines one or more GNU regular expressions that are applied to the transaction identifier of each transaction event. If a match is found, the event listener is executed for that transaction. If defined, this attribute specifies the event handler transaction to be executed whenever an event is processed. See the EventHandler class for more details. If defined, this attribute specifies the address to which the event should be sent. If the AddrType attribute is not defined, it will be set to "NONE". See the EventAddress class for more details. If the _clientID attribute is defined, it will be used as the client ID when the event handler transaction is registered and subsequently executed. Otherwise, the default client ID specified in the process.cfg configuration file will be used. If the _authInfo attribute is defined, it will be used as the username and password when the event handler transaction is registered and subsequently executed. Otherwise, the default authentication information specified in the process.cfg configuration file will be used. All attributes defined in the item that do not start with an underscore are copied into the input item when the eventMgr/add-listener.tdf transaction is executed, allowing arbitrary parameters to be passed to that transaction.

TxName

AddrType

_clientID

_authInfo

Other Attributes

For example, the following Process Definition File defines two process items, which specify a total of five event handler transactions:
item notifyProcess { TxName = "myapp/notifyOperator.tdf"; TxFilter = [ "myapp/addUser", "myapp/delUser" ]; }

114 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

item accountProcess { TxName = "accounting/logActivty.tdf"; TxFilter = [ "accounting/.*Credit", "accounting/.*Debit", "accounting/Deduction" ]; } item main { processList = ["notifyProcess", "accountProcess"]; }

The notifyProcess process item specifies that the myapp/notifyOperater.tdf transaction should be executed whenever the myapp/addUser or myapp/delUser transaction events are generated. The notifyOperator transaction could send an email message to a list of subscribers, possibly defined in the database, or could record the event activity in an application-level log table or file. The accountProcess process item specifies that the accounting/logActivity.tdf transaction should be executed whenever any accounting transaction ending with "Credit" or "Debit" generates an event, or when the accounting/Deduction transaction event is generated. The TxFilter attribute uses GNU Regular Expressions to specify matching criteria for transaction event identifiers.

Transaction Items
Each Process Definition File can define a list of transaction items as the main.startupList attribute to be executed when the Process Manager is initialized. Such transactions can be used for the initialization of application data structures, to log initial server information or any other server initialization purpose. Each Transaction Item specifies the name of the transaction to be executed, the meta information needed to execute the transaction and all input parameters for the transaction. In addition, each transaction item can specify one or more error checks, with associated error messages, that can be used to verify the correctness of the transaction output. Specifically, the following transaction item attributes are supported: Attribute
_transName _clientID

Description The _transName attribute specifies the identifier of the transaction to be executed. If the _clientID attribute is defined, it will be used as the client ID when the transaction is executed. Otherwise, the default client ID specified in the process.cfg configuration file will be used.

115 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

_authInfo

Other Attributes

If the _authInfo attribute is defined, it will be used as the username and password when the transaction is executed. Otherwise, the default authentication information specified in the process.cfg configuration file will be used. All attributes defined in the item that do not start with an underscore are passed along as input parameters when the transaction is executed.

For example, the following Transaction Items could be added to the previous Process Definition file to execute an initialization transaction and send an alarm to the operator when the server is restarted:
item notifyProcess { TxName = "myapp/notifyOperator.tdf"; TxFilter = [ "myapp/addUser", "myapp/delUser" ]; } item accountProcess { TxName = "accounting/logActivty.tdf"; TxFilter = [ "accounting/.*Credit", "accounting/.*Debit", "accounting/Deduction" ]; } item myInit { _transName Param1 Param2 } item genAlert { _transName Severity Message } = "myapp/initialize.tdf"; = "try this"; = 12;

= "alarmMgr/insert.tdf"; = "ALERT"; = "Server Restarted";

item main { processList = ["notifyProcess", "accountProcess"]; startupList = ["myInit", "genAlert"]; }

Process Table
All threads that are dynamically created by server applications (including all background actions and startup processing threads) are registered in the Process Table that is maintained internally by the Process Manager. The Process Table can be used by operators and developers to monitor internal thread activity.
5/11/2007 10:14 AM

116 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The Process Table can also be used to manually terminate a thread that may not be working properly or that otherwise isn't needed anymore. The Process Table can be viewed by executing the processMgr/show-table.tdf transaction. When viewed in a browser, the table will be displayed as an HTML table, with one line per internal thread. Each thread is assigned a unique PID which can be used to track the thread over time. The PID can also be used to kill a thread using the processMgr/kill-process.tdf transaction. As a convenience, the HTML Process Table display includes a "delete" button on each row which can be used to kill the thread represented by that row. Threads registered in the Process Table should not normally be terminated manually, since they are automatically terminated when there work is done. The ability to kill a thread registered in the Process Table is provided primarily for advanced trouble-shooting purposes and should only be used by experienced operators. The HTML Process Table display also provides a "Reload" button that may be used to reload all Process Definition Files defined in the Process Manager configuration directory. This is provided primarily for developers working on Process Definition Files so that they can be tested without restarting the server.

Process Observers
External applications and applets can monitor the progress of any Skipjack process by registering an Event Listener using a transaction filter of "processTable/PID", where PID is the numeric ID associated with the process being monitored. After such a listener is registered, whenever the process table entry associated with the given process is added, modified or removed, the process observer will be notified. The navius.skipjack.client.ProcessObserver applet provides a convenient mechanism for monitoring one or more processes within an HTML page. By default, when all of the processes being monitored have been removed from the process table, then the browser will branch to a given URL. Generally, such a URL would then check to ensure that the process was successful or not, displaying an appropriate next page. The ProcessObserver applet can also be used to automatically kill the processes being monitored if the user leaves or overwrites the current page. See Event Listening for more details and examples about event handlers and listeners in Skipjack.

Process Manager Configuration


The Process Manager is controlled by the process.cfg configuration file which is located in the $SKIPJACK/app/WEB-INF/conf directory, where $SKIPJACK is the runtime directory for the Skipjack Server. The process.cfg file is updated automatically by the Skipjack configuration and installation scripts, and should not normally be updated manually. The processDir property that is defined in the process.cfg configuration file specifies the directory to be processed by the Process Manager when the

117 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server is started. All files ending in ".gdf" that are located in the directory will be processed as Process Definition Files. By default, the directory is defined to be $SKIPJACK/app/WEB-INF/process where $SKIPJACK is the Skipjack runtime directory. Application installation scripts need only copy Process Definition Files into that directory to have the corresponding event handlers registered when the server is started again. The standard $SKIPJACK/bin/CopyApp.pl application installation script automatically copies all files found in the process sub-directory of the application installation directory to the appropriate server runtime directory. Among the configuration variables specified in the process.cfg file are the default client ID and user authentication information that are used when registering and executing all event handler transactions. In most situations, the default configuration settings are sufficient for all event handler transactions. However, in some cases, it is necessary to use a different client ID, username or password to ensure that the event handler transaction works properly or can be more easily tracked in the server logs. In such cases, specific information can be defined using the _clientID and _authInfo attributes in a given process item. For example, the following definition:
item notifyProcess { TxName = "myapp/notifyOperator.tdf"; TxFilter = [ "myapp/addUser", "myapp/delUser" ]; _clientID = "NotifyProcess"; _authInfo = "notifier:mypassword"; }

overrides the default client ID and authentication information for the notifyOperator event handler transaction. That is, when that event handler is registered and executed, it will be assigned a client ID of "NotifyProcess" and will use the username of "notify" and a password of "mypassword". The process.cfg file also specifies the default settings for the RemoveOnRestart, RemoveOnFailure and ReceiveFromSelf attributes that are accepted by the
eventMgr/add-listener

transaction. The default settings have been chosen to be consistent with the way the Process Manager operates and should not need to be adjusted or customized for a given event handler.

118 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 13: Session Management
Skipjack supports the use of "sessions" to automatically track the activities of a user. Sessions are automatically maintained by the browser and the Tomcat server (in which Skipjack resides), using a number of standard client/server information storage techniques. Session information can be read or written by any transaction processed during the client session through the session item. Transaction authors are free to use or update any of the session information as needed to perform any session-based task.

Session Item
The session item is automatically created when using login forms (see Custom Login Forms for more details) or can be created by any transaction that needs to maintain client information across multiple transactions in the same session. If a session exists when an HTTP request is made, it will appear as an HttpSession object associated with that request when it is processed by the Skipjack Server. In such cases, the Skipjack Server will automatically create the session item and will assign a reference to the HttpSession object to the session.object attribute. Furthermore, it will copy all HttpSession attributes into the session item. Transactions can access any of the session attributes simply by referencing the session item attributes. If a transaction defines the session item in the transaction definition file or modifies the session item during the execution of the transaction, then any attributes defined for that item will be stored in the HttpSession object when transaction processing has been completed. If the session is defined, but no HttpSession object currently exists, a new HttpSession object will be created and associated with the current client session. This allows transactions to pass information from one transaction to another as the user travels around the site. Since the transaction definition file is processed before the HttpSession object, any session item attributes defined in the transaction definition file itself will be overwritten by HttpSession attributes with the same name. Transaction authors should use the ComputeAction to dynamically update session parameters sometime during transaction processing to ensure that those values will be assigned to the session when the transaction processing is completed. For example, the following transaction demonstrates how a session value can be modified:

119 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

// // test/sessionTest.tdf // include "skipjack-common.tdf" item session { curValue } = 0;

item updateSession extends ComputeAction { _destItem = "session"; curValue = integer(session.curValue) + 10; curTime = date("now"); } item main extends BaseAction { actions = ["updateSession"]; templateName = "sessionTest.vm"; }

The first time the transaction is executed during a browser session, a new session object will be created, with the curValue attribute set to 0. Then, when the updateSession action is executed, the curValue session attribute will be incremented by 10 and the curTime session attribute will be set to the current date and time. Every time that the transaction is subsequently executed during the browser session, the curValue attribute will be incremented and returned to the browser. Keep in mind, even though the transaction definition always sets the session.curValue attribute to zero in the previous example, that value is overwritten by the current value defined in the session object provided by the client, if any. That is, the session item values defined in the transaction definition file are the initial values used whenever a session is created. The ComputeAction should be used update session values for existing sessions.

Session Timeout
The information stored in a session item can be automatically erased if the user does not perform any session activity in a certain time period. The default session inactivity timeout value can be specified in the $SKIPJACK_HOME/app/WEB-INF/conf/transaction.cfg file by the sessionTimeout property (in seconds), which is configured for a default value of 604,800 seconds (ie. 7 days). If a negative value is specified, then sessions will not timeout. In addition to the default timeout setting, any transaction can modify the timeout value for the current session by setting the _timeout attribute of the
session

item. When the transaction response is generated, any value specified by that attribute will be used as the timeout value for the session. If a negative value is specified, the session will not timeout.

120 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Session Invalidation
There are times when a transaction author needs to immediately invalidate a session. For example, the application may require the user to "logout" in order to safeguard information or the user may want to "empty" their shopping cart. In such cases the _invalidate attribute of the session item can be used. If that attribute is set to "true", then the session will be invalidated when the transaction response is generated. Any subsequent access made by the user will cause a new session to be created. For example, the following transaction causes the current user session to be invalidated:
// // test/formLogin/logout.tdf // include "skipjack-common.tdf" item session { _invalidate } = true;

item main extends BaseAction { actions = []; successMsg = "You Have Been Logged Out Of Your Current Session"; templateName = "/COMMON/tx-success.vm"; }

Notice that no actions are actually performed by this transaction, only the session._invalidate is set to "true", which causes the current session to be invalidated. If the current session was created as the result of a forms-based login screen and it is invalidated, then when the user attempts to execute another transaction the login form will automatically appear again, requiring them to provide their username and password.

Session Debugging
Session debugging is enabled for a given transaction by setting the debug.sessionDebug attribute to "true", as in the following example:
item debug { sessionDebug = true; }

When session debugging is enabled, the incoming and outgoing value of all session attributes will be logged in the $SKIPJACK_HOME/logs/trans.log file. See Debug Management for server-wide debug management techniques.

121 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 14: Data Importing
The Skipjack Server provides a flexible mechanism for importing data in various formats from various sources using the ImportAction. This section describes the features provided by that action and shows examples of how it can be used for various importing tasks.

Import Processing Phases


All imported data is processed by the ImportAction as an ASCII data stream containing one or more records, which consist of one or more fields. Data stream processing is broken into distinct phases: data stream access, record parsing, record validation and record processing. The access phase determines where and how the data stream is to be accessed. During the record parsing phase, the data stream is broken into one or more records, containing one or more fields. Each record found is then validated against a given schema and a list of business rules. Finally, the record is processed by transaction. The ImportAction provides mechanisms for each of these processing phases that are controlled by a small set of items and attributes.

Data Stream Access


The inputType attribute is used to determine how to access the desired data stream, with the following types currently supported: FILE A file in the server's local file system, designated by the fileInputFile attribute, is used as the data stream. If the filename starts with '/', then it will be treated as an absolute filename. Otherwise, the directory containing the current transaction will be prepended to the specified file path. FTP The data stream file will be accessed using FTP from any server accessible on the network, using the following attributes: Attribute
ftpInputHost

Description host name or IP Address

122 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

ftpInputPort ftpInputUsername ftpInputPassword ftpInputMode ftpInputFile

IP port (default = 21) FTP account username FTP account password binary or ascii (default = binary) remote file path

If the file path specified by the ftpInputFile attribute starts with '/', then it will be treated as an absolute path on the remote file system. Otherwise, the file path will be treated as a path relative to the default directory for the remote user specified by the ftpInputUsername attribute. VELOCITY The data stream is generated by the Velocity template engine, using the template specified by the velocityTemplate attribute and the current transaction state.

Record Parsing
The parseType attribute is used to determine how the data stream should be broken into records and fields, with the following types supported: DELIMITED The data stream is broken into records based on the following attributes: Attribute
delimRecord delimField

Description Delimiter used between records, consisting of one or more characters.

Default Value \n (newline)

Delimiter used between fields within a record, consisting of one or more characters. If the | (pipe) keyword "FIXED_WIDTH" is specified then all records are assumed to contain fixed width fields as defined by the fieldWidths attribute of each record definition item (discussed below). Delimiter used to denote the start of a comment, consisting of one or more characters. All // (double-slash) characters following a comment delimiter will be ignored up to the next record delimiter. Delimiter used to escape another delimiter, consisting of one or more characters. Any character following the escape delimiter will not be considered as part of another delimiter. If true, then leading and trailing whitespace for all fields will be removed. \ (back-slash)

delimComment

delimEscape

delimTrim

true

123 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Additional parse types will be supported in the future.

Record Validation
To support the validation of heterogeneous record formats defined in the same file, the recordMap attribute is used to specify the names of one or more record definition items that determine how each record should be validated, processed and stored for further processing. Each record definition item may specify the following attributes: acceptExpr schemaName actions fieldWidths For every record found in the data record stream, the following processing will be performed for every record definition item defined in the recordMap list: 1. A temporary item named curRecord will be created using the attributes defined by the schema item referenced by the schemaName attribute, assigning the values found in the current input fields to each attribute. For example, if the schema defines three attributes: A, B and C, then the curRecord item will also have three attributes named A, B and C, with values assigned from the input record. Additionally, the RecordType, RecordNumber, RecordString and RecordFile meta attributes will be defined as described below. If "FIXED_WIDTH" was specified as the delimField value in the import action item, then the fieldWidths attribute must be specified in each record definition item, defining a list of field widths. As each record definition item in the recordMap is processed for a given input record, the field width list associated with that record definition item will be used to break the record into fields. Otherwise, the field delimiter specified by the delimField attribute of the import action item will be used to determine the field values for all record definition items. 2. The acceptExpr of the record definition item will be evaluated as a boolean value. If it is false, then no further processing of the curRecord will be performed for the current record definition item. If it is true, then the current record is "accepted" by the current record definition item and no subsequent record definition items will be processed for that record. 3. If the acceptExpr is true, then the schema action defined by the schemaName attribute will be executed to validate all of the attributes in the curRecord item. If a validation exception is thrown, then no further processing will be performed for the current record definition item. 4. If schema validation was successful, then all of the actions defined in the actions list (if any) will be performed. Each action can reference the
curRecord

124 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

as needed to perform additional validation or custom data conversion. If any of the actions throws an exception, then no further processing will be performed for the current record definition item. If the curRecord is accepted by a record definition item, the schema validation was successful and the actions list was successfully executed, then the curRecord is appended to the Table object specified by the _destItem and _destTable attributes of the record definition item. If those attributes are not defined, the record definition item itself will be used as the value of the _destItem attribute and "table" will be used as the value of _destTable attribute. If the curRecord is not accepted by any record definition item or an exception is thrown during schema validation or action list processing, then an error entry will be added to a Table object that is stored as the value of the errorTable attribute of the import action item itself.

Record Table Format


All of the Table objects used to store records that have been accepted by a given record definition item will have column names defined according to the schema referenced by the schemaName attribute of that record definition item. For example, if the validation schema defines three attributes, A, B and C, then the Table object will have three columns named A, B and C. Each row in the table will consist of one of the records that was accepted by the record definition item. In addition to the attributes defined by the schema, the following meta columns will be defined in the record table: Column Name RecordFile Description File that defined the record

RecordNumber Record number in the defining file RecordString RecordType Record definition string from the file Name of the record definition item that accepted the record

The meta columns can be used by the transaction for subsequent record processing as needed.

Error Table Format


If a record is not accepted by any record definition item or a validation or processing errored occurred, then an entry is appended to the Table object stored as the errorTable attribute of the import action item. The errorTable is automatically created by the import action item prior to processing any records. Applications should check the size of that table after import action processing has been completed to determine if any errors were generated during the import process.

125 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Unlike most actions, the ImportAction does not automatically cause the transaction to abort as soon as an exception is raised. Rather, all exceptions raised while processing records are captured and stored in the errorTable, thereby allowing transactions to deal with each error individually if necessary. The error table consists of all of the meta columns defined above, as well as the following error columns: Column Name ErrorStatus ErrorMessage Description Value of the tx.status attribute at the time the error was generated Value of the tx.errorMsg attribute at the time the error was generated or the message string of any exception that was thrown

Record Processing
All of records imported using the ImportAction can be processed either by specifying a list of one or more actions for the actions attribute of each record definition item or by executing transactions after the ImportAction that directly access the record tables. In either case, the transaction author is free to specify whatever processing is necessary to perform custom validation or record processing. The only real distinction between an action that is performed as part of the actions list for a record definition item and an action that is performed after the ImportAction has completed is how errors are handled. In the former case, any exception that is thrown will automatically cause an entry to be appended to the error table and the current record to be discarded. In the latter case, the transaction author must handle exceptions themselves. Record processing actions defined in the actions list of the record definition item also have the benefit of accessing the curRecord item directly, instead of having to access fields in the Table object. Usually, this makes record processing easier to specify. The curRecord item is appended to the record table associated with a given record definition item after all actions defined in the actions list for that record definition item are executed. Therefore, if any of the actions alter the contents of the curRecord item (using the ComputeAction for example), then those changes will be stored in the record table, which may or may not be desirable depending on the application.

Basic Import Example


The ImportAction defined in the skipjack-common.tdf include file is the basis for all import processing. The default attributes for the ImportAction are
5/11/2007 10:14 AM

126 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

defined so that it is relatively easy to extend that action and import a file containing records with the same format. That is, the ImportAction item itself (or any item extended from it) can be used as both the import action item and the record definition item. For example, consider the following data file:
// // tutorial/dataImport/ex1.dat // Fred Smith|78000|410-555-1212|Bldg 8, Rm 301 Sally Jane|84000|410-555-7878 Oscar Van-Pelt|87350.56|301-444-1867|Home

In this example, a collection of employee records are being imported from the ex1.dat file from the server's local file system. (Accessing a file using FTP will be shown in a subsequent example.) Since the data file contains only one type of record, we can combine the import action item and the record definition item into a single item, as in the following transaction:
// // tutorial/dataImport/ex1.tdf // include "skipjack-common.tdf" item importData extends inputType fileInputFile schemaName } ImportAction { = "FILE"; = "ex1.dat"; = "recordSchema";

schema recordSchema extends BaseSchema { attrs = [ ("Name", "string", "nonempty"), ("Salary", "double", "nonempty"), ("Phone", "phoneno", "nonempty"), ("Office", "string", "optional") ]; } item recordList { table hiddenFields borderColor borderWidth } item main extends BaseAction { actions = ["importData"]; templateName = "ex1.vm"; } = importData.table; = ["RecordFile", "RecordNumber", "RecordString", "RecordType"]; = "black"; = 1;

The importData action item is defined to perform the import processing, extending the standard ImportAction defined in the skipjack-common.tdf include file. The importData item specifies that the "FILE" input type will be used to access the file and that the recordSchema item will be used to validate all records contained in that file.

127 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The ImportAction specifies a parseType of DELIMITED and a set of default delimiters to be used, which suffices for this example. The ImportAction specifies a default recordMap list which contains only a reference to itself and a default acceptExpr equal to "true". This allows the import action item to serve as the record definition item as well. When the importData action is executed by the main action, it accesses the designated file and parses it using the designated delimiters. For each record found, the recordSchema item is used to validate the record. The recordSchema item requires the record to contain the Name, Salary and Phone attributes, with an optional Office attribute. If record validation is successful, that record will be added to the importData.table record table. Otherwise, an error entry will be added to the importData.errorTable error table. The item used to store the record and error tables can be changed in this example by specifying the importData._destItem attribute. In this example, all of the records are valid and are stored in the importData.table record table. The recordList item references that table so that the listShow() macro in the ex1.vm template can display the table of records.
## ## tutorial/dataImport/ex1.vm ## #htmlPageHeader("Data Import Example 1") <center> #listShow($recordList) </center> #htmlPageFooter()

Note how the hiddenFields attribute is used to hide the meta table columns when the table is displayed. (The output can be seen at Data Import Example 1 if you are viewing this documentation directly from a Skipjack Server.)

FTP Import Example


Data files can be imported from different data sources simply by modifying a few attributes in the importData action. For example, if the data file processed in the previous example was located on a remote server, then the following modifications would suffice:
item importData extends ImportAction { inputType = "FTP"; ftpInputHost = "myServer"; ftpInputUsername = "myName";

128 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

ftpInputPassword = "myPassword"; ftpInputFile = "ex1.dat"; schemaName = "recordSchema"; }

Fixed Width Fields


Consider the data file from the previous example formatted using fixed width fields, as in the following example:
// // tutorial/dataImport/ex5.dat // Fred Smith 78000 410-555-1212Bldg 8, Rm 301 Sally Jane 84000 410-555-7878//END Oscar Van-Pelt87350.56301-444-1867Home

//END //END

In this case, there is no field delimiter used to separate the field values, only a predefined width for each field. To accomplish such import parsing, the delimField attribute should be defined as "FIXED_WIDTH" and the fieldWidths attribute should be defined as a list of integer field widths, as follows:
item importData extends inputType fileInputFile schemaName delimField fieldWidths } ImportAction { = "FILE"; = "ex5.dat"; = "recordSchema"; = "FIXED_WIDTH"; = [14, 8, 12, 16];

With only these modifications, the fixed width import file can be processed as in the previous example.

Custom Validation Example


The schema item provides a set of attribute types that can be used to specify the syntax of the values expected. Semantic validation, however, is intrinsically dependent on the task being performed, requiring custom expressions and processing to be written.

Schema Post Error Checks


The easiest way to specify custom validation criteria, and the associated error messages, is to define them using the postErrorCheck list attribute of the record schema item. For example, consider the following modification to the schema item from the previous example:

129 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

// // tutorial/dataImport/ex2.tdf // schema recordSchema extends BaseSchema { attrs = [ ("Name", "string", "nonempty"), ("Salary", "double", "nonempty"), ("Phone", "phoneno", "nonempty"), ("Office", "string", "optional") ]; postErrorCheck = [ (curRecord.Salary < 80000, guiStatus.InvalidParameter, "The Salary Field In Record #" + curRecord.RecordNumber + " From The Import File " + curRecord.RecordFile + " Is Too Small, Give " + curRecord.Name + " A Raise."), (curRecord.Phone->startsWith("410") == false, guiStatus.InvalidParameter, "Invalid Area Code") ]; }

In this case, two error checks are performed based on various fields in the curRecord item. Specifically, an error is generated for a given record if the Salary field is less than 80,000 or the Phone field does not begin with the 410 area code. If an error is generated by the postErrorCheck criteria for a given record, then the resulting error status and error message will be appended to the importData.errorTable error table and the record will not be added to the importData.table record table. Note how the curRecord meta fields are used to generate a very specific salary error message. Usually, when more specific information is provided in error messages it is easier to resolve the problem.

Custom Validation Actions


Although the postErrorCheck list of the schema action is convenient for checking many types of error conditions, there are times when additional processing must be performed in order to validate a record. For example, the application may require that the employee name specified in the Name field already exist in the Employee table in the database. In that case, we may need to execute a SQLRecordAction to verify the value in the Name field, as in the following example:
item importData extends inputType = fileInputFile = schemaName = actions = } ImportAction { "FILE"; "ex1.dat"; "recordSchema"; ["checkName"];

130 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

item checkName extends SQLRecordAction { sqlFile = "checkName.sql"; Name = curRecord.Name; zeroRowsMsg = "Invalid Employee Name '" + Name + "' Found In Record #" + curRecord.RecordNumber; _destItem = "employeeRecord"; }

In this case, the checkName SQL action has been defined to validate the Name of each record processed. If the name is invalid, then the error thrown by the checkName action will cause all further processing to be aborted for that record and the error status and message will be appended to the importData.errorTable error table. Any number of custom validation actions can be specified in the actions list of the record definition item. Each action will be performed in the order given, until all actions have completed successfully or until the first action throws an exception. Each action can access the curRecord item as needed to accomplish its task (as well as any other transaction item defined).

Custom Processing Example


There are no restrictions on the number or type of actions that can be executed while records are being imported. The previous examples showed how validation processing could be performed, but other types of processing may be done as well. For example, consider the following action list definition:
// // tutorial/importData/ex3.tdf // item importData extends ImportAction { inputType = "FILE"; fileInputFile = "ex1.dat"; schemaName = "recordSchema"; actions = ["checkName", "formatSalary"]; } item checkName extends SQLRecordAction { sqlFile = "checkName.sql"; Name = curRecord.Name; zeroRowsMsg = "Invalid Employee Name '" + Name + "' Found In Record #" + curRecord.RecordNumber; _destItem = "employeeRecord"; } item formatSalary extends ComputeAction { Salary = decimalFormat(curRecord.Salary, "$,000.00"); _destItem = "curRecord"; }

131 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

In this case, the formatSalary action is used to format the value of the Salary field as a money field and store the result in the curRecord item, so that it is subsequently stored in the importData.table data table. Since the formatSalary action is listed after the checkName action in the actions list, it will only be performed for records that have been successfully validated by both the recordSchema action (including any custom error checks) and the checkName action. Similar formatting could be performed by either defining a storage format expression for the Salary attribute (see Input Validation for an example) or by executing the TableFormatAction after all import processing has been completed. Each approach has different advantages depending on the application and transaction developer preferences.

Multi-Record Import Example


If the data file being imported contains two or more different types of records, the recordMap attribute of the import action can be used to specify different record definition items for each record type expected. Each record definition item can specify a different acceptance criteria, validation schema, and set of record processing actions as needed for that type of record. Furthermore, each record definition item can specify a different record table to contain all of the records of that type that have been imported. Consider a data file that may contain any combination of EMPLOYEE and SUPERVISOR records, as in the following example:
// // tutorial/dataImport/ex4.dat // EMPLOYEE|Fred Smith|78000|410-555-1212|Bldg 8, Rm 301 EMPLOYEE|Sally Jane|84000|410-555-7878 EMPLOYEE|Oscar Van-Pelt|87350.56|301-444-1867|Home // SUPERVISOR|Joe Brown|Dept 3|410-555-8765 SUPERVISOR|Alice Summers|Accounting|410-555-2356

Usually, when different records are defined in the same data file they contain one or more fields that are used to determine the appropriate record type. In this example, the first field contains the record type, thereby making the acceptance criteria very easy to specify, such as:
item importData extends ImportAction { ... recordMap = ["empDefn", "supDefn"]; } item empDefn { acceptExpr = curRecord.Type == "EMPLOYEE"; ... } item supDefn {

132 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

acceptExpr = curRecord.Type == "SUPERVISOR"; ... }

The actual field names used for the curRecord item being processed by each record definition item depend on the list of attributes defined in the corresponding schema. Usually, the record type field is assigned the same name in all schemas to avoid confusion, but that's not a requirement. Clearly, each record type needs a different schema definition in order to properly name and validate all of the record fields. In this example, the following schema definitions suffice:
item empDefn { acceptExpr = curRecord.Type == "EMPLOYEE"; schemaName = "empSchema"; ... } schema empSchema extends BaseSchema { attrs = [ ("Type", ["EMPLOYEE"], ("Name", "string", ("Salary", "double", ("Phone", "phoneno", ("Office", "string", ]; }

"nonempty"), "nonempty"), "nonempty"), "nonempty"), "optional")

item supDefn { acceptExpr = curRecord.Type == "SUPERVISOR"; schemaName = "supSchema"; ... } schema supSchema extends BaseSchema { attrs = [ ("Type", ["SUPERVISOR"], ("Name", "string", ("Dept", "string", ("Phone", "phoneno", ]; }

"nonempty"), "nonempty"), "nonempty"), "nonempty")

Note how the Type field is defined by each schema, specifying a single enumerated value as a valid input. (In this case, the Type field can never be invalid, because the acceptExpr ensures that only the proper record type is accepted, but that might not always be the case.) Note also how the schemas define record fields with different types and names, as well as a different number of fields. This allows transaction authors to process and store records using the most appropriate names and types, instead of having to invent generic field names like "field1", "field2", etc. Since multiple records are being imported, we need to store them in different tables. By default, the resulting data tables are stored as the table
5/11/2007 10:14 AM

133 of 150

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

attribute of the corresponding record definition item. In the following example we specify a common results item, with appropriate table names for both of the data tables:
item empDefn { acceptExpr schemaName _destItem _destTable } item supDefn { acceptExpr schemaName _destItem _destTable } = = = = curRecord.Type == "EMPLOYEE"; "empSchema"; "results"; "empTable";

= = = =

curRecord.Type == "SUPERVISOR"; "supSchema"; "results"; "supTable";

Clearly, this example can be expanded to any number of different record types relatively easily.

134 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Skipjack Server

5 October 2002

Application Development Guide


Section 15: HTML Form Macros
In this section we discuss how the standard form macro provided by the Skipjack Server can be used to quickly generate basic input forms. The various features provided the macro are controlled by specifying a Form Definition Item in the transaction definition file, which is referenced when the form macro is invoked. This greatly simplifies transaction response templates, while adding all the flexibility that comes from item attribute expressions and transaction processing.

HTML Form Macro


The HTML Form Macro is defined in the form-macros-01.vm file which resides in the $SKIPJACK/app/WEB-INF/transaction/MACROS runtime directory. The macro file is loaded automatically whenever the server is started, allowing all transaction templates to use the macro. The form macro can be invoked from a Velocity template file using the following syntax: #formShow($defItem $dataItem) where \$defItem references a Form Definition Item and \$dataItem references a data item that are both defined in the transaction definition file. The form definition item specifies the display characteristics and behaviors associated with the form, while the data item specifies the initial value for some or all of the entry fields defined by the form. For example, consider the following transasction definition file:
// // tutorial/formMacro/simpleForm.tdf // include "skipjack-common.tdf" item formItem extends FormAction { title = "My Form"; schema = "mySchema"; boxWidth = 400; } schema mySchema extends BaseSchema { attrs = [

135 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

("FirstName", ("LastName", ("Age", ("Married", ("State", ("Zipcode", ]; stateList } item myInfo { FirstName LastName Age Married State Zipcode } = = = = = =

"string", "string", "integer", "boolean", stateList, "zipcode",

"nonempty"), "nonempty"), "nonempty"), "default", "yes"), "default", ""), "nonempty")

= UnitedStates("ABBR LIST");

"Fred"; "Smith"; 27; "no"; "MD"; "21401";

item main extends BaseAction { actions = ["formItem"]; templateName = "simpleForm.vm"; }

and the corresponding Velocity template file:


#htmlPageHeader("/tutorial/formMacro/simpleForm.tdf") <center> #formShow($formItem $myInfo) </center> #htmlPageFooter()

The formItem defines a simple form that consists of the given title and one entry field for each of the six attributes defined in the mySchema schema item, with the following output:

136 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

The overall width of the form is constrained to be 400 pixels by the formItem.boxWidth attribute and is centered on the page by the <center> HTML tag in the template file. Since the myInfo data item was referenced in the formShow() macro invocation, the attribute values defined in that item will be used to override any default attribute values specified by the schema item. If the second argument to the formShow() macro is specified as the empty string (""), then the default attribute values defined in the schema item will be used as the default values for the form fields.

Form Action
The previous example defined the formItem form definition item as an extension of the FormAction action item defined in the skipjack-common.tdf file. The
FormAction

action item defines a default set of attributes for all form items and it performs various form initialization functions when it is executed. As shown in the main item of the previous example:
item main extends BaseAction { actions = ["formItem"]; templateName = "simpleForm.vm"; }

the formItem is executed as part of the main action list. (Usually, form items are executed last, after all other transaction actions have been performed, thereby allowing the form to access all information generated during the transaction.)

137 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

If the form definition item is not executed by the transaction then an alert box will be displayed on the user's browser when the transaction response page is loaded indicating that the form definition item was not initialized properly.

Form Field Labels


By default, the label displayed for every form field is the same as the attribute name defined in the schema referenced by that form. One or more of the form field labels can be customized by defining the guiLabel item, as in the following example:
item guiLabel overrides guiLabel { _readonly = true; FirstName = "First Name"; LastName = "Last Name"; Zipcode = "Postal Zip Code"; }

Since the guiLabel item is defined in the standard Skipjack definition files, the "overrides" directive is used to modify that item in the current transaction file. In this case, we define three labels by specifying the form field name as an attribute name in the guiLabel item and the form field label as the corresponding attribute value, resulting in the following form being displayed:

The guiLabel item is used by a number of Skipjack features to specify labels for such things as form fields, database table columns and HTML table columns. In general, applications should define a single guiLabel item that defines all of the labels needed for that application and then include that file in all transaction definition

138 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

files to maintain consistency across all displays.

Form Display Attribues


The following form definition item attributes are supported to customize the display properties of a form: Attribute
title instructions schema

Description If defined, the given title is displayed inside of the form border, centered at the top of the form. If defined, the given set of instructions is displayed at the top of the form, just below the title, if any. If defined, this attribute should reference an item that extends the BaseSchema item, defining all of the input fields to be displayed in the form as schema attributes. The type of HTML widget used for each form field will depend on the type of attribute specified in the schema. See Form Field Types below for more details. If the inputItem macro parameter is defined when the formShow() macro is invoked and it contains an attribute with the same name as a given field, then the value of that inputItem attribute will be used as the default value of the field. Otherwise, any default value for the field defined in the schema will be used.

buttons

If defined, this attribute should define a Vector of one or more button item names, where each string value in the list should reference a button definition item. See Button Definition Items below for more details. If defined, this attribute should define a Vector of schema attribute names. Each field referenced in the list will be displayed as a readonly field if a default value is defined for that field, either by the inputItem macro parameter or by the default value in the schema definition item. This allows transaction authors to prevent the user from updating critical fields, such as the unique ID of a database record. If defined, this attribute should define a Vector of schema attribute names. Each field referenced in the list will be generated as a HTML hidden form field if a default value is defined for that field, either by the inputItem macro parameter or by the default value in the schema definition item. This allows tranasction authors to hide form fields from the user, while still POSTing that information when the form is submitted. NOTE: Additional hidden fields can be defined for a form by using the hiddenItems attribute as described in the Form Control Attributes section below.

readonlyFields

hiddenFields

fieldSize

The field size (in columns) for all input fields displayed in the form. The default value is 40.

139 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

focusField boxWidth

If defined, the form field name referenced by this attribute will be given the focus as soon as the form is loaded. The overall width of the form in pixels. If not defined, the form will be as wide as necessary to accomodate all fields. NOTE: If an instruction is defined, then it may span the entire page width by default. In that case, use this attribute to limit the total width of the form.

outerWidth outerColor innerWidth innerColor

The width (in pixels) and color of the form border. The gap width (in pixels) between the outer border and the form components, and the background color of the form.

Form Field Types


The form macro automatically generates HTML form fields based on the type of each attribute defined in the form schema item, using the following conversion table: Attribute Type string, int, double, datetime, duration, url, id, phoneno, zipcode, email, ipaddress, regular expression password text enumeration boolean HTML Field Type text Comments Any text can be entered in the form field, with syntax validation performed on the server when the form is submitted All input characters are displayed as '*' The number of rows and columns can be controlled by defining addition schema item attributes. See below for details. Display depends on various "Choice" properties that may be defined for the attribute. See below for details. Displayed using image buttons which are dynamically updated by JavaScript, thereby providing the same look and feel across all browser types Displays an editable field and a browse button that allows the user to browse the local file system and select a filename for uploading to the server

password textarea selection list or radio buttons checkbox

file

file

140 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Check Box Values


When a boolean check box is displayed in the form, the box will be initially checked if the default value equals "on" (case insensitive) or starts with a 't' or 'y' (case insensitive). All other values will be interpreted as false and the box will not be checked. When a check box field is POSTed to a transaction, the value will be set to "on" or "off". Unlike normal HTML check boxes, the check box provided by the form macro always POSTs a value when the form is submitted.

Text Area Properties


When a "textarea" form field is displayed, the number of rows and columns can be specified by defining the xxxRows and xxxColumns attributes in the schema item, where xxx is the name of the field. For example, the following schema item defines a text area field with 10 rows of 40 columns:
schema formSchema extends BaseSchema { attrs = [ ("Comment", "text", "default", "") ]; CommentRows = 10; CommentColumns = 40; }

Choice Properties
When an enumerated list is specified as the attribute type in a schema item, a choice field will be generated in the form as either a selection list (the HTML <SELECT> tag) or a set of radio buttons. By default, a set of radio buttons is displayed if the number of choices is six or less, and a selection list is displayed if more than six choices are available. For example, consider the following schema definition and resulting form:
schema formSchema extends BaseSchema { attrs = [ ("ColorList", colorList, "default", ""), ("StateList", stateList, "default", "") ]; colorList = ["red", "yellow", "blue", "gold", "green"]; stateList = UnitedStates("ABBR LIST"); }

By default, the short color list is displayed as a set of radio buttons, with three columns of buttons per row. The number of columns can be specified using the xxxRadioCols schema item attribute, where xxx is the attribute name. The long state list is displayed by default as a drop-down choice list. If a selection list is desired, then the xxxChoiceSize schema item attribute can be used to specify the number of choices to be displayed at a time, where xxx is the attribute name. For example, the following attribute definitions

141 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

result in the following form:


schema formSchema extends BaseSchema { attrs = [ ("ColorList", colorList, "default", ""), ("StateList", stateList, "default", "") ]; colorList = ["red", "yellow", "blue", "gold", "green"]; stateList = UnitedStates("ABBR LIST"); StateListChoiceSize = 5; ColorListRadioCols = 2; }

Choice Labels
The xxxChoiceLabels schema item attribute can be used to define a different set of labels to be displayed in a choice field, while still reporting the actual choice value when the form is submitted. For example, if we want the color values to be displayed as upper case labels, while still reporting them as lower case, we could modify the previous example as follows:
schema formSchema extends BaseSchema { attrs = [ ("ColorList", colorList, "default", ""), ("StateList", stateList, "default", "") ]; colorList = ["red", "yellow", "blue", "gold", "green"]; stateList = UnitedStates("ABBR LIST"); StateListChoiceSize = 5; ColorListRadioCols = 2; ColorListChoiceLabels = ["RED", "YELLOW", "NAVY BLUE", "NAVY GOLD", "ARMY GREEN"]; }

The label list must be in the same order as the value list specified for the corresponding attribute in the schema item.

142 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Choice Type
The xxxChoiceType schema item attribute can be used to force a choice field to be displayed in a specific way ("select" or "radio", regardless of the number of choice items. For example, we can reverse the types of choice fields displayed in the previous example as follows:
schema formSchema extends BaseSchema { attrs = [ ("ColorList", colorList, "default", ""), ("StateList", stateList, "default", "") ]; colorList = ["red", "yellow", "blue", "gold", "green"]; stateList = UnitedStates("ABBR LIST"); StateListChoiceSize = 5; ColorListRadioCols = 2; ColorListChoiceLabels = ["RED", "YELLOW", "NAVY BLUE", "NAVY GOLD", "ARMY GREEN"]; StateListChoiceType = "radio"; StateListRadioCols = 5; ColorListChoiceType = "select"; }

Multiple Choice Type


Choice fields that allow multiple selections can be specified by setting the xxxChoiceMulti attribute to "true". In that case, an HTML selection list will be generated, using the xxxChoiceSize attribute as the number of items to be displayed. For example, we could modify the previous example to allow multiple states to be selected:

143 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

schema formSchema extends BaseSchema { attrs = [ ("ColorList", colorList, "default", ""), ("StateList", stateList, "default", "") ]; colorList = ["red", "yellow", "blue", "gold", "green"]; stateList = UnitedStates("ABBR LIST"); StateListChoiceSize = 5; ColorListRadioCols = 2; ColorListChoiceLabels = ["RED", "YELLOW", "NAVY BLUE", "NAVY GOLD", "ARMY GREEN"]; StateListChoiceMulti = true; StateListChoiceSize = 10; ColorListChoiceType = "select"; }

In most browsers, the user should hold the Control key when selecting an item in order to select or deselect that item without changing the other selections. The Shift key can also be used to select all items between the last item selected and the current item being selected.

Choice Change Function


The xxxChoiceOnChange attribute can be used to specify a JavaScript command to be executed whenever a choice is selected in a choice field. Usually, this is used to either provide custom browser-side validation or automatically fill in another field as needed. The xxxChoiceOnChange attribute is ignored for multiple choice fields.

Button Definition Items


The buttons attribute of the form definition item can be used to specify one or more buttons to be displayed at the bottom of the row. Buttons are displayed as two HTML images, which are automatically toggled when the button is "pressed". This provides the same look and feel across all browsers.

144 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Button image files can be created using any graphics program, thereby allowing a wide range of look and feels. Basic rectangular buttons can also be generated using the navius.apps.ButtonMaker application. Each item in the buttons Vector should be the name of a Button Definition Item which specifies the properties and behavior of each button, with the following attributes supported: Attribute
buttonName buttonImage

Description Name of the button Specifies the prefix of the image files to be used to represent the button. If buttonImage is not defined, then the buttonName is used. The actual image file names are determined by appending "-button.gif" and "-recess.gif" to the specified image name. URL to which the form should be submitted when the button is pressed. JavaScript command to be executed when the button is pressed. If this attribute is specified, the actionURL attribute is ignored. Message to be displayed on the browser status line when the mouse hovers over the button

actionURL actionFunc

helpMsg

Form Control Attributes


In addition to the various display properties described in the previous sections, the behavior of the form generated by the form macro can be controlled by the following form definition item attributes: Attribute
actionURL target enctype hiddenItems

Description Specifies the 'action' property of the HTML <FORM> tag Specifies the 'target' property of the HTML <FORM> tag Specifies the 'enctype' property of the HTML <FORM> tag Specifies a Vector of one or more item names. For each item referenced in the list, all of the attributes defined in that item will be created as hidden form fields. In each case, the attribute name will be used as the form field name and the attribute value will be used as the form field value. This allows transaction authors to pass hidden data to the action when the form is submitted.

145 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

hiddenInputItem

Specifies the name of an item that should be used to define hidden fields for all of the input parameters of the transaction that generated the form. When the form action item is executed, it will automatically create the item referenced by this attribute and copy all input attribute names and values into that item. When the HTML form is generated, hidden form fields will be created for each attribute copied into that item. When copying the input attributes, the form action will not copy any input attributes that are already defined as either normal or hidden form fields. That is, it will skip any input attribute that has the same name as any of the form fields specified in the form schema attribute list or any of the form fields specified in the items specified by the hiddenItems list. This allows transaction authors to make use of whatever fields are needed by the form, while passing all input parameters through the form to the next transaction.

formID

If this attribute is defined, a hidden field named '_formID' will be created with the value given. The _formID field can be used by transactions to determine from which form they were executed. If this attribute is defined, then a hidden field named '_formStack' will be created with that value. The _formStack field is used by the standard JavaScript functions created with every form to automatically execute the "previous" form. Specifically, the form stack maintains a chain of transaction identifiers that can be used to "return" from a form to the form that originally executed it. The _formStack field is automatically maintained by the Form Action. This attribute is used to "set" the stack to a known starting transaction. Generally, top level forms will set this attribute and all lower-level forms will use the automatic settings.

formStack

HTML Form Menu Macro


The formMenu() Velocity macro can be used to generate vertical or horizontal menus of buttons. Any number of button menus can be displayed anywhere on a given page containing one or more forms, with each menu associated with possibly a different form. The form menu macro can be invoked from a Velocity template file using the following syntax: #formMenu($formItem $menuItem) where the $formItem references a form definition item and the $menuItem references a menu definition item. Each button displayed in the menu will be associated with the form generated by the referenced form definition item. The following attributes are supported by Menu Definition Items:

146 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Attribute
layout

Description If "vertical" is specified, then all buttons will be displayed as one or more vertical columns. Otherwise, all buttons will be displayed as one or more horizontal rows. The default value is "horizontal". Vector of one or more Button Definition Item names. If the special name "BREAK" is specified, then a blank space will be inserted in vertical layout mode and a new line of buttons will be started in horizontal layout mode. If this attribute is defined, then it should specify the name of a form definition item to be used for all menu buttons instead of the formItem parameter specified when the macro was invoked.

buttons

formItem

For example, the following menu definition item results in the following menu being displayed:
item formMenu { layout = "horizontal"; buttons = ["insertButton", "deleteButton", "editButton", "BREAK", "okButton", "cancelButton"]; }

HTML Form Message Box Macro


The formMsgBox() macro can be used to display a given message in a box, with a given background color and a black border. Usually this is used to alert the user to some problem. The message box macro can be invoked from a Velocity template file using the following syntax: #formMsgBox($msg $bgcolor) where $msg is the message to be displayed and $bgcolor is the background color.

HTML Form Header Macro


The formPageHeader() macro should be executed at the top of any page that makes use of the form macros. It creates data structures and functions that are used during

147 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

page loading. Specifically, it generates the necessary HTML tags to include the "skipjackForm.js" file, which defines all of the JavaScript functions used by the form macros. This macro is automatically invoked by the default htmlPageHeader() macro that is used by all Skipjack Server page templates.

HTML Form Page Loader Macro


The formPageLoader() macro should be used whenever an HTML body tag is generated for a page containing a form macro. When executed the macro generates an HTML "onload" attribute definition for the <BODY> tag that executes the formPageLoad() JavaScript function which initializes all forms on the page. Since only one <BODY> tag can exist for an HTML page and only one "onload" attribute can be specified, if a custom onload function is required for a given page, then the $pageOnloadFunc Velocity variable can be defined prior to executing the formPageLoader() to specify a custom onload function. In that case, the custom onload function is responsible for executing the formPageLoad() function before returning. This macro is automatically invoked by the default htmlPageHeader() macro that is used by all Skipjack Server page templates.

Default Input Form


As was discussed in Section 2, when a transaction is invoked using the .form suffix an HTML Default Input Form is returned as the trasaction response. The default input form allows the user to enter all of the input parameters expected by the transaction, as specified by the inputSchema item. When used for development or testing purposes, the default characteristics of the input are usually sufficient. Nonetheless, all of the features supported by the HTML form macro can be used to customize the default input form as needed, simply by overriding the standard inputForm item that is created for all transactions. For example, consider the default input form for the last example in Section 2 when invoked as tutorial/helloWorld/ex5.form:

148 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

Although the form is functional, we might want to specify a custom set of field labels using the guiLabel item as follows:
item guiLabel overrides guiLabel { _readonly = true; who = "To Whom"; fontSize = "Size of Font"; bgColor = "BG Color"; }

and perhaps specify a bunch of display properties (doesn't everyone love being a graphics expert!) by overriding the inputForm item as follows:
item inputForm overrides inputForm { title = "Hello World Input Form"; instructions = "Please fill out the following fields and press" + " OK to display your message:"; buttons boxWidth outerColor outerWidth innerColor fieldSize } item returnButton { buttonName = "return"; actionFunc = "history.back()"; helpMsg = "Return To Previous Page"; } = ["inputFormSubmitButton", "returnButton"]; = = = = = 250; "black"; 1; "lightgreen"; 10;

In addition to the cosmetic changes, we also re-defined the list of buttons displayed on the form to include a "return" button. The resulting customized input form would be displayed as follows:

149 of 150

5/11/2007 10:14 AM

Skipjack Server Application Development Guide

http://205.177.219.178/doc/appDevGuide/printable.html

150 of 150

5/11/2007 10:14 AM

Das könnte Ihnen auch gefallen