Examples

Tabulator comes with a set of examples. Each is designed to illustrate various features/capabilities of the Tabulator framework.

Each example builds to produce a .zip file, which is then unzipped somewhere to install it. Here we assume unzipping to /tab_<example-name>.

Music Database

The data is stored in a .json file, 2 .csv files and an .xml file. This examples uses JSON file, flat-file and XML file sources to access them. As a result, it has no external dependencies. Regardless of whether you have QPid, MariaDB or MarkLogic Server, or not, you should be able to run this example.

$ /tab_music/bin/TabulatorServer

The "album" type has an attribute called "year" which is a part of an attribute group called "extras".

The 4 "Type" classes provide navigations between each other, primarily based upon whether you are looking at a "list" or "show" page.

This example shows off the role based security in the web application. The guest user isn't able to view the "review" type. Only andy can do this.

A Type named T is accessible to a user if the user has a role called type.T, the role types.* or a role which has been added to the Type with the addRole method.

Complex JSON

The data is stored in a single complex.json file, which as the name suggests, is quite complicated.

The example shows off many of the features of the JSON file source.

$ /tab_json/bin/TabulatorServer

Orders Database

This example assumes you have MariaDB installed, listening on its default port (3306).

$ /tab_orders/bin/TabulatorServer

The sample comes with a couple of .sql files. One file is to be used to set up the database and populate it with some content, the other cleans out the content. Read the comments at the start.

The comments describe setting up a database called order_db and a user called order with password password. This corresponds to the values in the sample code "Configuration" class.

The sample .sql files are MariaDB specific. However, a file orders.xml is also included which is a database configuration file. DBSetup can be used to read this file and generate create and drop scripts which work on MySQL (and thus MariaDB), Oracle or Sybase.

The example configuration instantiates 2 "Type" classes, one for "order" and one for "item".

The "order" type is a simple binding of attributes to columns in the ORDERS table.

$ mysql --user root --password
Enter password:

mysql> use order_db ;

mysql> select * from ORDERS ;
+----+-------------+
| id | customer    |
+----+-------------+
|  1 | Wile Coyote |
|  2 | Roadrunner  |
+----+-------------+
2 rows in set (0.00 sec)

The "item" type is a little more sophisticated. Most of its attributes are simple bindings of attributes to columns in the ITEMS table.

mysql> select * from ITEMS ; 
+----+----------+--------------------+
| id | order_id | description        |
+----+----------+--------------------+
| 10 |        1 | Acme explosives    |
| 11 |        1 | Acme rocket sledge |
| 12 |        1 | Medical insurance  |
| 20 |        2 | Bird seed          |
+----+----------+--------------------+
4 rows in set (0.00 sec)

However, it implements an attribute group called "Customer". If this is selected, we also have an additonal attribute called "customer". This attribute does not come from the ITEMS table, it actually comes from the ORDERS table. Put another way, the "customer" shown on the "item" is actually the "customer" from the "order" the "item" is a part of. ie: its a denormalised or JOINed view. So in this case, the query done is actually for the JOIN of the ORDERS and ITEMS tables.

mysql> select i.id,i.order_id,i.description,o.customer
    -> from ITEMS i LEFT JOIN ORDERS o ON i.order_id = o.id ;
+----+----------+--------------------+-------------+
| id | order_id | description        | customer    |
+----+----------+--------------------+-------------+
| 10 |        1 | Acme explosives    | Wile Coyote |
| 11 |        1 | Acme rocket sledge | Wile Coyote |
| 12 |        1 | Medical insurance  | Wile Coyote |
| 20 |        2 | Bird seed          | Roadrunner  |
+----+----------+--------------------+-------------+
4 rows in set (0.00 sec)

Because the query is using column name aliases, the example uses a mapping from attribute names (as known to Tabulator) and SQL column names (including the alias prefixes).

Note: The code is configured to use the MariaDB JDBC driver and JDBC URL, but some of the text above was captured running on MySQL.

Fishy Database

This example shows off the XCC source.

This example assumes you have MarkLogic Server installed.

$ /tab_fishy/bin/TabulatorServer

The sample comes with an .xqy file which includes comments on how you should set up MarkLogic, and how you should execute the file to populate it with sample data.

The example configuration instantiates 3 "Type" classes, one for a type of "fish", one for an "environment" in which fish may be found and one called "environmentResident" which records the numbers of a given fish type found in an environment.

One of the fish documents looks like this :-

<fish>
  <variety>koi</variety>
  <cost>120</cost>
  <length units="cm">30</length>
  <length units="inch">12</length>
  <description>Exotic. Often Japanese. Beautifully coloured.</description>
</fish>

One of the environment documents looks like this :-

<environment>
  <name>pond</name>
  <residents>
    <resident>
      <fish>koi</fish>
      <number>20</number>
    </resident>
    <resident>
      <fish>english-koi</fish>
      <number>2</number>
    </resident>
  </residents>
</environment>

Note that the environment document includes details of the environment (ie: the fact it is named "pond"), and a repeating block, one per resident fish type in that environment. Its quite common for a single document to represent a hierarchy like this.

The code for the "fish" type takes advantage of the fact the URIs for the fish documents are named fish/ followed by the variety. This speeds up searching if we know from the start what documents to fetch. There is a convention for environment document URIs too, but the supplied code doesn't exploit this.

The sample only cares about fish lengths in centimetres. However, one of the fish also has a measurement in inches. Because the units are encoded in an attribute, it's not possible to construct a precise query to search on it. Therefore this code can fetch more fish than is necessary, but conveniently the SourceXCC.search() method filters out the false positives.

The "fish" type provides an extended navigation which displays the raw XML page corresponding to a variety of fish. To do this, it uses a low-level method in the XCC source called searchResultItems and streams the data directly to the browser.

The Fishy Database example shows how named type group(s) can be created and types associated with them. This causes a different presentation on the home page of the web interface whereby all buttons for types in the same type group are grouped together on the same line, thus reducing screen clutter.

QPid JMX

In this example, it is assumed you have QPid running, with RMI port 8999 and the admin userid with admin password. These values can be changed in the "Configuration" class.

The example simply instantiates the JMX variants of the QPid queue type and the QPid message type.

$ /tab_qpidjmx/bin/TabulatorServer

QPid REST

In this example, it is assumed you have QPid running, with an admin userid with admin password. You need to have configured a "HTTP" listener using SSL on port 8443. You'll probably be using an internally generated self-signed certificate, and it'll need to be exported to SelfSigned.jks. This file has an empty (ie: zero characters long) keystore password. These values can be changed in the "Configuration" class.

The problem with using normal HTTP access is that QPid (quite sensibly) won't let you use basic authentication (you can enable this), or see message headers or content (you can't enable this).

The example simply instantiates the REST based variants of the QPid queue type and the QPid message type.

$ /tab_qpidrest/bin/TabulatorServer