TESS
version 1.0
System for customizing data view by the use of XML templates
This version optimized for "WebWisdom Educational Objects"
but basic ideas and some capabilities can be used in other domains
This system is integrated with Tango to allow collaborative access
but it works equally well outside Tango
System still under test/improvement
This document cannot be distributed without written permission from Geoffrey Fox (315-443-2163,
gcf@npac.syr.edu).Ó NPAC and WebWisdom.com, Syracuse, 1998, 1999
Table of contents
1. Introduction *
2. Servlet architecture *
2.1. Initialization Module
*2.2. Main Module
*2.3. Template Loader
*2.4. Template Cache
*2.5. XML Parser
*2.6. Interpreter
*2.7. Sender
*2.8. Output Cache
*2.9. Remote Configuration
*3. TDL - Template Definition Language *
3.1. Expressions
*3.2. Conditional statements
*3.3. Assigning values to internal servlet variables
*3.4. Inserting values
*3.5. Connecting to database
*3.6. Invoking another template file
*3.7. Inline command
*4. Application Programming Interface for the servlet *
4.1. API functions from TDLTag abstract class
*4.2. Example implementation of methods for control tags
*5. Servlet installation procedure *
6. Sample template - WebWisdom NT „CPS" template *
6.1. Tag definition
*6.2. Main template file
*6.3. Template file to display foils as HTML-bulleted lists
*6.4. Template file to display foils as images
*6.5. Template file to navigate in foilworld tree
*6.6. Template file to create and display index with links to foils
*The TESS system (Template Extension of Software System) is a HTTP server extension designed for user-defined output formatting. The main idea of the system is to present the same data in different views by the use of templates - XML-compliant files describing the way of data formatting. The architecture of the system is presented in Fig. 1.
Fig. 1. Global TESS system architecture
The TESS system is composed of a servlet - Java program being an extension of a standard HTTP server, and a set of templates. The servlet is capable to access local software systems, mainly database management systems by the use of JDBC. The servlet can also access WWW files and documents via other HTTP servers. Some files are of special meaning. They are called templates and their role is to define patterns for output formatting. The templates are written in TDL - Template Definition Language, a language specially developed to be used in TESS system.
The basic way of using the TESS system is the following. A user accesses the HTTP server from his/her HTML browser, providing in URL: (1) a locator of the servlet, (2) a locator of a TDL template, and (3) - some additional parameters. The HTTP server passes the call to the servlet addressed in the user's URL. Basing on the template locator, the servlet reads the template from a given HTTP server. Next, the servlet interprets the contents of the template tag by tag, in the meanwhile contacting local database management system and other HTTP servers for data needed to complete the operation, i.e., data being results of an SQL query, a given file, etc. The data is formatted according to the template and the parameters, and send back to the user as a standard HTML file. For example, to display nth foil of a presentation, a user sends (as URL) a locator of a template together with servlet location and with two parameters – presentation identifier and foil number. The servlet reads the contents of the template, interprets it, invokes some queries to the database as defined in the template (a query to get a foil with two parameters – the presentation identifier and foil number), formats query results into HTML format, adding necessary HTML tags including text formatting tags with font and color definitions, adds a page header (with customer logo for example or with advertisement), and sends the complete HTML file back to the user. As it can be seen, TESS system gives much more functionality in comparison to CGI programs - first of all, a way of output formatting can be fully and dynamically controlled by a user. Moreover, the servlet allows data caching and persistent data storage (as an extension of HTTP servlet it is active all the time), and more efficient communication with the database.
Main TESS system features are the following.
TDL is a tag-based language for template definition. The language definition is fully extensible, giving to a user a possibility to define his/her own tags. A user-defined Java method is provided for each tag. This method is invoked every time the tag is interpreted by the servlet. This approach gives a possibility to personalize the behavior of the system according to user needs.
TDL language is an application of the XML standard. The language interpretation is performed by standard XML parser. Moreover, correctness of template syntax can be automatically verified to ensure that it can be interpreted correctly.
First level of cache is used to store input files (including templates). The second level is used to store output cache (HTML-formatted output files). The cache can significantly improve system performance especially in a case when many users access the same data at the same time and format them in the same way (for example a class of students accessing the same course material simultaneously).
The object used for interpretation of a tag can be re-used, i.e., every time the tag is about to be interpreted the same object is used, with no initialization of its internal data. Thus, one can use "interpretation history" of the tag.
A set of HTML pages is provided to configure the servlet via WWW.
Templates can be located on different hosts and maintained by different users. A user does not have to have access to the server to modify his/her templates.
Servlet behavior can be modified by the use of properties. There are configuration properties, predefined properties, user-defined properties (read form a file), system-defined properties, variable properties (defined by tags during template interpretation), and addressing properties.
TDL language is equipped with expression evaluator, making it possible to perform some arithmetical, logical, and text-formatting operations on tag parameters.
In the next sections of the document the system architecture and usage is described. In Section 2, detailed servlet architecture is shown. In Section 3, TDL language is described together with its syntax and expression evaluation. Section 4 describes how the system can be used to format data retrieved from the database; in Section 5 a typical TESS application is shown. Section 6 summarizes the document.
The servlet is developed according to the requirements specified in [http://java.sun.com/products/ webserver/features/]. Thus, it can be used with any HTTP server fulfilling these requirements, for example Netscape Enterprise Server.
The servlet is composed of several modules (Fig. 2): Main Module with Initialization Module, Template Loader with Template Cache, XML Parser, Interpreter with Persistent Data Storage and Tag Implementations, and Sender with Output Cache.
Fig.2. Servlet architecture
First time the servlet is invoked, the Initialization module is activated. This module is responsible for reading configuration files, initializing all the data structures used by other modules, and initializing both cache modules.
The servlet can be remotely configured by the use of its HTTP server and a standard HTML browser. The configuration parameters include (among others) cache timings and methods, and names of Java methods to be used for tag interpretation. The Main Module is responsible for invoking and synchronizing the other modules. The order of invoking is the following. After a call is received from the HTTP server the servlet is linked to, servlet checks if the output for this call does not exists in the Output Cache (i.e., if the output for such call was already prepared and has not yet expired). If the output is ready in the Output Cache, it is sent directly to the user without activating other modules. If, however, the output for the call is not cached at the moment (or the cache is not active), the Main Module starts to activate other modules to perform this call. First, the Template Loader Module is activated with the template as a parameter. If this template file is stored in the Template Cache, it is passed to the Main Module. If, however, the template file is not cached at the moment, the Template Loader reads it from a given HTTP server, according to template locator. Once read, the template is put to the Template Cache and passed to the Main Module.
When the template is ready, the Main Module invokes the XML Parser for this template. As a result, a template derivation tree is generated, being a result of syntactical decomposition of the template. Each tag is stored as a node of the tree, with children nodes being nested tags, text inside tag body, and tag attributes. The root node of the generated parsing tree is passed back to the Main Module.
Once the tree for the template is ready, the Interpreter is invoked to parse the tree recursively, node by node. For every node, the tag type is determined and a corresponding Java method is invoked to generate tag output (i.e., a text in HTML format). The called method recursively calls similar methods for the nested elements of the tag body. Methods can access database management system (via JDBC) to get some data, read documents from HTTP servers, generate their own text, etc. As a final result of parsing the root node and all its children, a string of characters being HTML-formatted output is generated.
The Interpreter is also equipped in the Persistent Data Storage module, to deal with persistent objects (for example template variables) and to remember an interpretation state for some tags.
The generated HTML output is passed to the Sender, and, at the same time, to the Output Cache. The Sender sends via Internet (i.e., the HTTP server the servlet is linked to) the output back to the user.
In the remaining part of this section Modules are described in details.
Initialization ModuleThe Initialization Module reads configuration files. There are two files to configure the servlet behavior. Both files are read once when the servlet is about to perform the first request. The first file, called servlet_tdl.conf, is used to link tags with their corresponding Java classes and methods with formal parameters. This file is read line by line, with every line complaining to the following syntax:
tag_name | Java_class.method(formal_parameters) | persistency
where:
Note that each TDL tag is interpreted in the same way, including control tags (IF, FOR, WHILE, etc.). Thus, the approach gives maximum flexibility to the user, as each tag method can be freely changed according to user’s needs.
Sample configuration file servlet_tdl.conf is presented in Fig. 3.
WW_DOCUMENT|Tags.WW_DOCUMENT()|0
WW_IMAGE|Tags.WW_IMAGE (IMAGENAME, ID, PARENTID)|0
WW_LOGIN|Tags.WW_LOGIN()|0
WW_IF|Tags.WW_IF ( CONDITION)|0
WW_THEN|Tags.WW_THEN ()|0
WW_ELSE|Tags.WW_ELSE ()|0
WW_CONNECT|Tags.WW_CONNECT ( CONNECTION)|0
WW_AUTHORNAME|Tags.WW_AUTHORNAME ( ID)|0
WW_OWNERNAME|Tags.WW_OWNERNAME ( ID)|0
WW_TITLE|Tags.WW_TITLE ( ID)|0
WW_CREATIONDATE|Tags.WW_CREATIONDATE ( ID)|0
WW_SOUND|Tags.WW_SOUND ( SID, ID, PARENTID)|0
WW_USERNAME|Tags.WW_USERNAME()|0
WW_PASSWORD|Tags.WW_PASSWORD()|0
Fig. 3. A sample contents of configuration file servlet_tdl.conf
The second configuration file called servlet_templ.conf is used to declare localization of template directories. This file is also read line by line, with every line of the following format:
template_name | template_location
where the template_name is the name used by users in template locators (URLs passed to the servlet), and the template_location is an URL address of a document pool where the template files are stored. Note that if a template is composed of more than one file, these files must be stored in one directory only. Note also that the directories do not have to be placed in the local host the HTTP server is running.
The example servlet_templ.conf file is presented in Fig. 4.
taurus|http://taurus.kti.ae.poznan.pl/templates/t1/
cps|http://taurus.kti.ae.poznan.pl/templates/cps616dbforvrml/
my_template|http://sandman.npac.syr.edu/~mark/lectures/
Fig.4. A sample contents of configuration file servlet_templ.conf
Main ModuleThe Main Module is responsible for synchronizing the work of other modules and for getting calls from the HTTP server. In general, according to a type of a call (HTTP POST or GET), one of the methods of the Main Module is invoked: doPost() or doGet(). In general, doPost() method is used for servlet configuration, while doGet() – for accessing data. Both methods operate in "stateless" manner (like HTTP servers do). Methods for concurrent user calls are run in multi-thread environment (thanks to built-in Java multithreading).
The doPost() method is used to configure the servlet behavior. Main tasks performed by the use of this method are the following:
All the performed POST calls are stored in a file TDLDebug.log located in the configuration directory (cf. Section 2.1). This file is automatically erased during every servlet restart.
The doGet() method is used to serve calls for data. This method calls other servlet modules in a cycle (cf. Fig. 2). First, the Template Loader module is called to load a template file and store it in the Template Cache. Second, INLINE statements are searched in the template file, and for every such statement found, a text-based content of a file pointed by it is put into the template text instead of this statement. Next, "magic" HTML characters ‘<’ being starting characters of non-TDL tag definitions are mapped into special strings of characters. This mapping is forced by the XML Parser (invoked as a next module), to suppress confusing this module by unknown tags. Next, the template text is passed to the XML Parser module to build a template derivation tree. Next, interpretation of this tree is started by an invocation of the Interpreter module. A text-based output being a result of tree interpretation is decoded to restore the non-TDL tags and sent by the Sender back to the user as a response for his/her GET invocation.
Template LoaderTESS template is a set of files, stored in a single directory, written in TDL format, and defining a way of formatting output send to a client by the servlet. The TDL format is described in details in the next chapter. Each template has a name associated with it by the configuration file servlet_templ.conf (cf. Section 2.1). Each file belonging to a template is identified (in other files of the template) by its name. Some arguments may be passed from one template file to another during template interpretation.
Two files are treated in a special way. If the user accesses the template without specifying any particular file (for example http://taurus.kti.ae.poznan.pl/cps/), the default "login.tdl" template file is loaded. This file does not differ from other template files. However, if it contains special tag <WW_LOGINFORM>, the "SUBMIT" button will redirect control to the second special file – "index.tdl". Each template that requires user identification should use "login.tdl ® index.tdl" mechanism.
During the first attempt to use a template, a file called properties.conf is read (located in the template directory) to define some properties for the template. Properties are internal template variables. They are identified by names and they may have text values. The format of the properties.conf file conforms to XML and is a definition of a single XML tag <PROPERTIES>. Sample file is shown in Fig. 5. In this file there are two property definitions: property internal_name of value „P0ABC", and property display of value „My_comp". Both property names and values are case-insensitive. Properties are visible in all template files. However, they are local for its template and cannot be accessed by another template.
"<PROPERTIES>"
internal_name="P0ABC"
display="My_comp"
"</PROPERTIES>"
Fig.5. A sample contents of property definition file properties.conf
Some properties are predefined by the servlet and their role is set while the template is loaded. These properties are presented in the table below.
Property name |
Meaning |
Sample value |
TEMPLATE_LOCATION |
URL address of the directory with template files |
http://www.npac.syr.edu |
CONNECTION_STRING |
Database connection string |
Jdbc:oracle:thin:9001 |
SERVER_PORT |
HTTP port number of a server the template is located |
80 |
HOST_NAME |
Name of the host on which the servlet is running |
taurus.kti.ae.poznan.pl |
SERVLET_DIR |
Server directory where servlets are stored (usually server_root/Java/plugins/servlets) |
Server_root/plugins/srv |
TEMPLATE_ID |
internal servlet template identifier |
cps |
USID |
internal database user identifier of a user who invoked the template |
- |
Note that properties defined in templates (by the use of WW_SET tag described in the next chapter) are accessible in the same way as predefined properties mentioned above.
Each template file has the following structure:
<?TDLTEMPLATE?>
<?XML version="1.0"?>
<WW_DOCUMENT>
...
</WW_DOCUMENT>
with some tags inside a body of the <WW_DOCUMENT> tag. The body is written in TDL language described in Chapter 3. The tag definitions and their corresponding Java methods are user-defined (cf. Section 2.1). The complete example of a template is given in Chapter 5.
Once a template file is read from its HTTP server to the servlet, it is stored in a cache memory called the Template Cache. Each template has its own Template Cache with parameters set independently of each other. Next time the template file is addressed, the local, cached copy is taken rather than the original, remote one. The template files are cached once and stored in the Template Cache as long as their cache is not expired.. Thus, if a servlet is running and a given template file is changed, the cache should be expired to read the new version of this file (cf. Section 2.9).
The servlet uses Microsoft XML Parser to parse contents of a template file. This parser is a validating XML parser written in Java. The parser checks for well-formed documents and optionally permits checking of the documents' validity. Once parsed, the XML document is exposed as a tree. The called parser methods are going to be standardized by W3C consortium. These methods support reading and/or writing XML structures, such as the Channel Definition Format (CDF) or other text formats based on XML, and thereby enable building applications using XML. This version of the parser implements the W3C working draft of the XML specification dated November 17th, 1997.
For general information on XML, see the following:
The interpreter is responsible for parsing the derivation tree generated by the XML parser. As a parsing starting point the root node (corresponding to WW_DOCUMENT tag) is passed. Starting from this node, the tree is recursively parsed. For every node, a new instance of its interpreting Java class is loaded, and one selected method of this class is invoked (cf. Section 2.1 – configuration files). For tags declared as persistent, if this tag was already detected in the current template file, its previously created instance is used rather than a newly created one. Note that for multiple persistent tags related to one Java class (but possibly different methods of this class), their methods can communicate by the use of internal class variables.
Each interpreting method can use built-in servlet method parseChildren(). This method is responsible for recursive parsing of all nodes of the tree corresponding to tags nested in the current tag. If used, this method must be explicitly called from the tag interpreting method.
Each interpreting method may also use another built-in servlet method evaluateExpression(). This method is called with a text as its single argument. The method parses this text and changes all the valid expressions to their current values. Parts of text not being valid expressions are not changed. Detailed expression grammar is presented in the next chapter. The evaluateExpression() method is usually used to find current values of arguments passed to the interpreting method and current values of variables (properties).
Usually, one interpreting method is build over the following schema:
String interpretingMethod (String arg1, ..., String argN)
{
String result="";
arg1=evaluateExpression(arg1);
...
arg1=evaluateExpression(argN);
...Java code being tag interpretation and changing the result variable...
result+=parseChildren();
...Java code being tag interpretation and changing the result variable...
return result;
}
The sender is responsible for sending output - a string of characters being a result of parsing by the Interpreter the tree generated by the XML parser. The output is send back to the HTTP server to be sent to a client.
The output sent by the Sender to the HTTP server is at the same time stored in the Output Cache. If there is a next call to the same template with the same parameters, such cached output is sent back to avoid performing the whole output building cycle described in the previous sections. This approach may significantly improve the servlet performance, especially in the case when multiple users try to access the same data simultaneously (for example students participating in a class). The Output Cache is cleaned after a declared period of time, usually a few seconds. Cache expiration can be also caused by a specified number of hits. It allows more precise tuning of cache utilization. For example, if previously mentioned class of students consists of 12 people, cache expiration could be set to 13 hits (12+teacher). Thus, if data in the database are updated, the template reading this data will be updated too every time the whole class read a part of the course material, even if output for this data has been cached.
The servlet can be configured on-line by the use of any HTML browser. The configuration includes some info pages, as well as template and cache management.
The configuration page is invoked by a URL http://hostname/servlet_config_dir/config.html, where hostname is a network identifier of a server the servlet is running, and servlet_config_dir is any sub-directory in the server WWW document root. After invocation, a page is displayed with basic information about the servlet (Fig. 6): general info (servlet name, version, author(s), a short description), and system info (hostname, free memory).
Fig. 6. Servlet on-line configuration pasic page
The configuration page is divided into three areas. In the upper area there are three buttons: „Servlet", „Template", and „Cache". Pressing each button changes the contents of two frames located below: menu frame on the left side of the page, and data frame on the right side. At the beginning the „Servlet" button is active (cf. Fig. 6). In the menu frame two items can be chosen: „Information" (chosen by default) and „Known Tags". By pressing the latter one, the data frame is filled by a table with currently declared tag definitions (Fig. 7).
Fig. 7. Displaying tag definitions
A definition of each tag includes invoked Java class, method and formal parameters (cf. Section 2.1). The tag definitions can be changed only by a change of the configuration files (cf. Section 2.1) and restarting the servlet.
By pressing the „Template" button new frames are displayed to deal with templates (Fig. 8). The menu frame is equipped with four items: „List templates", „Add template", „Remove Template", and „Properties".
Fig. 8. Displaying template info
The „List templates" item (chosen by default) displays names and localization (URL addresses) of each template defined in the system (cf. Fig. 8). To add a new template, one must click on the „Add Template" item in the menu frame, while to remove a template - on the „Remove Template" item. To display properties (cf. Section 2.1) for a given template, one should click on the „Properties" item in the menu frame. A table with properties for a template is then displayed, in a form „Name"-„Text value" (Fig. 9). System-defined properties are displayed with a red background, while user-defined properties are displayed with orange background. If use-defined properties were not loaded yet (the template was not accessed till the last server restart) corresponding information is displayed below the table. To change a template, one may use a menu located above the table. Only one template can be selected at a time.
Fig. 9. Displaying system-defined properties for a given template
To deal with cache parameters one must press the „Cache" button. The menu frame is changed and contains three items: „Cache Info", „Output Cache", and „Template Cache". By default, the „Cache Info" item is selected and in the data frame some information about caching is displayed (Fig. 10). The information includes: an indicator whether a given cache is active, number of currently cached entries, and current cache buffer size in bytes. There is a button „Expire now" below the information for each cache. This button may be used to clean the cache, i.e., to remove all its entries.
Fig. 10. Displaying cache information
By pressing the „Output cache" item one can set the Output Cache parameters. The data frame is changed to display current parameter values (Fig. 11). By pressing the „On/Off" toggle button one can set the Output Cache to be active or inactive. An information whether the cache is active or not is displayed left to the button. Below the "On/Off" button an information is displayed about current cache entries and the memory used. The button „Expire now" can be used to remove all the entries from the cache.
Fig. 11. Setting the Output Cache parameters
The text fields „Cache timeout" and „Cache maximum hits" are used to define cache behavior. The „Timeout" parameter is used to declare maximum period of time an entry is stored. The expiration time should be set to relatively small value to prevent the situation the data from cache is inaccurate after database update, for example 60 seconds. The „Cache maximum size" parameter is used to declare maximum number of hits for a given entry. If set to „-1", there are no limitations. If set to „0", the cache is not activated (no entries are allowed). If, however, this parameter is greater than zero and a new hit number is greater than its value, then the cache is expired. After setting new values for the parameters one must press the „Apply" button to send the changes to the servlet. After servlet restart, user-defined values are replaced by default ones.
Similar data frame is invoked after pressing the „Template Cache" button, except a name of a given template must be selected (Fig. 12). Note that template caching may be activated and parameters can be selected for each template separately.
Fig. 12. Setting the Template Cache parameters
TDL (Template Definition Language) is an application of XML (Extensible Markup Language) for defining templates. The templates are used by the servlet to format data read from the database. TDL is not computing-complete and has similar power to UNIX shells. The language is based on XML definition on one hand, and typical UNIX shell commands and syntax on the other hand.
A template text is a sequence of XML tags with parameters. A tag is a command read and performed by a parser. As a parse output for a given tag (a set of tags) a part of HTML document is generated. Tags have names and they may have parameters, according to XML syntax. A parameter has a name and a text value. The values may be computed from expressions with syntax based on reverse Polish Notation (described further in details). Examples of tags are: <LOGIN>, <TEXT COLOR="black" SIZE="3">, etc.
Tags are always included inside ‘<’ and ‘>’ brackets. There is no possibility to nest tags, i.e. every ‘<’ character must be accompanied by ‘>’ character before a new ‘<’ is read beginning a new tag. Nevertheless, the language elements may be nested.
There are three types of tags. An empty tag is a stand-alone command that creates no context while it is parsed. Such tag is pointed out by "/" character before the closing ‘>’ bracket. Examples of empty tags are: <DATE/>, <AUTHOR/>, etc.
A pair of start and end tags defines an element. Everything between a start tag and its counterpart is named element’s body and is being interpreted according to the tag type. Start-end pairs of tags may be arbitrarily nested, on condition they are closed by ‘>’ characters. An empty tag may be also nested in a start-end pair of tags. An end tag has the same name as the corresponding start tag, except it has ‘/’ character as its name prefix. Examples of start-end tags are: <AUTHOR> </AUTHOR>, <BOLD> </BOLD>, <TEXTEFFECTS BOLD="on" ITALICS="off"> </TEXTEFFECTS>, etc. Both start and end tags may have parameters, although the parameters are mainly used for start tags.
Tag names and syntax are completely user defined, by the use of the configuration files read by the server before its first execution. This file contains entries composed of tag name, corresponding Java class/method and parameters. In this file, a tag and an appropriate Java class/method to generate HTML output is stored. The methods may query the database. Detailed syntax of a servlet configuration file is described in Section 2.1.
There are also some predefined control tags which do not generate explicit HTML output but are used to control the process of parsing a template. Control tags also can be changed by a user and they are listed in the configuration file. They are based on typical UNIX shell syntax (very limited, however) with extensions specific for XML. Control tags are either empty or start-end tags. Below a list of control tags is presented.
ExpressionsIn most places in TDL instead of simple values, expressions can be used (e.g., to define current values of parameters of some TDL tags). An expression is a string inside apostrophes (") of valid syntax. Expressions are always string-oriented, i.e. arguments as well as an output are strings of characters. Some strings may contain numeric values, evaluated by Java classes/methods to another strings with numeric values. This approach simplifies the process of defining and using templates as well as the servlet internal structure.
To define an order of operations inside an expression, extended Reverse Polish Notation is used.
As expressions being parameters of XML tags are processed outside XML parser, their syntax (described below in details) cannot be changed by a user. There is a possibility, however, to extend expressions by direct calling to Java methods performing specific operations on their parameters. For example, it is possible to implement arithmetic operations, advanced operations on strings, specialized database queries, etc.
Boolean values are defined by special strings: false by the empty string, and true by any non-empty string, in particular "true". This implementation detail, however, should not be explicitly addressed by templates, i.e. one should avoid using syntax like <WW_IF CONDITION="">.
Expressions are given in ‘"’ characters according to XML rules. Expressions are evaluated from left to right, and every evaluated part is concatenated at the end of the output string. Non-string elements (functions, constants, and variables) are always prefixed by special characters. This approach is similar to the one used in UNIX shell scripts and "printf" function in C/C++ programming language.
The simplified syntax for expressions is given below in BNF-like notation.
Expression ::= Variable |
Constant |
%equ[al](ExpressionList) |
%dif[ferent] (ExpressionList) |
%or (ExpressionList) |
%and (ExpressionList) |
%gre[ater] (ExpressionList) |
%les[s] (ExpressionList) |
%nog[reater] (ExpressionList) |
%nol[ess] (ExpressionList) |
%tol[ower] (ExpressionList) |
%tou[pper] (ExpressionList) |
%tri[m] (ExpressionList) |
%nos[pace] (ExpressionList) |
%add(ExpressionList) |
%mul[tiply](ExpressionList) |
%div[ide](ExpressionList) |
%sub[stract](ExpressionList) |
%sum(ExpressionList) |
%min[imum](ExpressionList) |
%max[imum](ExpressionList) |
%not (Expression)
ExpressionList ::= Expression , ExpressionList |
Expression
Variable ::= ${variable_name} |
// access to a value of a variable`class.method(par)`
//direct Java invocation,//the string must not contain ‘`’
character$$ | ${$} |
// ‘$’ character itself$` | ${`} |
// ‘`’ character itself$% | ${%} |
// ‘%’ character itself$, | ${,} |
// ‘,’ character itself$} |
// ‘}’ character itself${quot} |
// ’"’ character itself${true} |
// boolean value "true"${false} |
// boolean value false, equivalent to an empty string$$
Constant ::= string |
// string with no delimiters (may have ‘}’ characters inside)%{string}
// any string of characters with no ‘}’ character insideFunctions prefixed by ‘%’ character can have any number of parameters (separated by ‘,’ characters) starting from one parameter. All the parameters are evaluated from left to right. For example, a call "%equal(ANNA, DOROTHY, EVE)" gives false as a result, while "%equal(2,2,2,2,2)" - true. Of course, they may be invoked with exactly two parameters as in classical programming languages.
Variable_name is a string-based name of a variable. The name must not contain "}" character. A value of a variable is also string-based. If a variable was not set before first access for its value, this value is automatically set to an empty string at the moment of the access. There is a possibility to perform arithmetic operation on variables – in such case Java methods treat strings as encoded numbers of type "integer" or "real".
${variable_name} stands for an access to a value of a given variable.
Sub-parts of expressions inside a pair of ‘`’ characters are treated as calls to Java methods. In such a case, first all the prefixes inside the sub-expressions are detected and evaluated (recursively), eventually updating a string being a Java call. Next, the resulted string is evaluated as a call to Java method of a given class with given parameters. For example, a sub-expression:
`math.add(${foil_number},1)`
is first evaluated to (assuming a value of the variable "foil_number" is currently equal to "44")
`math.add(44,"1")`
and finally after performing a Java call to string "45", while sub-expression:
`string.add(${quot}${foil_name}${quot},${quot} number${quot})`
is first evaluated to (assuming a value of the variable "foil_name" is currently equal to "Appendix")
`string.add("Appendix"," number")`
and finally after performing a Java call to string "Appendix number".
Some variables are predefined by the servlet (as properties, cf. Section 2.1).
Prefix ‘%’ for a string-based constant is added for simplicity, to facilitate entering strings containing special characters used usually as prefixes for functions and variables. For example, one can use any of the below expressions to enter string "100% and $100,00":
"100${%} and ${$}100,00"
or simply:
"%{100% and $100,00}"
Examples of expressions are:
"some ${var1} have ${var2}"
// for var1=animals , var2=eyes, output is "some animals have eyes""Author: `databaseDirectCall.getAuthorName()`"
// sample output is "Author: Smith"TDL allows for conditional inclusion of fragments of templates. Conditional statements are expressed by the WW_IF element. It is a non-empty XML element whose body is included in the outcome only when the specified condition is satisfied. This element has an optional part(s) included when the specified condition is not satisfied.
The syntax of the IF statement is the following:
<WW_IF CONDITION="...">
<WW_THEN>
</WW_THEN>
<WW_ELSE>
</WW_ELSE>
</WW_IF>
Inside the WW_IF element an optional WW_ELSE element can be included. If the condition evaluates to true, the code included in the WW_THEN element is interpreted. Otherwise the part of code included in the WW_ELSE element is interpreted. There could be multiple WW_ELSE and WW_THEN parts. These parts must be included between WW_IF and /WW_IF tags. The case when it is only one WW_THEN part, followed by WW_ELSE part, followed immediately by /WW_IF tag is similar to typical IF-THEN-ELSE control statement from many programming languages.
The WW_IF tag has only one attribute: CONDITION. This attribute contains an expression string that is evaluated to a boolean value.
In TDL one can assign a value to a variable by the use of the WW_SET tag. This is an empty tag and it does not generate any output.
The WW_SET element has the following syntax:
<WW_SET NAME="..." VALUE="..."/>
The WW_SET tag uses two attributes.
Values of internal servlet variables and dynamically computed expressions can be included into the output by the use of WW_INSERT command. This command is implemented by empty WW_INSERT tag. Note that, in comparison to WW_SET tag, this tag generates directly an output rather than storing a new value of a given variable.
The syntax of the WW_INSERT element is the following:
<WW_INSERT VALUE="..."/>
The parser replaces the WW_INSERT tag with the value calculated from the contents of the VALUE attribute being an expression.
Before the servlet can connect to a database it must be provided with some connection parameters. These parameters include:
Connection to a database is specified by WW_CONNECT element. The required connection parameters are concatenated into one connection string attribute with JDBC-like syntax.
The syntax of the WW_CONNECT element is the following:
<WW_CONNECT CONN_STRING="..."/>
The WW_CONNECT element must precede all database access elements.
Invoking another template fileThe control may be passed from one template file to another by the use of <WW_LINK> element. In the attributes of this element one can specify a filename of a template file the control is passed to, and some parameters. The parameters are separated by ‘|’ character. Each parameter definition is composed of a parameter name (i.e., a property for a calling template file) and an expression reflecting current property value, separated by ‘=’ character. For example, the text ATTR="PID=1 | FID=${FID}" is a definition of two parameters, the first one with name PID and constant value 1, and the second one with name FID and a value equal to current value of variable FID.
The syntax of the WW_LINK element is the following:
<WW_LINK FILENAME="..." ATTR="..."/>
The WW_INLINE tag is used to include a text of one template file in the other template file, before this file is parsed by the XML Parser module. This mechanism is similar to #include preprocessor command known from many programming languages, for example C/C++. The content of the file pointed by tag argument is put instead of the tag just before the template file is going to be parsed. The included template file may also contain WW_INLINE tags pointing to other template files.
The syntax of the WW_INLINE element is the following:
<WW_INLINE FILENAME="filename">
Note that the current property values are passed to the sub-templates. Thus, the WW_INLINE tag can be treated as a kind of a macro definition.
The servlet is equipped with a set of methods to be used in user-defined interpretation methods for tags. These methods are provided as parts of system-defined abstract class TDLTag. To define an interpretation method for a tag one should first create a new class (of any name) being an extension of the TDLTag class and next provide in it a method to interpret the tag:
public class Tags extends TDLTag {
//private variables
interpretation_method(String param1, …, String paramN) {
…
}
// private functions
}
The interpretation_method may use any of the build-in API functions described in Section 4.1. Sample interpretation functions for control tags are described in Section 4.2.
The classes and methods for tag interpretation must be declared in the configuration file servlet_tdl.conf (cf. Section 2.1).
API functions from TDLTag abstract classpublic abstract class TDLTag {
public TDLTag() {}
// empty contructor
public InputStream getFileHandle (String fileName);
// returning a handle to current template file
public void removeAttrValue (String name);
// removing a property from property table
public String getStringAttrValue(String name);
// getting a value of a property and returning it as a string
public int getIntAttrValue(String name);
// getting a value of a property and returning it as an integer value
// if a conversion from string to integer cannot be done, returning value 0
public float getFloatAttrValue(String name);
// getting a value of a property and returning it as a float value
// if a conversion from string to integer cannot be done,
// returning value 0.0
public boolean setStringAttrValue(String name, String value);
// setting a string value of a property
// returning true if everything is OK, false if a property cannot be set
public boolean setFloatAttrValue(String name, float value) {
// setting a float value of a property
// returning true if everything is OK, false if a property cannot be set
public boolean setIntAttrValue(String name, int value) {
// setting an integer value of a property
// returning true if everything is OK, false if a property cannot be set
final String parseChildren();
// parsing body of the tag
public String evaluateExpression (String expression);
// parsing string from left to right
// and evaluating all the valid expressions to their current values
// parts of string not being valid expressions remain unchanged
}
import java.io.*;
import java.util.*;
import java.sql.*;
import java.sql.Date;
import db.*;
import view.*;
public class Tags extends TDLTag {
...
/**
* Main tag for all TDL documents. Standard TDL tag implementation.
* @return Parsed contents
*/
public String WW_DOCUMENT () {
return parseChildren();
// parse all children
}
/**
* IF statement. Standard TDL tag implementation.
* <b>Must be used with THEN and/or ELSE tags</b>.
* @param condition - <code>if</code> condition
* @return Parsed contents
*/
public String WW_IF (String condition) {
String res="";
condition = evaluateExpression(condition);
setIntAttrValue(Constants.IFLevelProperty,
getIntAttrValue(Constants.IFLevelProperty)+1);
// setting a temporary property with current value of the condition
if (condition!="")
setIntAttrValue(Constants.IFLevelConditionProperty+
getIntAttrValue(Constants.IFLevelProperty),1);
else
setIntAttrValue(Constants.IFLevelConditionProperty+
getIntAttrValue(Constants.IFLevelProperty),0);
res+=parseChildren();
// removing temporary property
removeAttrValue(Constants.IFLevelConditionProperty+
getIntAttrValue(Constants.IFLevelProperty));
setIntAttrValue(Constants.IFLevelProperty,
getIntAttrValue(Constants.IFLevelProperty)-1);
return res;
}
/**
* THEN statement. Standard TDL tag implementation.
* Have to be used only in IF tag context.
* @return Parsed contents
*/
public String WW_THEN () {
if (getIntAttrValue(Constants.IFLevelConditionProperty+
getIntAttrValue(Constants.IFLevelProperty))==1)
return parseChildren();
else
return "";
}
/**
* ELSE statement. Standard TDL tag implementation.
* Have to be used only in IF tag context.
* @return Parsed contents
*/
public String WW_ELSE () {
if (getIntAttrValue(Constants.IFLevelConditionProperty+
getIntAttrValue(Constants.IFLevelProperty))==0)
return parseChildren();
else
return "";
}
/**
* Inserts result of the calculation or the variable value.
* Standard TDL tag implementation.
* @param name - variable or expression
* @return String with a value
*/
public String WW_INSERT(String name) {
return evaluateExpression(name);
}
/**
* Inserting result of the calculation or the variable value
* into <code>name</code> variable. Standard TDL tag implementation.
* @param name - name of the variable
* @param value - variable or expression value
* @return Empty string
*/
public String WW_SET (String name, String value) {
name = evaluateExpression(name);
value = evaluateExpression(value);
setStringAttrValue(name,value);
return "";
}
/**
* Connecting to database. Standard TDL tag implementation.
* @param connection - connection string, if <code>connection</code> is empty,
* default value is taken from property file.
* @return Empty string
*/
public String WW_CONNECT (String connection) {
connection = evaluateExpression(connection);
if (connection.equals(""))
connection=getStringAttrValue(Constants.ConnectionStringProperty);
else
setStringAttrValue(Constants.ConnectionStringProperty,connection);
try {
setConn (DriverManager.getConnection(connection));
} catch (SQLException e) {
ExceptionHandler.handleException(e,"TAGS:WW_CONNECT");
}
return "";
}
...
}
/**
* Process its contents inserting into the <code>name</code> variable
* id’s of foilworlds that are in the foilworld specified by <code>fwid<code>
*
* @param fwID - foilworld id
* @param name - name of the variable
*
* @return Parsed contents
*
* @version 1.0 07/15/98
*/
public String WW_FOILWORLDLOOP (String fwID, String name) {
name = evaluateExpression(name);
fwID = evaluateExpression(fwID);
String res = "";
String query = "SELECT WID FROM FOILWORLD WHERE BUFFER_OWNER_UID IS
NULL AND WID<>1 AND BELONGS_TO_WID = "+fwID+" ORDER BY NAME";
try {
Statement sqlStatement =
tdlTemplate.getCon().createStatement();
ResultSet rs = sqlStatement.executeQuery(query);
while (rs.next()) {
setStringAttrValue(name,rs.getString("WID"));
res+=parseChildren();
}
rs.close(); sqlStatement.close();
} catch (SQLException e) {
ExceptionHandler.handleException(e,"TAGS:WW_FOILWORLDLOOP");
}
return res;
}
/**
* Process the contents inserting into the <code>name</code> variable
* id's of presentations from the foilworld specified by <code>fwid<code>
*
* @param fwID - foilworld id
* @param name - name of the variable
*
* @return Parsed contents
*
* @version 1.0 07/15/98
*/
public String WW_PRESENTATIONLOOP (String fwID, String name) {
name = evaluateExpression(name);
fwID = evaluateExpression(fwID);
String res = "";
String query = "SELECT COMPONENT_PID FROM FW_CONTAIN_PR WHERE
CONTAINER_WID="+fwID;
try {
Statement sqlStatement =
tdlTemplate.getCon().createStatement();
ResultSet rs = sqlStatement.executeQuery(query);
while (rs.next()) {
setStringAttrValue(name,rs.getString("COMPONENT_PID"));
res+=parseChildren();
}
rs.close(); sqlStatement.close();
} catch (SQLException e) {
ExceptionHandler.handleException(e,"TAGS:WW_PRESENTATIONLOOP");
}
return res;
}
/**
* Process the contents inserting into the <code>name</code> variable foil
* id's from the presentation specified by <code>parentID<code>
*
* @param parentID - presentation id
* @param name - name of the variable
*
* @return Parsed contents
*
* @version 1.0 07/15/98
*/
public String WW_FOILLOOP (String parentID, String name) {
name = evaluateExpression(name);
parentID = evaluateExpression(parentID);
String res="";
Vector vc = new Vector();
fillFoilID(parentID, vc);
Enumeration en = vc.elements();
while (en.hasMoreElements()) {
setStringAttrValue(name,(String)en.nextElement());
res+=parseChildren();
}
return res;
}
Basic system requirements to use the TESS system are the following:
The details of the servlet installation depend on the HTTP server used. In this chapter an installation of the servlet for Netscape Enterprise Server is described. File and directory names for other HTTP servers may differ.
The installation procedure of the servlet includes the following:
After completing the above steps, the servlet installation procedure is completed and the servlet may be used. Note, however, that if the servlet uses any Java extension libraries, Java code for these libraries and all the necessary drivers (for example database access drivers and JDBC library) must be installed before the servlet is used for the first time. These classes should be copied to the same directory the servlet Java classes are copied.
This template is used in the WebWisdom NT 2.1 system do give access to foils and other teaching material. This is a template originally prepared for WebWisdom 1.0 system and it was adapted with some changes.
Tag definitionThere is a set of tags defined in the servlet configuration file to be used with the „CPS" template. The tag names begin with „WW_" prefix. In the table below all tags used by the „CPS" template are presented in details. All the tags except WW_COUNTER are declared as non-persistent (cf. Section 2.1).
Tag name |
Java class/method invoked |
Purpose |
WW_ABSMISSING |
Tags.WW_ABSMISSING ( PRESENTATIONID) |
inserting HTML "HREF" link to the template file that is capable to access an image version of an abstract of presentation PARENTID |
WW_ABSTRACTIMAGE |
Tags.WW_ABSTRACTIMAGE ( PRESENTATIONID) |
inserting an image of an abstract of presentation PRESENTATIONID |
WW_ABSTRACTTEXT |
Tags.WW_ABSTRACTTEXT ( PRESENTATIONID) |
inserting a text (HTML bulleted list) of an abstract of presentation PRESENTATIONID |
WW_ADDON |
Tags.WW_ADDON ( FOILID, PARENTID) |
inserting add-on for foil FOILID in presentation PARENTID |
WW_ANNOTATION |
Tags.WW_ANNOTATION ( |
inserting an annotation belonging to presentation PRESENTATIONID at position POSITION |
WW_AUTHORNAME |
Tags.WW_AUTHORNAME ( FOILID, PARENTID) |
inserting name of primary author of foil FOILID in presentation PARENTID |
WW_BODYIMAGE |
Tags.WW_BODYIMAGE (FOILID, PARENTID) |
inserting 'body' HTML tag with background image typical for foil files for foil FOILID in presentation PARENTID |
WW_BODYINDEX |
Tags.WW_BODYINDEX ( PRESENTATIONID) |
inserting 'body' HTML tag with background image typical for index files for presentation PRESENTATIONID |
WW_BODYSEPHTML |
Tags.WW_BODYSEPHTML ( FOILID, PRESENTATIONID) |
inserting HTML "BODY" tag for templates for displaying text-based HTML version of foil FOILID in presentation PRESENTATIONID rather than its image version |
WW_CONNECT |
Tags.WW_CONNECT ( CONNECTION) |
connecting to the database with connection string CONNECTION |
WW_COUNTER |
Pers.WW_COUNTER( ) |
the only persistent tag counting references to the template |
WW_CREATIONDATE |
Tags.WW_CREATIONDATE ( FOILID) |
inserting date of creation of foil FOILID |
WW_DBSET |
Tags.WW_DBSET ( NAME, PROPNAME, PROPTYPE, FOILID, PARENTID) |
taking signature value from database property in context of current user, presentation, and foil; PROPTYPE attribute specifies the type of the property, ('overall' in case of the signature), PROPNAME specifies the database property name; the value of the property is assigned to a variable with name given by NAME attribute |
WW_DEFAULTBG |
Tags.WW_DEFAULTBG ( ) |
taking default background image for foils |
WW_DEFAULTLOGO |
Tags.WW_DEFAULTLOGO ( ) |
taking defaults logo image |
WW_DOCUMENT |
Tags.WW_DOCUMENT ( ) |
root XML/TDL „document" tag, a container for all other tags (like an 'html' tag in HTML) |
WW_ELSE |
Tags.WW_ELSE ( ) |
ELSE control statement |
WW_EVENT |
Tags.WW_EVENT ( FOILID ) |
inserting primary event related to a foil FOILID |
WW_EVENTDATE |
Tags.WW_EVENTDATE ( FOILID) |
inserting primary event date of an event associated with FOILID |
WW_EXTERNALURL |
Tags.WW_EXTERNALURL ( FOILID, PARENTID ) |
inserting HREF tag pointed to external location for foil FOILID in presentation PARENTID |
WW_FIRSTFOIL |
Tags.WW_FIRSTFOIL ( PARENTID, NAME ) |
inserting into NAME variable identifier of the first foil of presentation PARENTID |
WW_FOIL |
Tags.WW_FOIL ( FOILID, PARENTID, MODE ) |
inserting an image or text-based version of foil FOILID in presentation PARENTID based on MODE value (IMAGE,TEXT or ASNEEDED) |
WW_FOILIMAGE |
Tags.WW_FOILIMAGE ( FOILID, PARENTID ) |
inserting an image of foil FOILID in presentation PARENTID |
WW_FOILLINK |
Tags.WW_FOILLINK ( FOILID, FILENAME, ATTR ) |
inserting a HREF link to template file FILENAME with foil FOILID and parameters ATTR; it allows to create an 'index' of all foils contained in a given presentation |
WW_FOILLOOP |
Tags.WW_FOILLOOP ( PARENTID, NAME ) |
tag iterates for all foils in PARENTID presentation each time assigning current child foil ID to NAME variable |
WW_FOILNUMBER |
Tags.WW_FOILNUMBER ( PARENTID, FOILID ) |
inserting foil number for foil FOILID in presentation PARENTID |
WW_FOILTEXT |
Tags.WW_FOILTEXT ( FOILID ) |
inserting HTML bulleted list of foil FOILID |
WW_FOILWORLDLINK |
Tags.WW_FOILWORLDLINK ( FWID, FILENAME, ATTR) |
inserting a HREF link to template file FILENAME with foilworld FWID and parameters ATTR; it allows to create an 'index' of all foilworlds contained in a given foilworld |
WW_FOILWORLDLOOP |
Tags.WW_FOILWORLDLOOP ( FWID, NAME ) |
parsing in a loop contents of foilworld FWID, setting for each loop pass a variable given by NAME attribute. This variable contains an identifier of a 'child' foilworld. The loop is repeated as many times as many child foilworlds the given foilworld contains. |
WW_FWPARENTLINK |
Tags.WW_FWPARENTLINK ( FWID, FILENAME, ATTR) |
inserting HREF tag with a pointer to foilworld containing current presentation by the use of template file FILENAME with attributes ATTR |
WW_IF |
Tags.WW_IF ( CONDITION ) |
IF control statement |
WW_IMAGE |
Tags.WW_IMAGE ( IMAGENAME, FOILID, PARENTID ) |
inserting an image of name IMAGENAME associated with foil FOILID in presentation PARENTID |
WW_INSERT |
Tags.WW_INSERT ( NAME ) |
inserting current value of an expression to evaluate; an expression could be a variable evaluation |
WW_LINK |
Tags.WW_LINK ( FILENAME, ATTR) |
inserting contents generate by the use of another template file FILENAME invoked with parameters ATTR |
WW_LOGIN |
Tags.WW_LOGIN ( ) |
log-in page to the WebWisdom NT system |
WW_LOGINFORM |
Tags.WW_LOGINFORM( ) Built-in servlet method |
user identification form - after detecting this tag the "SUBMIT" button of this form will redirect control to the special template file – "index.tdl" (cf. Section 2.3) |
WW_MISSING |
Tags.WW_MISSING ( FOILID, PARENTID ) |
inserting HTML "HREF" link to the template file that is capable to access an image version of foil FOILID in presentation PARENTID |
WW_MODIFICATIONDATE |
Tags.WW_MODIFICATIONDATE ( FOILID ) |
inserting date of last modification of foil FOILID |
WW_NEXT |
Tags.WW_NEXT ( PARENTID, FOILID, FILENAME, IMAGENAME ) |
inserting a button with HREF links to template file FILENAME with next foil in the presentation PARENTID after foil FOILID; IMAGENAME is a name of the property defining image |
WW_NOBULLETSIFGIF |
Tags.WW_NOBULLETSIFGIF ( FOILID) |
inserting HTML bulleted text if there is no corresponding image for foil FOILID |
WW_NOTE |
Tags.WW_NOTE( FOILID, PARENTID) |
Inserting a HTML bulleted list of a note of foil FOILID in presentation PARENTID |
WW_NUMBEROFFOILS |
Tags.WW_NUMBEROFFOILS ( PARENTID ) |
inserting number of foils in presentation PARENTID |
WW_OWNERNAME |
Tags.WW_OWNERNAME ( FOILID) |
inserting name of owner of foil FOILID |
WW_PASSWORD |
Tags.WW_PASSWORD( ) Build-in servlet method |
user identification tag – a text field in the log-in form to enter user’s password |
WW_PRESENTATIONLINK |
Tags.WW_PRESENTATIONLINK ( PRESENTATIONID, FILENAME, ATTR) |
inserting a HREF link to template file FILENAME with presentation PRESENTATIONID and parameters ATTR; it allows to create an 'index' of all presentations contained in a given foilworld |
WW_PRESENTATIONLOOP |
Tags.WW_PRESENTATIONLOOP ( FWID, NAME) |
parsing in a loop contents of foilworld PARENTID, setting for each loop pass a variable given by NAME attribute. This variable contains an identifier of a child presentation. The loop is repeated as many times as many presentations the given foilworld contains. |
WW_PREV |
Tags.WW_PREV ( PARENTID, FOILID, FILENAME, IMAGENAME) |
inserting a button with HREF links to template file FILENAME with previous foil in the presentation PARENTID before foil FOILID; IMAGENAME is a name of the property defining image |
WW_RUNNINGTITLE |
Tags.WW_RUNNINGTITLE ( FOILID) |
inserting foil „running title" of foil FOILID |
WW_SELECTADDON |
Tags.WW_SELECTADDON ( FOILID, NAME) |
checking for the existence of add-on in foil FOILID; if an add-on is associated with the specified foil, the ID of the database object containing add-on is inserted into variable given by the NAME attribute. |
WW_SELECTCOMMENT |
Tags.WW_SELECTCOMMENT ( FOILID) |
inserting text-based comment for foil FOILID |
WW_SELECTDISPMODE |
Tags.WW_SELECTDISPMODE ( FOILID, NAME) |
tag inserts into variable with name given by NAME attribute the preferred display mode of foil FOILID |
WW_SELECTEXTERNAL |
Tags.WW_SELECTEXTERNAL ( FOILID) |
if there is an external link defined for foil FOILID, parsing body of the tag |
WW_SELECTIMAGE |
Tags.WW_SELECTIMAGE ( FOILID) |
if there is an image defined for foil FOILID, parsing body of the tag |
WW_SELECTNOTE |
Tags.WW_SELECTNOTE ( FOILID) |
if there is a note defined for foil FOILID, parsing body of the tag |
WW_SELECTSOUND |
Tags.WW_SELECTSOUND ( FOILID, NAME) |
checking for the existence of sound in foil FOILID; if a sound is associated with the specified foil, the ID of the database object containing sound is inserted into variable given by the NAME attribute. |
WW_SELECTSOURCEFOIL |
Tags.WW_SELECTSOURCEFOIL ( FOILID) |
if there is source PowerPoint file defined for foil FOILID, parsing body of the tag |
WW_SELECTSOURCEMASTER |
Tags.WW_SELECTSOURCEMASTER( FOILID) |
if there is source PowerPoint "master" file for foil FOILID, parsing body of the tag |
WW_SELECTSOURCEPRES |
Tags.WW_SELECTSOURCEPRES ( FOILID) |
if there is source PowerPoint file with presentation containing source for foil FOILID, parsing body of the tag |
WW_SELECTTEXT |
Tags.WW_SELECTTEXT ( FOILID) |
if there is HTML-based text data defined for foil FOILID, parsing body of the tag |
WW_SET |
Tags.WW_SET ( NAME, VALUE) |
setting a new value VALUE for a variable (property) NAME |
WW_SETPOSITION |
Tags.WW_SETPOSITION ( |
innserting foil position of foil FOILID in presentation PARENTID into variable NAME |
WW_SOUND |
Tags.WW_SOUND (FOILID, PARENTID) |
inserting sound data for foil FOILID in presentation PARENTID |
WW_THEN |
Tags.WW_THEN ( ) |
THEN control statement |
WW_TITLE |
Tags.WW_TITLE ( FOILID) |
inserting foil title of foil FOILID |
WW_TITLEFOILWORLD |
Tags.WW_TITLEFOILWORLD ( FWID) |
inserting a title of foilworld FWID |
WW_USERNAME |
Tags.WW_USERNAME( Built-in servlet method |
user identification tag – a text field in the log-in form to enter user’s name |
In the succeeding sections of this chapter the „CPS" template files are presented with some comments inside describing a purpose of using some tags. The TDL tags are printed in bold.
<?WWTEMPLATE>
<?XML VERSION="1.0" CACHE="NO"?>
<WW_DOCUMENT>
<!-- This is a first file of the template.
If in the URL, after the name of the template, the filename is omitted,
the index.tdl file is read by default.
-->
<!-- ?WWTEMPLATE and ?XML tags form a header for all template files.
CACHE attribute of the XML tag specifies whether the servlet should cache
this file or not.
-->
<!-- The main task of this file is to redirect a user to a list of foilworlds.
This is implemented by a JavaScript function that redirects to
the following URL:
tempfoilworld.tdl?FWID=1.
The tempfoilworld.tdl file lists all foilworlds and presentations
in a foilworld identified by FWID parameter (1 identifies the root foilworld)
-->
<html>
<head>
<title>Get WebWisdom NT Started</title>
</head>
<script LANGUAGE="JavaScript">
<!-- function a ()
{top.location.href = "tempfoilworld.tdl?FWID=1";}
-->
</script>
<body background="greymarb.gif" >
<h1>Click The Correct Button to Get to WebWisdom NT</h1>
<form>
<b>Click this if you have Netscape 3.0(but not 2.0 which is confused by Complex Javascript). <br> If you don't have a JavaScript Multiframe system,
other links below form will take you to where you want to go with lower technology!<br>
</b>
<form>
<input type="button" value="Start Click Here!" onClick="a()">
</form>
<br>WebWisdom NT is a JavaScript and servlet-based system for managing hierarchically arranged information such as you get in Education as you span lectures, courses, degrees, departments, Universities. The database available here illustrates 3 worlds:
<b>
<ul>
<li>Administration,
<li>The Virtual University with Courses(electronic foils) and the
<li>Virtual Family (photo sets)</b>
</ul>
<center><img align=top src="WEBWIS2.JPG" BORDER="5" HSPACE="5" VSPACE="5"></center>
<br>
<br>
<center><h2>The Tree of Wisdom </h2></center>
<center><img src="maplerun7.gif" ></center>
</body>
</html>
</WW_DOCUMENT>
<?WWTEMPLATE>
<?XML VERSION="1.0" CACHE="NO"?>
<WW_DOCUMENT>
<WW_CONNECT CONNECTION=""/>
<!-- See comments in tempfoilsepimage.tdl for detailed info-->
<html>
<head>
<title> Separate HTML for LOCAL Foil
<WW_FOILNUMBER PARENTID="${PID}" FOILID="${FID}"/> <WW_TITLE FOILID="${FID}"/>
</title>
</head>
<WW_BODYSEPHTML/>
<b>
<WW_LINK FILENAME="temphelp.tdl" ATTR="">HELP!</WW_LINK>
GREY=local</b><tt> LOCAL HTML version of Foils prepared
<WW_MODIFICATIONDATE FOILID="${FID}"/> </tt>
<h2> Foil <WW_FOILNUMBER PARENTID="${PID}" FOILID="${FID}"/>
<WW_TITLE FOILID="${FID}"/> </h2>
<b> <i>From</i>
<WW_RUNNINGTITLE FOILID="${FID}"/>
<WW_EVENT FOILID="${FID}"/> --
<WW_EVENTDATE FOILID="${FID}"/>. <i>by</i>
<WW_AUTHORNAME FOILID="${FID}"/> </b> *
<WW_MISSING FOILID="${FID}" PARENTID="${PID}"/>
<hr>
<!-- WW_NEXT and WW_PREV insert buttons with HREF links to next and
previous foil in the current presentation. FOILID and PARENTID
attributes specify IDs of current foil and current presentation,
FILENAME is a template filename (usually the same as current)
and IMAGENAME is a name of the property defining image
that should be used for the button.
-->
<WW_NEXT FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsephtml.tdl" IMAGENAME="ww_next"/>
<WW_PREV FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsephtml.tdl" IMAGENAME="ww_prev"/>
<WW_LINK FILENAME="tempfullindex.tdl" ATTR="PID=${PID}">
<WW_IMAGE IMAGENAME="ww_up" FOILID="${FID}" PARENTID="${PID}"/>
</WW_LINK>
<!-- WW_SELECTSOUND checks for the existence of sound in the
foil. If a sound is associated with the specified foil, the ID of the
eduobject containing sound is inserted into variable given by the NAME
attribute.
The same is accomplished by WW_SELECTADDON tag for presentation/foil
add-ons
-->
<WW_SELECTSOUND FOILID="${FID}" NAME="ISSOUND">
<INSERT NAME="${ISSOUND}"/>
</WW_SELECTSOUND>
<WW_SELECTADDON FOILID="${FID}" NAME="ISADDON">
<INSERT NAME="${ISADDON}"/>
</WW_SELECTADDON>
<hr>
<WW_FOILTEXT FOILID="${FID}"/>
<hr>
<WW_NEXT FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsephtml.tdl" IMAGENAME="ww_next"/>
<WW_PREV FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsephtml.tdl" IMAGENAME="ww_prev"/>
<WW_LINK FILENAME="tempfullindex.tdl" ATTR="PID=${PID}">
<WW_IMAGE IMAGENAME="ww_up" FOILID="${FID}" PARENTID="${PID}"/>
</WW_LINK>
<!-- The following pair of tags inserts into output text the signature
for current foil/presentation.
First the WW_DBSET tag takes signature value from database property
in context of current user, presentation, and foil.
PROPTYPE attribute specifies the type of the property
('overall' in case of the signature),
PROPNAME specifies the database property name.
The value of the property is assigned to a variable with name given
by NAME attribute - here: SIG.
WW_INSERT inserts the value of the signature (here variable value)
into output text.
-->
<WW_DBSET NAME="SIG" PROPNAME="signature" PROPTYPE="OVERALL" FOILID="${FID}" PARENTID="${PID}"/>
<WW_INSERT NAME="${SIG}"/>
</WW_DOCUMENT>
<?WWTEMPLATE>
<?XML VERSION="1.0" CACHE="NO"?>
<WW_DOCUMENT>
<!-- ?WWTEMPLATE and ?XML tags form a header for all template files.
CACHE attribute of the XML tag specifies whether the servlet should
cache the file or not.
-->
<!-- WW_CONNECT is a tag that establishes a connection to the database.
Connection string may be supplied in the CONNECTION attribute,
or if it is omitted (empty string) the default connection string is
taken from properties.txt file for current template.
-->
<WW_CONNECT CONNECTION=""/>
<html>
<head>
<title> Separate IMAGE for LOCAL foil
<!-- WW_FOILNUMBER tag takes the position of the current foil in the current
presentation.
BUG! Because of the presentation nesting it returns false results
for nested presentations and foils
-->
<WW_FOILNUMBER PARENTID="${PID}" FOILID="${FID}"/>
<!-- WW_TITLE is a tag that allows to insert title of a presentation or foil.
The presentation/foil is identified by an ID supplied in FOILID attribute.
PARENTID is not currently used by the WW_TITLE tag, but can be later
used, e.g. to check the formatting properties, which can be defined on
the presentation level.
FID and PID were supplied by the servlet from query attributes of the URL
-->
<WW_TITLE FOILID="${FID}"/> </title>
</head>
<!-- WW_BODYIMAGE inserts a 'body' HTML tag with background image typical
for foil files. This tag should be reimplemented to take images from DB
-->
<WW_BODYIMAGE/>
<tt><a href="#image">Image</a><a href="#buttons"> Buttons</a> </tt>
<b><WW_LINK FILENAME="temphelp.tdl" ATTR="">HELP!</WW_LINK>
* GREY=local</b><tt> LOCAL IMAGE version of Foils prepared
<!-- WW_MODIFICATIONDATE inserts modification date of the current foil -->
<WW_MODIFICATIONDATE FOILID="${FID}"/> </tt>
<h2> Foil <WW_FOILNUMBER PARENTID="${PID}" FOILID="${FID}"/>
<WW_TITLE FOILID="${FID}"/> </h2>
<b> <i> From </i>
<!-- WW_RUNNINGTITLE inserts running title of the specified foil. WW_EVENT,
WW_EVENTDATE, and WW_AUTHORNAME get appropriate data for the current foil
from the database
-->
<WW_RUNNINGTITLE FOILID="${FID}"/>
<WW_EVENT FOILID="${FID}"/> -- <WW_EVENTDATE FOILID="${FID}"/>. <i>by</i> <WW_AUTHORNAME FOILID="${FID}"/></b>
<!-- This WW_LINK tag inserts a link to the HTML version of the
current foil -->
<WW_LINK FILENAME="tempfoilsephtml.tdl" ATTR="FID=${FID}|PID=${PID}">* HTML Version</WW_LINK>
<hr>
<a name="buttons">
<!-- WW_NEXT and WW_PREV insert buttons with HREF links to next and
previous foil in the current presentation. FOILID and PARENTID attributes
are IDs of current foil and current presentation, FILENAME is a template
filename (usually the same as the current),
and IMAGENAME is a property name specifying the image that should be
used for link button.
-->
<WW_NEXT FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsepimage.tdl" IMAGENAME="ww_next"/>
<WW_PREV FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsepimage.tdl" IMAGENAME="ww_prev"/>
<WW_LINK FILENAME="tempfullindex.tdl" ATTR="PID=${PID}">
<WW_IMAGE IMAGENAME="ww_up" FOILID="${FID}" PARENTID="${PID}"/>
</WW_LINK>
<!-- WW_SELECTSOUND checks for the existence of the sound in the
foil. If a sound object is associated with the specified foil, the ID of
the eduobject containing sound is assigned to a variable given by
NAME attribute.
The same accomplished by WW_SELECTADDON tag for presentation/foil add-ons
-->
<WW_SELECTSOUND FOILID="${FID}" NAME="ISSOUND">
<INSERT NAME="${ISSOUND}"/>
</WW_SELECTSOUND>
<WW_SELECTADDON FOILID="${FID}" NAME="ISADDON">
<INSERT NAME="${ISADDON}"/>
</WW_SELECTADDON>
<hr>
<!-- WW_NOBULLETSIFGIF checks for existence of the foil image.
If the foil specified in FOILID attribute has no image, the element
contents will be parsed.
Because inside WW_NOBULLETSIFGIF there is a WW_FOILTEXT tag,
the table with foil text will be displayed if this foil has no image.
If foil has an image, the contents of WW_NOBULLETSIFGIF will be ignored.
(this tag should be named WW_IFNOGIF but it is named
WW_NOBULLETSIFGIF in accordance with original NPAC templates)
-->
<WW_NOBULLETSIFGIF FOILID="${FID}">
<WW_FOILTEXT FOILID="${FID}"/>
</WW_NOBULLETSIFGIF>
<a name="image">
<!-- WW_SELECTDISPLAYMODE inserts into variable with name given by NAME
attribute the preferred display mode of the foil.
With the following WW_IF, it acts in the same way as the original
NPAC {select=123} tag.
-->
<WW_SELECTDISPMODE FOILID="${FID}" NAME="QUERY"/>
<WW_IF CONDITION="%OR(%EQU(${QUERY},1),%EQU(${QUERY},2),%EQU(${QUERY},3))">
<WW_THEN>
<!-- WW_FOILIMAGE inserts image for foil given by FOILID
attribute. The presentation id: PARENTID will be later
used to determine formatting properties (properties,
different than the default, can
be defined on user, presentation, or foil level).
-->
<WW_FOILIMAGE FOILID="${FID}" PARENTID="${PID}"/>
</WW_THEN>
</WW_IF>
<hr>
<WW_NEXT FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsepimage.tdl" IMAGENAME="ww_next"/>
<WW_PREV FOILID="${FID}" PARENTID="${PID}" FILENAME="tempfoilsepimage.tdl" IMAGENAME="ww_prev"/>
<WW_LINK FILENAME="tempfullindex.tdl" ATTR="PID=${PID}">
<WW_IMAGE IMAGENAME="ww_up" FOILID="${FID}" PARENTID="${PID}"/>
</WW_LINK>
<!-- The following pair of tags inserts the signature of the current
foil/presentation.
First WW_DBSET takes the signature value form a database property
in context of the current user, presentation and foil.
PROPTYPE attribute specifies the type of the property
('overall' in case of signature), PROPNAME supplies the
database property name. The value of the property assigned to a variable
given by NAME attribute - here: SIG.
WW_INSERT inserts the value of the signature into the output text.
-->
<WW_DBSET NAME="SIG" PROPNAME="signature" PROPTYPE="OVERALL" FOILID="${FID}" PARENTID="${PID}"/>
<WW_INSERT NAME="${SIG}"/>
</WW_DOCUMENT>
<?WWTEMPLATE>
<?XML VERSION="1.0" CACHE="NO"?>
<WW_DOCUMENT>
<!-- ?WWTEMPLATE and ?XML tags form the header for all template files.
CACHE attribute of the XML tag specifies whether the servlet should
cache the file or not.
-->
<!-- WW_CONNECT is a tag that establishes a connection to a database.
Connection string may be supplied in the CONNECTION attribute,
or if omitted (empty string) the default
connection string is taken from properties.txt file, which specific for
the template.
-->
<WW_CONNECT CONNECTION=""/>
<html>
<head>
<!-- WW_TITLEFOILWORLD is a tag that inserts the foilworld title into output text.
The foilworld is identified by the FWID attribute. The current value
of this attribute is taken here from the FWID variable.
This variable was set automatically by a servlet on the base of the URL
query parameter.
NOTE:
Every parameter passed within an URL is put into a variable of the same
name before a file is parsed. For instance, before parsing a file
referenced by an URL:
'file.tdl?A=1&B=3&C=one'
the following variables will be set:
A with value 1,
B with value 3, and
C with value 'one'.
All these variables are accessible within the file using ${variable_name} syntax.
-->
<title> Foilworld contents for <WW_TITLEFOILWORLD FWID="${FWID}"/> </title>
</head>
<!-- WW_BODYINDEX inserts a 'body' HTML tag with background image typical
for index files.
This tag should be reimplemented to take images from the database
-->
<WW_BODYINDEX/>
<h2><tt>Title for</tt> <WW_TITLEFOILWORLD FWID="${FWID}"/> </h2>
<hr>
<b><tt>Foilworlds in this foilworld </tt><b><p>
<!-- WW_FOILWORLDLOOP is a loop tag that for given foilworld ID (passed as FWID
attribute), parses its contents, setting for each loop pass a variable given by
NAME attribute.
This variable contains an identifier of a 'child' foilworld.
The loop is repeated as many times as many child foilworlds the
current foilworld contains.
With following WW_FOILWORLDLINK, which creates a HREF link to same
file but with child foilworld_id, it allows to create an 'index' of all
foilworlds contained by the current foilworld.
In this case the HREF link will have the form:
HREF="tempfoilworld.tdl?FWID=child_id_from_LOCALFWID_var&_
other_attributes_given_in_ATTR"
The target file can be changed using FILENAME attribute and additional
attributes may be suplied in the ATTR attribute
-->
<WW_FOILWORLDLOOP FWID="${FWID}" NAME="LOCALFWID">
<WW_FOILWORLDLINK FWID="${LOCALFWID}" FILENAME="tempfoilworld.tdl" ATTR=""/>
</WW_FOILWORLDLOOP>
<hr>
<b><tt>Presentations in this foilworld </tt><b><p>
<!-- The same as WW_FOILWORLDLOOP and WW_FOILWORLDLINK pair, but creates
a list of links to presentations instead of child foilworlds,
contained by a current foilworld.
Note that the filename in the FILENAME attribute was changed and points
to a full index file for presentation
-->
<WW_PRESENTATIONLOOP FWID="${FWID}" NAME="LOCALPID">
<WW_PRESENTATIONLINK PRESENTATIONID="${LOCALPID}" FILENAME="tempfullindex.tdl"
ATTR=""/>
</WW_PRESENTATIONLOOP>
</WW_DOCUMENT>
<?WWTEMPLATE>
<?XML VERSION="1.0" CACHE="YES"?>
<WW_DOCUMENT>
<!-- ?WWTEMPLATE and ?XML tags form header for all template files.
CACHE attribute of the XML tag specifies whether the servlet should
cache the template file or not.
-->
<WW_CONNECT CONNECTION=""/>
<html>
<head>
<title> Full Index for LOCAL <WW_TITLE FOILID="${PID}"/> </title>
</head>
<!-- WW_BODYINDEX inserts a 'body' HTML tag with background image typical for index
files. This tag should be re-implemented to take images from the database.
-->
<WW_BODYINDEX/>
<b>
<!-- WW_LINK inserts HREF link pointing to file given by FILENAME with
optional attributes specified in the ATTR attribute.
-->
<WW_LINK FILENAME="tempbasicsearch.tdl" ATTR="">Basic Foilset Search
<!-- WW_IMAGE inserts an IMG SRC html tag where SRC is pointing to a program
(servlet) that allows retrieval of images from the database.
All parts of the URL are filled in using database properties
for a given user in context of current presentation and foil
(given by FOILID and PARENTID attributes).
Because this file is a presentation index,
there is no foil context so the same ID is supplied for both.
Name of the image property is given by the IMAGENAME attribute.
It is a 'search name' for the database image property(not a gif/jpeg file name).
The same property can have different values in different
user/presentation/foil contexts.
-->
<WW_IMAGE IMAGENAME="ww_search" FOILID="${PID}" PARENTID="${PID}"/>
</WW_LINK>
<WW_LINK FILENAME="temphelp.tdl" ATTR="">Help!</WW_LINK>
* GREY=local</b><tt> Full Index for </tt><h2> LOCAL foilset <WW_TITLE FOILID="${PID}"/> </h2>
<b>Given by
<!-- Following tags get information from the database for the specified
presentation.
(WW_AUTHORNAME) - name of the author,
(WW_EVENT) - the event,
(WW_EVENTDATE) - date of the event,
and (WW_MODIFICATIONDATE) - presentation modification date
-->
<WW_AUTHORNAME FOILID="${PID}"/> at
<WW_EVENT FOILID="${PID}"/> on
<WW_EVENTDATE FOILID="${PID}"/>. </b><tt> Foils prepared
<WW_MODIFICATIONDATE FOILID="${PID}"/> </tt>
<br>
<WW_LINK FILENAME="temptitleabs.tdl" ATTR="PID=${PID}">More Detail!</WW_LINK> *
<a href="#toc">Foil Index from this file</a> *
<!-- WW_SELECTSOUND checks for the existence of the sound in the
foil. If a sound object is associated with the specified foil, the ID of
the eduobject containing sound is assigned to a variable given by
NAME attribute.
The same accomplished by WW_SELECTADDON tag for presentation/foil add-ons
-->
<WW_SELECTSOUND FOILID="${PID}" NAME="ISSOUND">
<WW_INSERT NAME="${ISSOUND}"/>
</WW_SELECTSOUND>
<WW_SELECTADDON FOILID="${PID}" NAME="ISADDON">
<INSERT NAME="${ISADDON}"/>
</WW_SELECTADDON>
<!-- WW_ABSMISSING inserts a link to the image of the presentation
abstract (more precisely to the temptitleabs.tdl file which is an image
version of the abstract foil).
The PRESENTATIONID attribute specifies the presentation.
-->
<WW_ABSMISSING PRESENTATIONID="${PID}"/>
<p>
<a name="localabstract"> </a>
<!-- WW_ABSTRACT TEXT inserts table with a bulleted text of the abstract
foil for the presentation specified in the PRESENTATIONID attribute.
-->
<WW_ABSTRACTTEXT PRESENTATIONID="${PID}"/>
<p>
<hr>
<h2><a name="toc">Table of Contents for <WW_TITLE FOILID="${PID}"/> </a> </h2>
<b>A</b> denotes presence of Additional linked information
<br><WW_IMAGE IMAGENAME="ww_audio" FOILID="${PID}" PARENTID="${PID}"/> Indicates Available audio which is grayed out if missing
<hr>
<!-- Following tags create a index (list) of foils in current presentation.
First WW_SET sets the COUNTER variable which allows to insert foil numbers
(this is different from the position of the foil in the presentation
because of the nested presentations) then WW_FOILLOOP iterates for all
foils in the current presentation each time assigning current child foild
ID to LOCALFID variable (given by NAME attribute)
-->
<WW_SET NAME="COUNTER" VALUE="1"/>
<WW_FOILLOOP PARENTID="${PID}" NAME="LOCALFID">
<!-- WW_ANNOTATION inserts the annotation text for the current position
within presentation given by PRESENTATIONID attribute. The position is
taken from the COUNTER variable
(See comment for WW_SET tag above)
-->
<WW_ANNOTATION PRESENTATIONID="${PID}" POSITION="${COUNTER}"/>
<!-- WW_INSERT tag inserts current value of COUNTER variable into the
output text. This is used both for 'A' html tag to identify
anchor and to insert current number into the displayed text -->
<b> <a name="local<WW_INSERT NAME="${COUNTER}"/>">
<WW_INSERT NAME="${COUNTER}"/></a> </b>
<!-- These two WW_LINK tags insert links to template files with foil
image and foil text respectively. The foil and presentation IDs
are suplied in the ATTR attribute.
NOTE:
Because of XML grammar the "&" sign cannot be use in tag attributes.
Instead, the "|" sign is used. The WW_LINK tag implementation
replaces the "|" signs with "&" in output text.
-->
<WW_LINK FILENAME="tempfoilsepimage.tdl" ATTR="FID=${LOCALFID}|PID=${PID}">
Separate IMAGE </WW_LINK>
* <WW_LINK FILENAME="tempfoilsephtml.tdl" ATTR="FID=${LOCALFID}|PID=${PID}">
Separate HTML </WW_LINK>
<WW_TITLE FOILID="${LOCALFID}"/> <br>
<!-- This WW_SET increments variable COUNTER (same as Java 'counter++') -->
<WW_SET NAME="COUNTER" VALUE="%ADD(${COUNTER},1)"/>
</WW_FOILLOOP>
<hr>
<WW_LINK FILENAME="tempfullsearch.tdl" ATTR="">Full WebWisdom URL and this Foilset Search<WW_IMAGE IMAGENAME="ww_search" FOILID="${PID}" PARENTID="${PID}"/></WW_LINK>
<a name="alias">
<br><b><WW_LINK FILENAME="tempaliaslist" ATTR="">Alias List</WW_LINK>
This contains all WebWisdom links preceded by those referenced in this foilset</b>
<hr><h2> List of WebWisdom URL's Used in this Foilset </h2></a>
<WW_DBSET NAME="SIG" PROPNAME="signature" PROPTYPE="OVERALL" FOILID="${PID}" PARENTID="${PID}"/>
<WW_INSERT NAME="${SIG}"/>
</WW_DOCUMENT>