You are a Programmer who has been given a Data Interface Definition file like the one shown here and a pointer to this documentation, and have been asked to code a servlet to this interface definition. This section of the WebStringTemplates documentation is for you.
If you already have existing servlets/JSP pages to convert to WebStringTemplates then you should review this introduction material first before looking at the later sections of this documentation that will cover that case (under construction).
This documentation assumes you are a knowable Java servlet/JSP programmer. It is not a tutorial on Java or servlet/JSP programming. The examples presented here are run on Tomcat V5.0 servlet server using MySQL as the database. The setup of these two packages will be covered on the next page.
To install WebStringTemplates on an existing servlet server see Installing RunWST in the Servlet Server
This documentation for the Programmer will cover:-
From the Programmer's point of view, a webstringtemplate is essentially a java.util.Map into which he inserts the data objects to be displayed on the web page. When the template accesses these objects, it eventually calls toString() to convert them to a string before passing them to the output. As the Programmer, it is your responsibility to ensure the correct data is placed under the key defined by the Data Interface Definition and that the toString() method of each data object returns the required string for the web page to display.
A java.util.Map can hold any type of Object. In particular a
webstringtemplate can handle Object, boolean, byte, char, short,
int, float, double, Enumeration, Iterator, Collection, Maps and objects
that implement get*() and is*() methods (full bean compliance is not
required). When a template access the data, all these objects are mapped to
one of three types:-
a String element (as returned by Object.toString())
a List, if the object is an array or Enumeration, Iterator or Collection (whose order is defined by its Iterator)
a Map, if the object is an instanceof java.util.Map or is an object that implements get*() or is*() methods.
A dot ('.') separated path is used by the template to access these objects. After breaking the data path into tokens, the template engine, recursively calls get(name) on the object returned from the previous call, until the data path is exhausted. For example, book.title would first call get("book") on the main webstringtemplate map and then call get("title") on the object returned and toString() is called on this return to give the result to be filtered (see Data Filters below) and passed to the template output.
Still using the example of book.title, if the call to get("book") returned an object that was not an instanceof a java.util.Map, then the template engine uses introspection to look for a getTitle() method to call. If a getTitle() method cannot be found then isTitle() is checked. If neither can be found, null is returned (by default). As mentioned above this process is applied recursively until the data path is exhausted.
WebStringTemplates has no concept of indexing. If get("books") returns an array of book objects, you cannot request the data item, books.3.title directly. To access the elements of a list or array in the template the Web Page Designer has to use the : syntax to pass the elements, one at a time, to a sub-template for processing. See List Processing in the Web Page Designers tutorial for a detailed example. WebStringTemplates automatically converts all arrays, Enumerations, Iterators and Collections to an ArrayList before returning them.
Of course as the Programmer, you can always use the java.util.Map interface to get the ArrayList and then access its individual elements. However the Web Page Designer cannot. This means you should include all data associated with a list element in that element. You should not have two lists, such as a list of names and a separate list of ages, as WebStringTemplates has no way of processing these two lists at the same time.
Beans and java.util.Map objects can have an overall descriptive string
specified for them. This overall string is the string returned when template
requests the string output for just the bean or the map object. For example
is the template requested the book object to insert in its
output. If get("book") returns a java.util.Map then the overall string is the
string representation of the object stored under the
String("") key. If this key does not exist or if get("book") returns
any object other than java.util.Map, then the get("book").toString() is
returned as the overall string.
If the Data Interface Definition file specifies an overall string for an
object, as it does for book object in this example, then the
output data you generate must supply a suitable string return for this
object. If the object is a java.util.Map, you must store a suitable string
new String("") key in the map. If the object is not a
java.util.Map, then you must define the
toString() method to
return the appropiate string in order to comply with the interface
Every object returned to the template engine is wrapped in a IWSTFilter. If you did not wrap the object in a filter when you added it to the template map, the WebStringTemplateGroup defaultFilter is applied. The default filter is WSTXmlFilter but you can set your own default filter using WebStringTemplateGroup.setDefaultFilter(IWSTFilter filter). WSTXmlFilter replaces < > & and " with the corresponding HTML escape codes.
In those cases where you have already formatted the output, you can prevent this default filter being applied by wrapping the object in a WSTPlainFilter. The WSTPlainFilter just returns the object.toString() unchanged. You can define you own filters, look at the code for WSTXmlFilter to see an example of what is required.
If you want to wrap an object in a filter there are two ways of doing it:-
i) wrap the object before putting it in the template using code like
ii) add a filter extension to the map's key when you call webstringtemplate put(key,obj) or setAttribute(key,obj) or addAttribute(key,obj). For example
put("Talk.plain", "This is the <b>best</b>
Two of these filter extensions are defined by default.
.xml applies a WSTXmlFilter to the object being added and
.plain applies a WSTPlainFilter. In both cases the extension
is stripped from the key before using the key to add the object to the map.
This means in the example above
put("Talk.plain", "This is the <b>best</b> book");the key used in the map is the string "Talk". The
.plain extension is stripped after the filter is applied to
the input object.
You can use setFilter(nameExtension, filter) in the WebStringTemplateGroup to add and remove your own filter extensions.
Data filters are singular and inherited. Any object has at most one data filter. You cannot chain data filters by wrapping a filter in a filter. The inter-most filter is the only that will be applied. Data filters are inherited by all the children of an object, unless the child is wrapped in its own filter. So for example if you apply a WSTPlainFilter to a Java Bean object then that same filter will be applied to all the bean's get*() and is*() method results and to their children. If you apply a filter to a Map object, then that filter will be applied to all the map's contents at every level. As mentioned above, the only exception to this is if a child object is already wrapped in a filter. In that case object filter takes precedence over the inherited filter. That is the inter-most filter is applied. Also any children of this child inherit the child's filter rather then some higher up filter.
In summary, most of the time you don't have to worry about filters as the default WSTXmlFilter is what you want. Occasionally you will want to protect a pre-formatted result from being escaped. In that case you will wrap the object in a WSTPlainFilter using either of the two ways discussed above.
When building up the data map hierarchy to match the Data Interface Definition, you may find it convenient to use WebStringTemplates addAttribute(key,obj) for making lists and filter extensions for applying filter. To build one level at a time you can use
WebStringTemplate wst = new WebStringTemplate(myGroup);
to create an empty template and data map that you can add to. Then when you have finished adding attributes to this level of the hierarchy you can use
map = wst.getAttributes();
to retrieve that map and add it to the next level up in the correct path position.
As well as being used to define the interface between the Programmer and the Web Page Designer, the Data Interface Definition file can also be used to load default data into the template map. The Data Interface Definition file is encoded in the same way as the Java property files. That is it uses ISO-8859-1 character encoding and escaped Unicodes (\udddd). Any HTML tag, except list tags, can be used in the data so that blocks of pre-formatted output can be loaded from the file into the correct place in the hierarchy. If you need data containing HTML lists, there is an escape mechanism available to handle this. Different versions of the data file can be loaded to support different languages.
The advantage of using a Data Interface Definition file over a Java property file is that the Data Interface Definition file maintains the correct hierarchy of the data when it is loaded. Also all data loaded from the data file is automatically wrapped in a WSTPlainFilter to ensure it is supplied to the template exactly as it is loaded.
The javadocs for WebStringTemplates are available here.
The next page will cover setting up the Tomcat Servlet Server and the MySQL database.