FormattedDataSet API (fdsapi) TABLE OF CONTENTS

1.     FormattedDataSet Introduction................................................................................. 3

1.1       What is the FormattedDataSet?............................................................................. 3

1.2       An Example:  Using the FormattedDataSet............................................................. 3

1.3       How does the FormattedDataSet  work?............................................................... 4

1.3.1        The TabularData Interface – The Iterator Design Pattern................................ 4

1.3.2        The DataSet Interface – The Command Design Pattern.................................. 5

1.3.3        FormattedDataSet Templates – Putting it all Together..................................... 5

2.     What are Some Advantages of the FormattedDataSet?.......................................... 6

2.1       Separation of Data and Presentation Formatting – Reuse........................................ 6

2.2       Open, Extensible API – Developers can Easily Add Functionality........................... 9

2.3       More than Text Generation – Execute ANY Logic Against TabularData................. 9

2.4       Template Inheritance – Promotes Reuse............................................................... 10

2.5       Subqueries – Implementing Master/Detail Reports................................................ 10

2.6       Dynamic Templates – Changing Formatting Based on Run-Time Data................... 11

2.7       Other Utilities – For Example: Simplified JDBC.................................................... 11

2.8       Monitored with JAMon – Tracking Application Performance................................ 12

2.9       Only 1,000 lines of code -  Easily Add New Features.......................................... 12

3.     FormattedDataSet Tutorial...................................................................................... 13

3.1       Where we are headed?........................................................................................ 13

3.2       Template Tag Coordinates – Example (0,1) – Column 1....................................... 13

3.3       Template Tags – Mapping DataSets to TabularData............................................. 15

3.4       Calling the getFormattedDataSet(…) method – Formatting Data........................... 17

4.     Misc. Info.................................................................................................................. 19

4.1       Reading Templates from Files and Template Inheritance....................................... 19

4.2       Template Tag Variables....................................................................................... 20

4.3       Default Templates................................................................................................ 20

4.4       FormattedDataSet Utilities – DataAccess, ResultSetConverter and ArrayComparator            22

4.5       Hiding the FormattedDataSet – An Implementation Detail..................................... 23

4.6       Using the FormattedDataSet to display Java Objects............................................ 24

4.7       Installing the FormattedDataSet............................................................................ 27

4.8       Running the Demo Application............................................................................. 27

5.     Template Terms........................................................................................................ 29

5.1       Template Tag...................................................................................................... 29

5.2       Template Start and End Tags............................................................................... 29

5.3       Template Tag Coordinate.................................................................................... 29

5.4       Template Tag Value............................................................................................. 30

5.5       Template Tag Variables....................................................................................... 30

6.     Template Rules......................................................................................................... 31

6.1       Template Tag Rules............................................................................................. 31

6.2       Template Tag Variable Name Rules..................................................................... 31

6.3       Template Tag Variable Value Rules...................................................................... 32

7.     Template Hierarchy.................................................................................................. 35

8.     Predefined Template Tag Variables........................................................................ 37

8.1       DataSource......................................................................................................... 37

8.2       IncrementData..................................................................................................... 37

8.3       Query.................................................................................................................. 37

8.4       Selected.............................................................................................................. 37

8.5       Size..................................................................................................................... 38

8.6       Template............................................................................................................. 38

8.7       Type................................................................................................................... 38

8.8       Odd, Even – See Alternating DataSet below........................................................ 38

8.9       If, IfValue, ElseValue – See Conditional DataSet below....................................... 38

9.     Predefined Template Tag Types (i.e. DataSet Types)........................................... 39

9.1       Alternating........................................................................................................... 39

9.2       Conditional.......................................................................................................... 39

9.3       Constant.............................................................................................................. 40

9.4       DropDownListBox.............................................................................................. 40

9.5       Empty................................................................................................................. 41

9.6       ListBox............................................................................................................... 41

9.7       Query.................................................................................................................. 41

9.8       RadioButton........................................................................................................ 42

9.9       Reserved DataSet Types Names.......................................................................... 42

10.       Sample Master Template..................................................................................... 43

11.       Misc. Template Samples...................................................................................... 45

12.       Acknowledgements............................................................................................... 47


 

 

1.     FormattedDataSet Introduction

1.1     What is the FormattedDataSet?

The FormattedDataSet API is an easy to use, powerful way to generate dynamic text such as HTML, XML, WML, JavaScript, and more. 

 

FormattedDataSet creates dynamic text by combining separate data and formatting.  Data can be any form of TabularData (ResultSets,  2 dimensional arrays, or user defined…).  Formatting is stored in FormattedDataSet templates.  FormattedDataSet templates are simply Java Strings, typically stored as files.  Developers and GUI designers can create their own templates and in this way have total control over presentation formatting.

 

The FormattedDataSet is easy to use.  No installation is required; a developer only has to place a few small jars in the class path and within a few minutes they can start creating dynamic text!  Also, the learning curve for creating FormattedDataSet templates is not steep, unlike competing products that involve knowing any number of the following technologies:  JDBC, tag libraries, proprietary GUI tools, and complex proprietary runtime Object creation code.

 

There is a lot more to the FormattedDataSet API, so keep reading!

 

1.2     An Example:  Using the FormattedDataSet

The FormattedDataSet can easily create dynamic HTML such as tables, list boxes, drop down list boxes, multi select listboxes, and radio buttons.   Out of the box the following few JSP lines of code will display ANY SQL query as an HTML table.

  <%

   FormattedDataSet fds=FormattedDataSet.createInstance();

   String htmlTable=fds.getFormattedDataSet(“select * from musicians where group=’Rolling Stones’”,

“htmlTable”);

   %>

   <%=htmlTable %>

 

The resulting HTML table follows:

 


 


In this case the “getFormattedDataSet()” method takes 2 arguments, a query (the data to be presented), and a FormattedDataSet Template name (the presentation formatting).  One of the key benefits of using the FormattedDataSet is the clean separation of data, and formatting.  This allows both data and formatting to be reused independently.  For example the “htmlTable” template can format ANY SQL QUERY as an HTML table.  The FormattedDataSet’s simple syntax allows anyone that knows SQL to easily create dynamic content. 

 

Note: There are alternative “getFormattedDataSet()” method signatures that can take other forms of tabular data (for example 2 dimensional arrays).  Developers can also register their own types of tabular data.

1.3     How does the FormattedDataSet  work? 

The FormattedDataSet is an implementation of the Gang Of 4’s Command and Iterator design patterns, with the DataSet executing commands against TabularData as this data is iterated through.

 

1.3.1     The TabularData Interface – The Iterator Design Pattern

Throughout this document the term TabularData refers to the FormattedDataSet APIs TabularData interface.  Tabular data is any grid of data that has rows, and columns.  “Cells” of data occur and row, column intersections (i.e. cell 1,1).  The classic example of tabular data is a spreadsheet.  ResultSets, arrays, ResultSetMetaData and even XML can be considered tabular data. 

 

The TabularData interface abstracts the concept of tabular data.  Out of the box the TabularData interface is implemented for ResultSets, 1 dimensional arrays, 2 dimensional arrays, and ResultSetMetaData.  The TabularData interface enables the FormattedDataSet to render ALL types of tabular data using the same FormattedDataSet templates.   Developers can implement the TabularData interface, and so extend the FormattedDataSet to render any future tabular data types as well.

 

1.3.2     The DataSet Interface – The Command Design Pattern

The DataSet interface has an execute() method that is called while tabular data is iterated through.  Without DataSet’s you could iterate through TabularData, but no action would be performed (i.e. The DataSet’s callback method (execute()) performs actions on the TabularData).

 

Out of the box there are a number of DataSet’s provided that perform actions such as rendering tabular cell data.   Developers can also implement the DataSet interface, and so extend the FormattedDataSet to perform actions that weren’t envisioned when the FormattedDataSet was designed.  Although all out of the box DataSet’s only support rendering textual data, there is no reason other actions such as email, or paging couldn’t be programmed into a DataSet.

1.3.3     FormattedDataSet Templates – Putting it all Together

 

FormattedDataSet templates map actions (i.e. DataSet’s) to tabular data.  Templates are simply Java Strings, but for convenience the FormattedDataSet API can read templates from text files.  Templates are an implementation of the Gang of 4’s Builder design pattern.  They specify which DataSet’s will be created at runtime and map the DataSet’s callback method (execute()) to various TabularData points of interest. For example the DataSet’s execute() method could be called for all rows in a specified column).

 

2.     What are Some Advantages of the FormattedDataSet?

The FormattedDataSet is easy to use, powerful and promotes reusable, maintainable code.  The sections below further discuss advantages of the FormattedDataSet.

2.1     Separation of Data and Presentation Formatting – Reuse

 

The FormattedDataSet cleanly separates data from presentation formatting.   In JSPs, often developers use tag libraries to display data.   To do this you must put both the data and HTML formatting in a JSP.  

 

In the JSP/Tag solution, the formatting cannot be reused independently from the data.  If a similar report is created in another JSP the HTML tags must be repeated.  In addition the data can’t be reused either as the iteration logic is embedded within the tags of each JSP.  The FormattedDataSet can reuse both the data, and the formatting in any number of JSPs/Servlets or even straight Java code.  For example one HTML table template could be created for the whole enterprise and if this template were changed, all pages using it would automatically be updated to the new look and feel.

 

In a recently developed application, the backend developer was often able to return new columns to the front end and because the GUI and Java developers used the FormattedDataSet often they did not have to change their code.   In other cases, the GUI developer was able to make GUI changes without the backend and Java developers needing to make changes to their work.  This capability allows GUI, backend, and Java developers to work independently.

 

The following graphic demonstrates how the same template may be used to format ANY type of TabularData (in this case two stored procs returning ResultSets, and a SQL select statement).  (Note the “tabs” are not rendered by the call to getFormattedDataSet(…), just the “htmlTable”).


The following example demonstrates how varying the template (i.e. the formatting) allows you to vary the presentation while keeping the data constant.  The example below shows the “emails” table being formatted as an “htmlTable”, “formLetter” and “xml” respectively.


2.2     Open, Extensible API – Developers can Easily Add Functionality

The FormattedDataSet API is extensible.  For example by implementing the DataSet interface, any developer can have their code called back during tabular data iteration, at various points of interest.  The FormattedDataSet doesn’t care know or care what logic it executes and so it is very open ended in what it can do.   DataSet.execute()” is simply called at the appropriate time.  By implementing the DataSet interface and properly registering it using the FormattedDataSet API, developers write code that can be reused in other templates.

 

By implementing the DataSet interface I added master/detail query abilities in about 10 lines of code.  Any other developer could have just as easily added this capability.   Developers should be able to come up with many useful DataSet types that original FormattedDataSet developers can’t envision.

 

There are also a number of other interfaces that a developer can implement and register with the FormattedDataSet that will allow them to further increase functionality.  For example, if the developer implements the TabularData interface and registers their code into the appropriate factory, then the FormattedDataSet will automatically work with this new TabularData type. 

 

2.3     More than Text Generation – Execute ANY Logic Against TabularData

Although one use of the FormattedDataSet API is to generate text, it is a more general tool than that.  The FormattedDataSet API can more generally execute ANY logic against ANY tabular data (Arrays, ResultSets, …).  Developers can extend the FormattedDataSet by registering there own call back code which will be called at various points of interest as the TabularData is being processed, such as before and after each row, and before every cell, at every cell and after every cell.  For example a DataSet could be created that sends emails out based on the value of a cell in a column.

 

When this document refers to the FormattedDataSet it is referring to a class in the FormattedDataSet API that uses TabularData and DataSet’s (created from templates) to generate any kind of text such as XML, HTML, WML, JavaScript, SQL,…

 

The FormattedDataSet class is really an implementation of the Gang Of 4’s Iterator and Command design patterns (Iterating through the TabularData executing commands that generate dynamic text).  

 

2.4     Template Inheritance – Promotes Reuse

The concept of template inheritance allows developers to leverage existing templates that are similar to one they would like to create.  For example, let’s say that a developer wants to display an HTML table, but would like to make the first column clickable (i.e. an href).  They can simply reuse the table template via inheritance and change this one difference/exception (i.e. make the first column clickable).   Inheritance encourages creating many small templates that can be dynamically plugged together. 

 

In the example below the first table uses the default “htmlTable” template, and the second table inherits from the default and makes column 3 clickable.

 

2.5     Subqueries – Implementing Master/Detail Reports

Using templates, Master/Detail reports can easily be created with any level of nesting.   I added this capability using FormattedDataSet’s open API with 10 lines of code.  Any developer could have added this capability due to the open-ness of the API.

 

In the example below the subquery is circled in blue.  The relationship between “Schedule No.”, and “SINs” below is a Master/Detail relationship.  The entire report below took two lines of Java code using the FormattedDataSet.

 

2.6     Dynamic Templates – Changing Formatting Based on Run-Time Data

Because templates are just strings they may be created at runtime based on dynamic data.  In fact the FormattedDataSet itself can be used to generate templates on the fly! 

 

Also because the template names are simply Strings, different presentation styles can be determined based on runtime data.  The example below either creates HTML, or XML based on a form request parameter.  A similar approach could be used to enable internationalization. 

FormattedDataSet fds=FormattedDataSet.createInstance();

if (request.getParameter(“xml”)==null)

                displayStr=fds.getFormattedDataSet(“select * from table”, “htmlTable”);

else

                displayStr=fds.getFormattedDataSet(“select * from table”, “myXML”);

 

2.7     Other Utilities – For Example: Simplified JDBC

Many utilities exist in the jar that will be of general interest to developers regardless of whether or not they use the FormattedDataSet class.  For example the following line of code retrieves a ResultSet (including opening, and closing JDBC Connection and Statement objects),  and converts the ResultSetMetaData and ResultSet into arrays (String[] and Object[][] arrays respectively).  The ResultSetConverter object below is a wrapper for these String[] and Object[][] arrays.  Note that many of the FormattedDataSet methods are overloaded to take ResultSetConverter objects as well as String[], and Object[][] arrays.

FormattedDataSet fds=FormattedDataSet.createInstance();

ResultSetConverter rsc=fds.getResultSetConverter(“select * from table”);

// Format the ResultSetConverter as an HTMLTable.

String html=fds.getFormattedDataSet(rsc, “htmlTable”);

2.8     Monitored with JAMon – Tracking Application Performance

Open Source JAMon is used to monitor FormattedDataSet performance.   One benefit of JAMon being required as part of the FormattedDataSet API is that the JAMon API will be available for developers to use in monitoring performance in other parts of their applications. 

The FormattedDataSet API uses JAMon to measure how long various JDBC actions take like opening/closing connections, executing ResultSets, and also to determine how long calls to getFormattedDataSet() take.  JAMon also tracks application scalability (correlation of performance to load).

JAMon is a simple, but powerful tool in its own right.  For more informatin about JAMon please see http://www.jamonapi.com.

 

 

2.9     Only 1,000 lines of code -  Easily Add New Features

Despite FormattedDataSets power it is only about 1,000 lines of code in 70 classes.  This makes it relatively easy to add new features.  It doesn’t use any advanced Java language features, so it could easily be ported to other languages.  For example it could be ported to C## and any template the user creates could be used in both J2EE and .Net.

Also the FormattedDataSet uses quite a few of the Gang of 4’s design patterns and serves as an excellent primer in design patterns. 

 

3.     FormattedDataSet Tutorial

 

3.1     Where we are headed?

In the next few sections we will discuss the basic concepts involved in using the FormattedDataSet API.   We will generate a template that will allow us to create an HTML table from any form of tabular data.

 

The code used to generate the HTML Table follows:

FormattedDataSet fds=FormattedDataSet.createInstance();

String html = fds.getFormattedDataSet(“select * from beatles”, “myHTMLTable”);

 

The resulting HTML follows.  In the source view the black text is dynamic and the green text is static and comes from our FormattedDataSet template. 

 

3.2     Template Tag Coordinates – Example (0,1) – Column 1

FormattedDataSet templates are simply Strings that specify which DataSet’s will be created at runtime and map the DataSets to various TabularData points of interest such as a column (i.e. The DataSet’s execute() method will be called for all rows in a specified column).

 

The TabularData interface abstracts rows and columns to start at 1 (even 2 dimensional arrays which usually are 0 indexed will start at 1).  TabularData consists of both a header and a body (Corresponding roughly to ResultSetMetaData and ResultSet respectively).  Any TabularData header or body cell can be identified by its coordinate.  Using the “Beatles” data below: 

·        “Fname” is in coordinate (1,1) of the header (i.e. row 1, column 1)

·        “John” is in coordinate (1,1) of the body

·        “McCartney” is in coordinate (2,1) of the body. 

 

As we will see shortly these “Template Tag Coordinates” are used in FormattedDataSet templates. 

 

 

 

 

 

 

 

 

 

 

 

 

 


A Template Tag Coordinate that contains a 0 has special meaning. 

·        Template tag coordinate 0,1 represents all rows in column 1.  In the “beatles” data for the body this would include cells (1,1), (2,1), (3,1) and (4,1) (i.e. column 1).

·        Template tag coordinate 1,0 means all columns in row 1.  In the “beatles” data for the body this would include cells (1,1) and (1,2) (i.e. row 1)

·        Template tag coordinate 0,0 means all cells in the tabular data.  In the “beatles” data for the body this would include cells (1,1), (1,2), (2,1), (2,2), (3,1), (3,2), (4,1), (4,2), (1,1).

 

The general concept of the FormattedDataSet is that using templates and specifying “Template Tag Coordinates” a developer can map what DataSet logic will be executed against TabularData at various points of interest such as before, at and after each cell. 

 

3.3     Template Tags – Mapping DataSets to TabularData

FormattedDataSet templates consist of any number of “Template Tags” that map DataSets to TabularData.  DataSet logic can be mapped to twenty-seven TabularData points of interest via templates!   We will cover some of these in the tutorial. 

 

To demonstrate template tags, let’s create a simple template that renders TabularData as an HTML table.

           

import com.fdsapi.*;  // FormattedDataSet API

String templateStr=”<!-- COMPOSITE_PREFIX --><table>\n<!-- COMPOSITE_PREFIX -->”+

“<!-- COMPOSITE_SUFFIX --></table><!-- COMPOSITE_SUFFIX -->”+

“<!-- HEADER_ROW_SUFFIX -->\n<!-- HEADER_ROW_SUFFIX -->”+

“<!-- HEADER_CELL_PREFIX --><th><!-- HEADER_CELL_PREFIX -->”+

“<!-- HEADER_CELL_SUFFIX --></th><!-- HEADER_CELL_SUFFIX -->”+

 

“<!-- BODY_ROW_PREFIX --><tr><!-- BODY_ROW_PREFIX -->”+

“<!-- BODY_ROW_SUFFIX --></tr>\n<!-- BODY_ROW_SUFFIX à”+

“<!-- BODY_CELL_PREFIX --><td><!-- BODY_CELL_PREFIX -->”+

“<!-- BODY_CELL_SUFFIX --></td><!-- BODY_CELL_SUFFIX -->”;//1

 

Template template=new Template(); //2  create Template object

template.initialize(templateStr);  //3  parse template String

FormattedDataSet fds=FormattedDataSet.createInstance();  //4 create FormattedDataSet

String htmlTable=fds.getFormattedDataSet(“select * from beatles”, template); //5 display data

 

Let’s examine the “body_cell_prefix” template tag to get a better understanding of how templates work.  Template tags can optionally specify template tag coordinates.  If template tag coordinates are not specified then the template tag coordinate defaults to 0,0 and so the following are equivalent:

·         <!-- BODY_CELL_PREFIX --><td><!-- BODY_CELL_PREFIX -->

·         <!-- BODY_CELL_PREFIX 0,0 --><td><!-- BODY_CELL_PREFIX 0,0 -->

 

The template parser looks for any text between matching template tag pairs.  This information is used to determine the type of DataSet to create and how it should be configured.    Typically the DataSet type is specified via the following syntax “Type==DataSetType”, however when there is no type specified the default DataSet type of “Constant” is created.   The tutorial will only cover “Constant” DataSets. 

 

The following template tag tells the template parser to create a “Constant” DataSet and to place a “<td>” before every cell (prefix) in the body when rendering the TabularData.   Due to the template tag coordinate being 0,0 this simple declaritive syntax will always put a “<td>” in front of ALL TabularData cells no matter how many rows and columns it has.  Note templates only know about text and not what the text is, so although the example uses the HTML element “<td>”, any other text could also be used.

<!-- BODY_CELL_PREFIX 0,0 --><td><!-- BODY_CELL_PREFIX 0,0 -->

 

Descriptions of the other template tags used in the example follow.  Look at the generated HTML to get a further understanding of what the template tags do:

·         <!-- COMPOSITE_PREFIX --><table>\n<!-- COMPOSITE_PREFIX --> - The Composite prefix comes before the header.  This has the effect of putting “<table>/n” before the header to open the HTML table.  Note white space is honored in template tag values (i.e. “<table>/n” puts a return after “<table>” in the output).

·         <!-- COMPOSITE_SUFFIX --></table><!-- COMPOSITE_SUFFIX --> - Composite suffix comes after the body.  This has the effect of closing the HTML table.

·         <!-- HEADER_ROW_SUFFIX -->\n<!-- HEADER_ROW_SUFFIX --> - This has the effect of  putting a return after the header row.  This makes no difference when the table is viewed in a browser, but makes the HTML more readable when the source is viewed.

·         <!-- HEADER_CELL_PREFIX --><th><!-- HEADER_CELL_PREFIX --> - Put a “<th>” before each cell in the header.

·         <!-- HEADER_CELL_SUFFIX --></th><!-- HEADER_CELL_SUFFIX --> - Put a “</th>” after each cell in the header.

·         <!-- BODY_ROW_PREFIX --><tr><!-- BODY_ROW_PREFIX --> - Put a “<tr>” before each row in the body.

·         <!-- BODY_ROW_SUFFIX --></tr>\n<!-- BODY_ROW_SUFFIX à - Put a “</tr>/n” after each row in the body.  Note the return “/n” will not be seen in the browser, but only when the HTML source is viewed.

·         <!-- BODY_CELL_PREFIX --><td><!-- BODY_CELL_PREFIX --> - Put a “<td>” before each cell in the body.

·        <!-- BODY_CELL_SUFFIX --></td><!-- BODY_CELL_SUFFIX --> - Put a “</td>” after each cell in the body.

 

Note there are default DataSets for all 27 of the TabularData points of interest.  The above were only provided because the defaults were not sufficient in this case.   The default DataSets for all template tags; except “HEADER_CELL_DATA” and “BODY_CELL_DATA”, do nothing (i.e. are they are noops).   The default DataSets for “HEADER_CELL_DATA” and “BODY_CELL_DATA” display their respective cells from the TabularData interface, so we did not have to provide these template tag types in the template above.

 

Templates are not case sensitive (i.e. body_cell_data and BODY_cell_DATA are the same), and all text not between Template Tag Pairs is simply ignored.  See other sections of this document for more information on FormattedDataSet templates.

3.4     Calling the getFormattedDataSet(…) method – Formatting Data

 

Now that we understand the basic template format let’s look at the rest of the code:

Template template=new Template(); //2  create Template object

template.initialize(templateStr);  //3  parse template String

FormattedDataSet fds=FormattedDataSet.createInstance();  //4 create FormattedDataSet

String htmlTable=fds.getFormattedDataSet(“select * from beatles”, template); //5 display data

 

First a Template object is created (comment 2) and then the Template String is passed to it (comment 3).  This “parses” the template.  After this point the Template object uses an internal data structure and never uses the Template String again. 

 

Finally a FormattedDataSet object is created (with createInstance() ),  and the HTML is created with a call to getFormattedDataSet(…).  Note the FormattedDataSet and Template instances can be used any number of times, even against different TabularData. Also Template and the FormattedDataSet objects are Thread safe. 

 

The Template can also be checked back into the FormattedDataSet and so be available outside the scope where it was created:

Template template=new Template(); //2  create Template object

template.initialize(templateStr);  //3  parse template String

FormattedDataSet fds=FormattedDataSet.createInstance();  //4  create FormattedDataSet

fds.putTemplate(“myHTMLTemplate”, template);

String htmlTable=fds.getFormattedDataSet(“select * from beatles”, “myHTMLTemplate”); //5

 

By calling the overloaded getFormattedDataSet(…) method, this code has the same effect as the previous code, however the Template object now is associated with a Template name and can be accessed from any scope until the JVM is shut down.  Typically Template’s are initialized at application start-up and are referenced by template name as in this example. 

 

Note by passing a query to the getFormattedDataSet(…) method, the developer doesn’t have to make JDBC calls.  JDBC Connections, Statements, ResultSets are all handled by the FormattedDataSet.  By default the FormattedDataSet is configured to work in a J2EE app server using “javax.sql.DataSource” objects.  If the DataSource has the name “jdbc/DataSource” (i.e. the default FormattedDataSet DataSource name), then you need not handle JDBC calls.  If you have a different DataSource name or more than one DataSource you may call the overloaded getFormattedDataSet(…) method that takes a DataSource name, and JDBC calls will also be handled automatically.

There are many overloaded method calls for getFormattedDataSet(…), as well as method calls that do things such as display list boxes, drop down listboxes and radio butons.  See the FormattedDataSet javadocs for further explanation of these methods.

 

4.     Misc. Info

This section will give a brief overview of important aspects of the FormattedDataSet API.  More in depth information may be found in the FormattedDataSet javadocs and throughout this document.

 

 

4.1     Reading Templates from Files and Template Inheritance

The tutorial demonstrated how Templates can be parsed from Java Strings.  However, this approach can be tedious when dealing with many Templates.   It is easier to create Templates as text files.  For Web applications this encourages a GUI designer to create a static prototype of the application and later to put tags directly into the HTML to make the files FormattedDataSet Templates. 

 

Sample code that reads FormattedDataSet Templates from files:

FormattedDataSet fds=FormattedDataSet.createInstance();

String[][] templates={{“myTemplate”, “/templates/table_template.html”},

                                {“myTemplate”, “/templates/inherited_table_template.html”},  // inheritance

                                {“myXML”, “/templates/myxml_template.html”},};

fds.initialize(templates);  // read files and parse templates

 

The first column in the templates array has the template name that will be passed to getFormattedDataSet(…) method.  For example:

fds.getFormattedDataSet(“select * from table”, “myTemplate”);

 

The second column in the templates array has the physical location of the template file.  This file will be read, and parsed to become a Template object. 

 

Note the “myTemplate” Template name appears in the array twice.   In this case the first file in the array is parsed, and when the second file with the same Template name is parsed any Template Tags that don’t already exist for “myTemplate” are added to the Template object, and any Template Tags that do exist are overwritten (i.e. If Template Tags are in both Template files the second Template files information replaces the firsts). 

 

This concept is called “Template Inheritance” and allows Templates to be reused and slightly modified quite easily.  Using this approach a developer could create one “htmlTable” template and if they want to create an HTML table that has column 2 as a clickable HTML HREF element they could inherit from “htmlTable” and only provide this new HREF Template Tag in the second Template.

 

4.2     Template Tag Variables

“Template Tag Variables” are portions of the template that can be retrieved via the FormattedDataSet API dynamically from a DataSet.  They have the format “variableName==variableValue”.  The “Type” Template Tag Variable is a special variable that tells the FormattedDataSet parser the type of DataSet to create. 

 

In the example below a DataSet of type “Query” is created.   The Query DataSet will execute a subquery (i.e. Master/Detail query).  The other Template Tag Variables (“Query”, and “Template”) are accessible to the “Query” DataSet at runtime.

<!-- BODY_CELL_DATA --> Type==Query  Query==select * from table where col=’##1’  Template==htmlTable<!-- BODY_CELL_DATA -->

 

“Template Tag Variable Values” are the portion of the variable to the right of “==”.   These values have access to runtime data via “Dynamic Template Tag Variable Value Substitution”.  This means that any part of the Template Tag Variable Value that starts with ‘##’ will be replaced during execution with runtime data. 

 

In the example above “##1” will be replaced at runtime with the TabularData’s cell data from the first column of the current row (In the Beatles example one of the substitutions would be:  “select * from table where col=’Paul’”).  The “Query” DataSet will execute this query, format the results as an HTML table and display the table in the current cell.  However, the more general point is that it is up to the DataSet to determine what action is appropriate.  See a further section for a description of all the possible “##” variables.

 

4.3     Default Templates

Out of the box the FormattedDataSet comes with a number of useful Templates.  They may be used as is, or they can be modified if necessary.   These default Templates are part of the FormattedDataSet code and so no external files are required for them to work.  The default Templates and their uses follow:

·        basicHTMLTable – A generic HTML table. 

o        String html=fds.getFormattedDataSet(“select * from table”, “basicHTMLTable”);

·        HTMLTable – A more attractive HTML table.  To get the improved looks “formatteddatatset.css” or another stylesheet should be included.

o        String html=fds.getFormattedDataSet(“select * from table”, “HTMLTable”);

·        sortedHTMLTable – A template inherited from “HTMLTable” that is used in the get getSortedText(…) methods that sort.  Note the JSP that is put in the Map below will be submitted to (MySortPage.jsp in the example).

o        Map map=new HashMap();

o        map.put("sortPageName", "MySortPage.jsp");

o       String html=fds.getFormattedDataSet(“select * from table”, map,  2, "asc", "sortedHTMLTable");   // sort column 2 in ascending order

·        XML – An XML template that includes all elements except the root element.  The root element start and end tags can just be appended to the output.

o         String xml=“ <myTable>”+fds.getFormattedDataSet(“select * from myTable”, “xml”)+”</myTable>”;

·        XML1 – An XML template that includes all elements including the root element.  The root is passed in via a Java Map using an alternative getFormattedDataSet(…) method.

o        Map miscData=new HashMap();

o        miscData.put(“rootElement”, “myTable”);

o        String xml=fds.getFormattedDataSet(“select * from myTable”, miscData, “xml1”);

·        Blank – Concatenates all cells in the body of the TabularData.  This is convenient for getting a scalar cell value back from the database.   The following returns the server version number when running a Sybase ASE database server.

o       String version=fds.getFormattedDataSet(“select @@version”, “blank”);

·        listBox – An HTML list box.  The first column is the value in the listbox and the second column is the display.   “Lennon” will be highlighted/selected in the example below.  The following method uses the “listBox” template behind the scenes.

o        String html=fds.getListBox(“select lname, lname from beatles”, “Lennon”, 2);

·        dropDownListBox – An HTML drop down list box.  The first column is the value in the listbox and the second column is the display.  “Lennon” will be highlighted/selected in the example below.  The following method uses the “dropDownlistBox” template behind the scenes.

o        String html=fds.getDropDownListBox(“select lname, lname from beatles”, “Lennon”);

·        multiSelectListBox – An HTML multi select list box.  The first column is the value in the listbox and the second column is the display.  In the example below a multi select list box will be displayed with “Lennon” and “Starr” highlighted/selected.  The following method uses the “multiSelectlistBox” template behind the scenes.

o        String[] selectedItems={“Lennon”, “Starr”};

o        String html=fds.getMultiSelectListBox(“select lname, lname from beatles”, selectedItems, 4);

·        radioButton – An HTML multi select list box.  The first column is the value in the listbox and the second column is the display.  “Lennon” will be highlighted/selected in the example below.  The following method uses the “multiSelectlistBox” template behind the scenes.

o        String html=fds.getRadioButton(“select lname, lname from beatles”, “Lennon”);

·        CSV (Comma Separated Values) – Comma separated text that is often used to export data from a database. 

o        String text=fds.getFormattedDataSet(“select * from myTable”, “csv”);

·        delimited – Similar to CSV except you can provide the data delimeter (providing ‘,’ would create CSV text)

o        Map miscData=new HashMap();

o        miscData.put(“delimeter”, “**”);

o        String xml=fds.getFormattedDataSet(“select * from myTable”, miscData, “delimited”);

 

 

See the FormattedDataSet javadocs for more examples.  Although all the examples above take queries, the FormattedDataSet methods are overloaded to take other forms of TabularData.    Also note that template names are case-insensitive, so “HTMLTABLE”, “htmltable”, “HtmlTable” all work equally well.  The contents of all the Templates mentioned above can be found by looking at the defaultTemplates.txt file or in the Templates class. 

 

4.4     FormattedDataSet Utilities – DataAccess, ResultSetConverter and ArrayComparator

The FormattedDataSet API also comes with a number of other useful utilities.  A couple will be covered here.  Refer to the FormattedDataSet API javadocs for more information on the various utilities.

 

The FormattedDataSet comes with DataAccess classes that wrap various JDBC methods that get Statements, Connections, ResultSets and more.   All of these classes are monitored with JAMon (http://www.jamonapi.com). 

 

In addition the DataAccess classes come with a method that returns a ResultSetConverter object.  The ResultSetConverter gets a ResultSet and converts the ResultSetMetaData into a 1 dimensional array and the ResultSet itself into a 2 dimensional array.  

 

FormattedDataSet fds=FormattedDataSet.createInstance();

ResultSetConverter rsc=fds.getResultSetConverter("select * from table");

String html=fds.getFormattedDataSet(rsc, “htmlTable”);

 

The above code snippet demonstrates one way to get a ResultSetConverter object.   If a developer chooses to use a ResultSetConverter instead of a ResultSet then the implementation details of interacting with JDBC (i.e. opening and closing Connections, Statements, and ResultSets) are all hidden.  This eliminates a whole class of resource allocation/deallocation bugs (not closing Connections for example).  All conversions required to change a ResultSet to a ResultSetConverter are timed with JAMon and so any performance impacts will be known.  In applications that I have worked with the performance impacts were negligible.

 

The FormattedDataSet has overloaded methods to take a ResultSetConverter as shown in the sample code.  ResultSetConverter’s (unlike ResultSets) can be cached, serialized, sorted and more, as they are just 2 dimensional arrays. 

 

A powerful class called the ArrayComparator that sorts 2 dimensional arrays is also provided.  The ArrayComparator and ResultSetConverter objects are the mechanism behind all the various FormattedDataSet sorting methods.

 

The FormattedDataSet API comes with 2 implementations of the DataAccess interface.  DataAccessJ2EE (uses J2EE DataSources), and DataAccessClient (used for non-pooled J2EE environments).  Both can connect to any number of backend database servers (Sybase ASE, Sybase ASE, MySQL, and Microsoft Access have been tested).  By default the FormattedDataSet uses the DataAccessJ2EE class, but by calling the setDataAccessFactory it can interact with any implementation of the DataAccess interace. 

 

If developers want to handle their own JDBC calls the “getFormattedDataSet(…)” method is overloaded to take ResultSet’s directly too.

 

4.5     Hiding the FormattedDataSet – An Implementation Detail

 

The FormattedDataSet API should be viewed as an implementation detail to be hidden from client code.   This is also referred to as “programming to the interface”. Implementation is “how” you do something, and an interface is “what” you are doing.  Implementation details change much more often than an interface, so by hiding the implementation you protect your code from these changes. 

 

For example say you are using the FormattedDataSet  and SQL to generate XML in a JSP.  The code may look like the following:

<%= fds.getFormattedDataSet(“select fname, lname, salary from employees”, “xml”) %>

This code exposes “how” the XML is to be generated (using the FormattedDataSet, and SQL), and unnecessarily exposes the JSP to several risks:

1.      If you decide to use a different approach other than the FormattedDataSet to generate XML then the JSP import and method call would have to be changed.  Multiply this by the number of JSP’s that call the FormattedDataSet.

2.      If FormattedDataSet developers change the method name or signature to the “getFormattedDataSet(…)” method the above code will break.

3.      If FormattedDataSet developers change the name of the “xml” template or the templates behaviour the above code will break.

4.      If the query changes (say by renaming a column, adding a column or using a stored proc instead of the select statement) then the above code will break.

 

It is better to expose a class you control (MyReports below) to the client.  This class should give away as little information as possible about implementation details.  Using this approach you avoid many of the problems mentioned and often end up with more flexible, readable code:

 

<% MyReports myReports=new MyReports; %>

<%= myReports.getEmployeesXML() %>

 

Behind the scenes this code may simply call “getFormattedDataSet(…)”, but now any of the changes mentioned previously can be made without breaking the JSP.  The MyReports class would have to be changed, but the changes would only affect this one class as opposed to many JSP’s.

 

The FormattedDataSet can be viewed as an implementation detail, but so can subsystems such as the JDBC and EJB layers, so I recommend hiding them also.

 

4.6     Using the FormattedDataSet to display Java Objects

Often a collection of Java objects can be thought of as TabularData.  For example if we have an Employee object with properties first and last name, then a collection of these Employees can be thought of as TabularData.  The FormattedDataSet can easily be used to display this type of information.  One way is to implement the TabularData interface for a collection of Employees, however often an easier approach is to return the Employees as a 2 dimensional array of Objects (Object[][]), as the FormattedDataSet already supports this type of TabularData.

 

The following example is a working program that shows how the FormattedDataSet may be used to display a collection of Employees. 

 

 

 

package com.mysampleapp;

 

import java.util.*;

import com.fdsapi.*;

 

 

public class Employee {

  private String fName;

  private String lName;

 

  public Employee(String fName, String lName) {

    this.fName=fName;

    this.lName=lName;

  }

 

  public String getFirstName() {

     return fName;

  }

 

  public String getLastName() {

     return lName;

  }

 

  // Return an Employee Object as a 1 dimensional array

  public Object[] getEmployee() {

     return new Object[] {getFirstName(), getLastName()};

  }

 

  // Return all Employees as a 2 dimensional array.

  public static Object[][] getEmployees() {

      Object[][] emps=new Object[list.size()][];

      for (int i=0; i<list.size(); i++) {

          Employee emp=(Employee) list.get(i);

          emps[i]=emp.getEmployee();

      }

      return emps;

  

  }

 

  // Return a header of the field labels.

  public static String[] getEmployeesHeader() {

      return new String[]{"FirstName", "LastName"};

     

  }

 

  private static List list=new ArrayList();

  public static void add(Employee emp) {

   list.add(emp);  

  }

 

  public static void main(String[] args) {

   add(new Employee("Keith", "Richards"));

   add(new Employee("Mick", "Jagger"));

   add(new Employee("Charlie", "Watts"));

   add(new Employee("Bill", "Wyman"));

   add(new Employee("Brian", "Jones"));

   add(new Employee("Mick", "Taylor"));

   add(new Employee("Ron", "Wood"));

  

   FormattedDataSet fds=FormattedDataSet.createInstance();

   String[] header=Employee.getEmployeesHeader();

   Object[][] body=Employee.getEmployees();

  

   // Print employees as an HTML table

   System.out.println(fds.getFormattedDataSet(header, body, "htmlTable"));

 

  }

   

}

 

 

4.7     Installing the FormattedDataSet

 

Installing the FormattedDataSet API is as simple as putting 3 small jars (less than 100K each) in your classpath (or in your web-inf\lib in the case of  Web Applications).  The jars are fdsapi.jar, JAMon.jar (Used for monitoring), and jakarta-oro-2.0.6.jar (Regular expression engine used to parse the Templates.  Other versions may work, but were not tested.)

That’s it!  Once installed to test you can try the following code:

import com.fdsapi.*; // FormattedDataSet API

FormattedDataSet fds=FormattedDataSet.createInstance();

String[] header={“fname”, “lname”};

Object[][] body={{“Steve”, “Souza”},{“Jeff”, “Beck”}, {“William”, “Reid”}}; System.out.println(fds.getFormattedDataSet(header, body, “basicHTMLTable”));

 

Note:  This product includes software developed by the Apache Software Foundation (http://www.apache.org/).

4.8     Running the Demo Application

 

If you have an app server that can run Web Applications (WARs) then install the demo application (fdsapidemo.war).  The WAR has been tested with Sybase’s EAServer connecting to Sybase ASE, and Apache Tomcat connecting to MySQL. The demo has 4 pages:

- http://myhost:port/fdsapidemo/demo.jsp - Index for the other demo pages in the WAR.   No database access or configuration is required to access this page.

- http://myhost:port/fdsapidemo/basicdemo.jsp - Simple JSP demonstrating how to create dynamic HTML (tables, list boxes, drop down list boxes and multi-select list boxes), XML and CSV files.  No database access or configuration is required to access this page.

- http://myhost:port/fdsapidemo/querydemo.jsp - A JSP that displays a textarea to enter a SQL select.  The query is executed and the ResultSet is formatted as an HTML table.  You will have to edit the jsp to configure a connection to your database for this page to work.  Sample code is already in the JSP to connec to MySQL, Sybase ASA, Sybase ASE, and J2EE apps using “javax.sql.DataSource” ( If your server uses authentication you may have to use the DataAccessJ2EE constructor that accepts authentication parameters via InitialContext).

- http://myhost:port/fdsapidemo/sortdemo.jsp - Just like querydemo.jsp except the ResultSet is sortable by clicking the HTML table’s column headers.

- http://myhost:port/fdsapidemo/JAMonAdmin.jsp - Administration page for JAMon (an open source performance tuning API), that displays various performance statistics for the demo WAR.  No database access or configuration is required to access this page.

 

A demo is also available at http://www.fdsapi.com

 

5.     Template Terms

5.1     Template Tag 

·        Template Tag Format - <!--level1_level2_level3 row, col -->value<!--level1_level2_level3  row,col -->

·        Template tag level 1 – Possible values COMPOSITE, HEADER, BODY

·        Template tag level 2 – Possible values empty (i.e. no value), ROW, CELL

·        Template tag level 3 – Possible values PREFIX, DATA, SUFFIX

·        Example - <!--BODY_CELL_PREFIX 4,2 --><td><!-- BODY_CELL_PREFIX 4,2 -->

5.2     Template Start and End Tags

·        Template Start Tag - The tag portion before the value.  This must exactly match the Template End Tag.

o       <!-- BODY_CELL_PREFIX 4,2 --><td><!-- BODY_CELL_PREFIX 4,2 -->

·        Template End Tag – The tag portion after the value.  This must exactly match the Template Start Tag.

o       <!-- BODY_CELL_PREFIX 4,2 --><td><!-- BODY_CELL_PREFIX 4,2 -->

·        Template Start and End tags are not case sensitive.  The following is valid

o       <!-- body_cell_prefix 4,2 --><td><!-- Body_Cell_Prefix 4,2 -->

 

5.3     Template Tag Coordinate

 

·        Template Tag Coordinate – A row and column number that specifies the cell that the formatting should be applied to.   Template tag coordinates have the following possibilities searched for in the given order: 

o       A value for a specific cell – Both row and column are provided (i.e 4,2)

o       A row default – A row is provided and, the column is 0 (i.e. 4,0).  In the example all cells within row 4 would have the given formatting.

o       A column default – A column is provided, and row is 0 (i.e. 0,2).  In the example all cells within column 2 would have the given formatting.

o       An overall default – This can either be specified by a 0,0 coordinate or the absence of a coordinate.   This value applies to all cells that don’t have any of the other template tag coordinates.  

 

 

Template tag Value Template tag Value Template tag ValueTemplate tag Value Template tag Value Note the template tag coordinate used in the start tag and the end tag must match. Example:  <!--BODY_CELL_PREFIX 4,2 --!><td><!--BODY_CELL_PREFIX 4,2 --!>

5.4     Template Tag Value

·        Template Tag Value – The value that is surrounded by the Template start and end tags.   This value is used to determine what text to generate for a particular cell.  The following sample shows a simple template tag value.   They may be much more complex (for example they can contain template tag variables) as will be discussed later in this document.

o       <!--BODY_CELL_PREFIX 4,2 --><td><!--BODY_CELL_PREFIX 4,2 -->

 

5.5     Template Tag Variables

·        Template Tag Variables – A portion of the template tag value that provides further information when the template is processed.  The template tag variables have the following format:

o       TemplateTagVariableName==TemplateTagVariableValue

o       Developers can create their own Template variables.  The ones that the FormattedDataSet API comes with out of the box are discussed later in this document.

o       Template Tag Variable Values – The value that is on the right of the template tag variable name.  The values can be static or dynamic.  Dynamic portions of the value use template tag variable substitution.  Template tag variable substitution replaces template tag variable values starting with ‘##’ at runtime with dynamic data.  For example in “body_cell_data” Template Tag,  ##1 will dynamically replace ##1 with the data in the current row and first column of the result set.   See further sections for more info on template tag variable substitution.

o       The order for Template tag variables does not matter.  The following are equivalent

·        <!-- BODY_CELL_DATA -->Type==Query Template==table Query==select * from table where col=’##1’<!-- BODY_CELL_DATA -->

·        <!-- BODY_CELL_DATA -->Query==select * from table where col=’##1’ Type==Query Template==table<!-- BODY_CELL_DATA -->

 

 

6.     Template Rules

6.1     Template Tag Rules

 

Template Tag Rules - Presently there is no syntax checking for Templates.  This means that you must be careful when typing them in.  I suggest keeping a master template that you copy and paste to create other templates.  There is a master template in this document.   Some types of errors are written to the standard out, so if you are having problems review them.

Only template tag values within valid template start and end tags are parsed by the template parser.  All other values are ignored.  The text below that says IGNORED is not parsed.

·        Typo in start tag

o       <!-- BODY_CLL_PREFIX 4,2 -->IGNORED <!--BODY_CELL_PREFIX 4,2 -->

·        Unmatched template tag coordinate

o       <!-- BODY_CELL_ PREFIX 4,5 -->IGNORED <!--BODY_CELL_PREFIX 4,9 -->

·        Only text inside a start and end tag pair is used.

o       IGNORED <!-- BODY_CELL_ PREFIX -->this value will be used<!--BODY_CELL_PREFIX -->

·        HTML comment tag was incorrectly typed in start tag (Extra spaces were added)

o       <!   -- BODY_CELL_ PREFIX -->IGNORED<!--BODY_CELL_PREFIX -->

 

 

6.2     Template Tag Variable Name Rules

 

·        White space between a template tag variable name and the ‘==’ character are ignored.  The following two items are equivalent

 

6.3     Template Tag Variable Value Rules

 

·        variable1== my first value   variable2==my second value

 

Sample Code: 

 

Map miscData=new HashMap();

int[] array={100,200,300,400};  // if an array it must be a 1 dim int or Object array.

miscData.put(“date”, new Date());  // template can reference this value with “##date”

miscData.put(“array”, array); // template can reference “##array2”, or “##arrayThis”

FormattedDataSet fds=FormattedDataSet.createInstance();

String text=fds.getFormattedDataSet(“select * from table”, miscData, “myTemplate”);

 

 

 

 

7.     Template Hierarchy

The following heirarchy represents the order in which the different portions of a DataSet are displayed. 

 

 

composite=

composite_prefix

composite_data

composite_suffix

composite_data=

            composite_row_prefix

            composite_row_data

            composite_row_suffix

composite_row_data=

            composite_cell_prefix

            composite_cell_data

composite_cell_suffix

composite_cell_data=

            header

            body

 

header=

header_prefix

header_data

header_suffix

header_data=

            header_row_prefix

            header_row_data

            header_row_suffix

header_row_data=

            header_cell_prefix

            header_cell_data

            header_cell_suffix

 

body=

body_prefix

body_data

body_suffix

body_data=

            body_row_prefix

            body_row_data

            body_row_suffix

body_row_data=

            body_cell_prefix

            body_cell_data

            body_cell_suffix

 

 

8.     Predefined Template Tag Variables

 

8.1     DataSource

·        Intent:  This determines what JDBC DataSource will be used for a connection.

·        Sample: DataSource==myDataSource

·        Values: Any valid DataSource that is in the JNDI Resources namespace

·        Default Value: DataSource

·         Template variable substitution:  Yes (i.e. DataSource==##2)

 

8.2     IncrementData

·        Intent:  This determines if the DataSets’ underlying TabularData should move the column pointer to the next column.  A value of true goes to the next TabularData column and a value of false does not.

·        Sample: IncrementData==true

·        Values: true or false

·        Default Value: Depends on the value in Template tag level 3.  It defaults to false for prefix, and suffix DataSets.  It defaults to true for data DataSets.

·        Template variable substitution:  yes (i.e. IncrementData==##1)

·         Case Sensitive:  no (i.e. true is the same as TRUE)

 

 

8.3     Query

·        Intent:  Used to call a stored proc or SQL statement that returns a result set.

·        Sample1: Query==select * from table

·        Sample2: Query==exec procGetBeatles

·        Values: Any valid stored proc or query that returns a result set.

·        Default Value: No default.  This field must be provided.

·         Template variable substitution:  Yes (i.e.  Query==select * from employee where ssn=##2)

 

8.4     Selected

·        Intent:  Used for displaying such HTML elements as ListBoxes which allow a specific value to be selected.  The selected value will usually be made dynamic by using template variable substitution.

·        Sample: Selected==##1

·        Values: Any string.

·        Default Value: No default.  This field must be provided although a blank may be provided indicating no entry should be selected (i.e. Selected==  )

·         Template variable substitution:  Yes (i.e.  Selected==##1)

 

 

 

8.5     Size

·        Intent:  Used to determine how many rows should be displayed using certain HTML elements such as ListBoxes. 

·        Sample: Size==8

·        Values: Any number.

·        Default Value: No default.  This field must be provided.

·         Template variable substitution:  Yes (i.e.  Size==##1)

 

8.6     Template

·        Intent:  The logical template name used to a display a result set

·        Sample: Template==table

·        Values: Any valid template.

·        Default Value: No default.  This field must be provided.

·         Template variable substitution:  Yes (i.e.  Template==##1)

 

8.7     Type

·        Intent:  This determines what type of DataSet will be created for a particular cell.

·        Values:  See a later section further discussing the Type variable for values

·         Sample: Type==QUERY

 

8.8     Odd, Even – See Alternating DataSet below

8.9     If, IfValue, ElseValue – See Conditional DataSet below

9.     Predefined Template Tag Types (i.e. DataSet Types)

Note that developers can also create their own DataSet types, and so the capabilities of DataSets can easily be expanded by the developer community.  This is done by implementing the DataSet interface, checking this object into the DataSetFactory and accessing the defined variables from the TemplateVariables class.

 

Note all of the DataSet Types can be placed in any Template Tag level (i.e. body_cell_prefix, header_row_data, composite_data etc.). 

 

The following sections describe the predefined DataSet Types. 

 

9.1     Alternating

·        Description:  Used to use alternately display different data depending on if the current entity (row or column) is odd, or even.  Similar to an “if then” statement that would display data one way for odd numbers, and another for even numbers.

·        Valid Variables: 

o       Odd:  Required.    Display for odd numbered data.

o       Even:  Required.  Display for even numbered data

·        Example:   The example will display “&nbsp” if the current cell is null else simply display the cell.

o        <!-- BODY_ROW_PREFIX -->Type==Alternating Odd==   <tr class='odd'>\n  Even==   <tr class='even'>\n<!-- BODY_ROW_PREFIX -->

 

9.2     Conditional

·        Description:  Used to display different data depending on the value of the current cell.  Similar to an “if then” statement. 

·        Valid Variables: 

o       If:  Required.    If the value is what comes after “==” then use ifValue, else use elseValue.

o       ifValue:  Required.  See above

o       ElseValue:   Required.  See above.

·        Example:   The example will display “&nbsp” if the current cell is null else simply display the cell.

o       <!-- body_cell_data -->Type==Conditional if==null ifValue==&nbsp; elseValue==##this<!-- body_cell_data -->

 

9.3     Constant

·        Description:  Used when plain text should be displayed for a cell.  If a type is not specified in a template tag a Constant DataSet will be assumed (i.e. it is the default Template DataSet).   Constants can use variable substitution (##columnnumber) as seen in the examples.

·        Valid Variables:  Value and IncrementData

·        Example: The first 2 examples are equivalent

o       <!-- HEADER_CELL_DATA -->Type==Constant Value==##1, ##2<!-- HEADER_CELL_DATA -->

o       The following Defaults to a Constant DataSet:

 <!-- HEADER_CELL_DATA -->##1, ##2<!-- HEADER_CELL_DATA -->

o       <!-- BODY_CELL_PREFIX --><td><!-- BODY_CELL_PREFIX -->

o       <!-- HEADER_CELL_DATA -->Type==Constant Value==##1, ##2<!-- HEADER_CELL_DATA -->

 

9.4     DropDownListBox

·        Description:  Used to execute a query and format the result set as a drop down listbox.

·        Valid Variables: 

o       Query:  Required.  For DropDownListBoxes the query must be of the format “select code_value, display_value from table”.  Where display_value will be shown in the browser and code_value will be submitted back to the server on HTML form submission and will also serve as the variable name.

o       Selected:  Required (although required an empty value can be specified by 2 consectutive spaces like Selected==  )

o       IncrementData:   Optional. 

o       DataSource:  Optional.  Defaults to DataSource

·        Example:

o       <!-- BODY_CELL_DATA 0,3 -->Type==DropDownListBox Query==select state_id, state_name from states where country='USA' Selected==##2<!-- BODY_CELL_DATA 0,3 -->

9.5     Empty

·        Description:  Used when nothing should be displayed for this cell.

·        Valid Variables:  IncrementData

·        Example:

o       <!-- HEADER_DATA -->Type==Empty<!-- HEADER_DATA -->

o       <!-- body_cell_data -->Type==Empty<!-- body_cell_data -->

9.6     ListBox

·        Description:  Used to execute a query and format the result set as a listbox.

·        Valid Variables: 

o       Query:  Required.  For ListBoxes the query must be of the format “select code_value, display_value from table”.  Where display_value will be shown in the browser and code_value will be submitted back to the server on HTML form submission and will also server as the variable name.

o       Selected:  Required (although required an empty value can be specified by 2 consectutive spaces like Selected==  )

o       Size:  Required

o       IncrementData:   Optional. 

o       DataSource:  Optional.  Defaults to DataSource

·        Example:

o       <!-- BODY_CELL_DATA 0,3 -->Type==ListBox Query==select state_id, state_name from states where country='USA' Selected==##2 Size==5 <!-- BODY_CELL_DATA 0,3 -->

9.7     Query

·        Description:  Used to execute a query and to format the result set with a template.

·        Valid Variables: 

o       Query:  Required.

o       Template:  Required

o       IncrementData:   Optional. 

o       DataSource:  Optional.  Defaults to DataSource

·        Example:

o       <!-- BODY_CELL_DATA -->Type==Query Template==table Query==select * from table where col=’##1’<!-- BODY_CELL_DATA -->

o       <!-- BODY_CELL_DATA -->Type==Query Template==table Query==select * from table where col=’##1’ DataSource==myDataSource IncrementData==false<!-- BODY_CELL_DATA -->

 

9.8     RadioButton

·        Description:  Used to execute a query and format the result set as a radio button.

·        Valid Variables: 

o       Query:  Required.  For DropDownListBoxes the query must be of the format “select code_value, ‘groupname’, display_name from department”.   Where display_value will be shown in the browser and code_value will be submitted back to the server on HTML form submission in the variable called groupname.

o       Selected:  Required (although required an empty value can be specified by 2 consectutive spaces like Selected==  )

o       IncrementData:   Optional. 

o       DataSource:  Optional.  Defaults to DataSource

·        Example:

o       <!-- BODY_CELL_DATA  -->Type==DropDownListBox Query== select dept_id, 'department', dept_name from department Selected==##2<!-- BODY_CELL_DATA  -->

 

9.9     Reserved DataSet Types Names

·        The following DataSet Type names shouldn’t be used:

o       NoAppend, Data (can be used but rarely needed) Row, Col, Decorator, Next

 

10.     Sample Master Template

Note you only have to enter the following in your templates if you want to provide specific behaviour for the given template tag level.

********* Composite Tags

<!-- composite_prefix --><!-- composite_prefix -->

<!-- composite_data --><!-- composite_data -->

<!-- composite_suffix --><!-- composite_suffix -->

 

<!-- composite_row_prefix --><!-- composite_row_prefix -->

<!-- composite_row_data --><!-- composite_row_data -->

<!-- composite_row_suffix --><!-- composite_row_suffix -->

 

<!-- composite_cell_prefix --><!-- composite_cell_prefix -->

<!-- composite_cell_data --><!-- composite_cell_data -->

<!-- composite_cell_suffix --><!-- composite_cell_suffix -->

 

********* Header Tags

<!-- header_prefix --><!-- header_prefix -->

<!-- header_data --><!-- header_data -->

<!-- header_suffix --><!-- header_suffix -->

 

<!-- header_row_prefix --><!-- header_row_prefix -->

<!-- header_row_data --><!-- header_row_data -->

<!-- header_row_suffix --><!-- header_row_suffix -->

 

<!-- header_cell_prefix --><!-- header_cell_prefix -->

<!-- header_cell_data --><!-- header_cell_data -->

<!-- header_cell_suffix --><!-- header_cell_suffix -->

 

********* Body Tags

<!-- body_prefix --><!-- body_prefix -->

<!-- body_data --><!-- body_data -->

<!-- body_suffix --><!-- body_suffix -->

 

<!-- body_row_prefix --><!-- body_row_prefix -->

<!-- body_row_data --><!-- body_row_data -->

<!-- body_row_suffix --><!-- body_row_suffix -->

 

<!-- body_cell_prefix --><!-- body_cell_prefix -->

<!-- body_cell_data --><!-- body_cell_data -->

<!-- body_cell_suffix --><!-- body_cell_suffix -->

 

11.     Misc. Template Samples

1) ***** Sample Tags

Any of the following types can be used for any template tag level.  The following are just representative samples

<!-- header_data -->Type==Empty<!-- header_data -->

<!-- body_cell_prefix --><td><!-- body_cell_prefix -->

a column default follows

<!-- body_cell_prefix 0,2 --><td><!-- body_cell_prefix 0,2 -->

a row default follows

<!-- body_cell_prefix 1,0 --><td><!-- body_cell_prefix 1,0 -->

a value for a specific cell follows

<!-- body_cell_prefix 4,2 --><td><b><!-- body_cell_prefix 4,2 -->

<!-- body_cell_data -->Type==Query Template==table Query==select * from table where col==’##1’<!-- body_cell_data -->

<!-- body_cell_data -->Type==Query Template==table Query==select * from table where col==’##1’ DataSource==myDataSource IncrementData==false<!-- body_cell_data -->

<!-- body_cell_data -->Type==ListBox Query==select state_id, state_name from states where country='USA' Selected==##2 Size==5 <!-- body_cell_data -->

<!-- body_cell_data -->type==DropDownListBox Query==select state_id, state_name from states where country='USA' Selected==##2<!-- body_cell_data -->

<!-- body_cell_data  -->Type==DropDownListBox Query== select dept_id, 'department', dept_name from department Selected==##2<!-- body_cell_data  -->

 

2) Recommended way of doing sample clickable elements

<!-- body_cell_data 0,2 -->Type==Constant Value==<a

href='Main?pageName=LogScanServer&SERVER=##this'>##this</a>

<!-- body_cell_data 0,2 -->

 

<!-- body_cell_data 0,4 -->Type==Constant Value==<img

src='##this-ball.gif' alt='##this'>

<!-- body_cell_data 0,4 -->

 

3) to replace all of the header (except for prefix and suffix)

<!-- header_row_data -->

    <th>Contract No.</th>

    <th>Vendor Name</th>

    <th>Schedule No.</th>

    <th>Buyer Code</th>

    <th>Received Date</th>

    <th>File Status</th>

    <th>Catalog Action</th>

    <th>Text Status</th>

    <th>Source</th>

    <th>DUNS No.</th>

<!-- header_row_data -->

 

4) To not display column 5 of the tabulardata

<!-- body_cell_prefix 0,5 --><!-- body_cell_prefix 0,5 -->

<!-- body_cell_data 0,5 -->Type==Empty<!-- body_cell_data 0,5 -->

<!-- body_cell_suffix 0,5 --><!-- body_cell_suffix 0,5 -->

 

5) the following template renders the html template (only changes that affect row color are shown)

paradoxically the column number below really represents the row (i.e. 2 and 3).

only 0, or 1 will work for the first parameter and they would render the same thing.

so when dealing with any of the body_row tags the template deals with n rows as 1 row with n columns.  so to specify formatting for the nth row use the template tag coordinates of “0,n”.  a row value of 2 would never be used.

<!-- BODY_ROW_PREFIX 0,2 --><tr bgcolor=blue><!-- BODY_ROW_PREFIX 0,2 -->

no effect <!-- BODY_ROW_PREFIX 2,0 --><tr bgcolor=green><!-- BODY_ROW_PREFIX 2,0 -->

<!-- BODY_ROW_PREFIX --><tr bgcolor=green><!-- BODY_ROW_PREFIX -->

<!-- BODY_ROW_PREFIX 0,3 --><tr bgcolor=red><!-- BODY_ROW_PREFIX 0,3 -->

 

Department

Manager

R & D

David Scott

Sales

Judy Snow

Finance

Mary Anne Shea

Marketing

Scott Evans

Shipping

Jose Martinez

 

6) Every other row indicators.  see htmlTable template for what this will look like.

<!-- BODY_ROW_PREFIX -->Type==Alternating

Odd==   <tr class='odd'>

Even==   <tr class='even'>

<!-- BODY_ROW_PREFIX -->

 

12.     Acknowledgements

I’d like to thank the General Services Administration (GSA) for their support in helping the FormattedDataSet API come to life.  I’d also like to thank Eric Laufer for all the great work he has done in creating visually appealing HTML GUI’s that demonstrate the benefits of using the FormattedDataSet API.