08-Jul-2008

AjaxToaster Release Notes – 1.0.0 RC2

Introduction

These release notes describe the first release of AjaxToaster.

AjaxToaster provides services to client applications that allow them to easily access data held in a relation database in a convenient format (either XML or JSON) in structures of arbitrary complexity.

AjaxToaster uses XMLToaster to give you the power to extract and save data in almost any structure that you might require. These release notes will not fully describe the functionality of XMLToaster – for this information please refer to the XMLToaster release notes and tutorial at www.inverse2.com

Prerequisites

AjaxToaster requires Java 1.5 JRE or above.

AjaxToaster can be downloaded in various packages (described in a section below). The packages come complete with all of the JARs that you need (except for JDBC drivers for databases other than H2).

If you need to set-up AjaxToaster from scratch as a web application then the versions of the JAR files required are as follows;
ajaxtoaster.jar  : AjaxToaster JAR
xmltoaster.jar   : XMLToaster 1.0.12 (or above)
jdom.jar         : JDOM version 1.0
jaxen1.1.1.jar   : JAXEN version 1.1.1
If you need to set-up AjaxToaster from scratch as a standalone server then you require the above JAR files, plus;
jetty-6.1.8.jar
jetty-util-6.1.8.jar
servlet-api-2.5-6.1.8.jar
You can get the Jetty files from the following link;
Jetting Zip File
Download the zip file, unzip it and the required JAR files are in the 'lib' directory.

The JDOM and JAXEN files can be downloaded from the following links;
JDOM Download
Jaxen Download

Available Download Packages

AjaxToaster Web Application

Download this package if you want to install the AjaxToaster web application in a J2EE web container.

The download is a web archive (WAR) file that can be installed in a J2EE web container such as Tomcat. The WAR contains the AjaxToaster web application, plus service implementations for the example applications. If you want to cleanup the installation then you can remove the following;
The directory named "database" in the webapps directory.
The H2 database driver JAR in the "webapps/WEB-INF/lib" directory.
The directory named "recipe" in the "webapps/services" directory.
The directory name "meeting" in the "webapps/services" directory.
You may wish to remove some or all of the service implementation files from the "webapps/services/system" directory.
When installed the application runs under the context “toaster”, therefore the URL to invoke services will be in the format;
http://server:port/toaster/service

AjaxToaster Example Applications

This package contains example applications that use AjaxToaster. To run the example applications you must also download and deploy the "AjaxToaster Web Application" WAR file.

AjaxToaster Standalone Server

Download this package if you want to run a standalone AjaxToaster server.

This download is useful if you want to use AjaxToaster but don't have a J2EE web container to run it in.

The download is a ZIP archive that can be unzipped and then AjaxToaster can be run using one of the provided start-up scripts.

To run it on a Microsoft Windows operating system use the script;
cd unzip_directory\AjaxToasterStandaloneServer
winrun.bat
To run it on a Linux operating system use the script;
cd unzip_directory/AjaxToasterStandaloneServer
./run.sh
By default the server will listen on port 8089, consume all URLs passed to it and look for script files in the directory that you run the script from. This default behaviour can be configured by passing the following parameters to the start-up script;
-p nnnn      : to set the port that the server will listen on
-d directory : to set the root directory where the server will look for service scripts
-c /context  : to set the services' context, e.g. http://localhost:8089/context/mapping?params...
-m /mapping  : to set the services' serlvet mapping, e.g. http://localhost:8089/context/mapping?params
Note that the options passed using the -c and -m parameters should always start with forward-slash (/).

AjaxToaster JAR File

Download this file is you want to set-up an AjaxToaster Servlet from scratch or if you want to upgrade the version of AjaxToaster that you are using.

To set-up an AjaxToaster Servlet from scratch you need to put the downloaded JAR file onto your web applications' classpath (for example put the JAR file into the directory your_web_app/WEB-INF/lib) and specify the following class as a “servlet-class” in the “web.xml” file of your application;

com.inverse2.ajaxtoaster.AjaxToasterServlet
For example;
<servlet>
  <servlet-name>AjaxToasterServlet</servlet-name>
  <servlet-class>com.inverse2.ajaxtoaster.AjaxToasterServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>AjaxToasterServlet</servlet-name>
  <url-pattern>/toaster</url-pattern>
</servlet-mapping>
To upgrade the version of AjaxToaster you are using simply stop your web container, copy the newer version of the JAR file to the directory where it was previously (normally in WEB-INF/lib under a web application directory) and then restart your web container.

Using AjaxToaster

The Service Directory

When the AjaxToaster Servlet initialises it will search for configuration files and script files that describe callable services (i.e. scripts with one of the following extensions “.stx”, “.xts” or “.custom”). The directory (and sub-directories under it) that will be searched will be determined in the following way;
If the Servlet is running as a standalone server then either the value passed as the “-d” parameter, or the directory where the start-up script was run from will be searched for service files.

Otherwise, if the Servlet initialisation parameter “toaster.script.path” is defined and specifies a valid directory (i.e. a directory that AjaxToaster can read) this will be searched for service files.

Otherwise, AjaxToaster will try to look in the web applications' root directory. If a directory named “services” exists then this be searched for service files, otherwise all directories under the web applications' root directory will be searched.

AjaxToaster Configuration File

Once the service directory has been determined AjaxToaster will look in it for a file named “AjaxToaster.properties”. This file configures the behaviour of AjaxToaster when it is running and may contain the following properties;
default_db_jndi_name - Specifies the database that a service script will use if it doesn't specify an alternative

default_db_jdbc_pool - The same as the above property, except that the default database is defined as a JDBC connection pool managed by AjaxToaster rather than one handled by the web container

ToasterPoolRefreshInterval - Specifies the number of milliseconds that AjaxToaster will wait before checking if any services have changed and need refreshing
The default_db_jndi_name and default_db_jdbc_pool properties are mutually exclusive, but if you do specify both the value of default_db_jndi_name will be used.

The configuration file also contains details of what JDBC connection pools that AjaxToaster will set-up and manage. These are an alternative to the connection pools that the J2EE container can provide via JNDI. JDBC connection pools can be set-up using the following properties;
jdbc.driver.xxx   - The name of the JDBC driver class
jdbc.database.xxx - The URL to connect to the database with
jdbc.username.xxx - The user to connect to the database as
jdbc.password.xxx - The password for the above user
The value of “xxx” should be replaced in the property names with a string of your choosing. AjaxToaster will use this string as the name of the JDBC connection pool which allows your application to maintain connections to multiple databases. The connection pool name is the value that you need to specify in the default_db_jdbc_pool property to make a particular pool the default one that service scripts will use.

The ToasterPoolRefreshInterval property specifies how many milliseconds AjaxToaster will wait between checking whether any of the service script files have changed. If a file has changed then the new version of the service will be cached and used. By default AjaxToaster will wait for 30 seconds between these checks. In a development environment it can be beneficial to decrease this and make script changes take effect faster. In a live environment it is probably better to increase this interval.

Here is a complete example of a “AjaxToasterServlet.properties” file;
# Specify the default database as a JDBC connection pool maintained by AjaxToaster
default_db_jdbc_pool=mydb

# How long to wait between checking if service scripts have changed (1 minute)
ToasterPoolRefreshInterval=60000

# A jdbc connection pool for the H2 database “mydb”...
jdbc.driver.mydb=org.h2.Driver
jdbc.database.mydb=jdbc:h2:${CONTEXTDIR}database/mydb;
jdbc.username.mydb=sa
jdbc.password.mydb=password

# A jdbc connection pool for a MySQL database...
jdbc.driver.forum=com.mysql.jdbc.Driver
jdbc.database.forum=jdbc:mysql://localhost/forumdb
jdbc.username.forum=root
jdbc.password.forum=password

AjaxToaster URI Mapping (RESTful Services)

AjaxToaster will look for a file named "AjaxToaster.urimappings" in the service directory. This file can be used to define URI mappings to service calls, which enables you to define RESTful services. For a full description of this feature see the section later in this document that covers RESTful services.

AjaxToaster Services Overview

The services that AjaxToaster provides to a client application can be broken down into three types;
Database Services
Custom Services
Default Services
Each of these service types will be described in detail in the following sections, but they all have one thing in common - they can all be invoked by a client application simply by using a HTTP URL.

The services are held by AjaxToaster in a pool of instances. When a client invokes one of the services AjaxToaster takes a free instance from the pool and asks it to run the clients request. When the number of free instances available in the service pool falls below a threshold AjaxToaster creates new instances. In this way the relatively expensive operation of starting up a service will not slow down the response to a client application.

Each sub-directory under the "services" root directory can contain a properties file named "service.config". This file can be used to define properties that will apply to all services in the directory, unless they over-ride the property setting. For example, you can add a property to the "service.config" file to define which database all scripts in the directory will connect to. Here is an example service.config file;
dbc_pool_name=recipe
login_required=true
valid_users=*
The property file shown above uses the "login_required" property to indicate that a user must login to AjaxToaster before they can run any of the service scripts in the directory. Details of this process are described in the AjaxToaster default services section of this release note.

AjaxToaster Database Services

Database services can be used by a client application to invoke an XMLToaster script to either retrieve or update data in a relational database. The services are specified in files with one of the following extensions;
*.stx : SQL to XML script (selects data from a database)
*.xts : XML to SQL script (updates data in a database)
The files contain the XMLToaster statements to select from a database or to update a database. See the XMLToaster tutorial or the AjaxToaster example applications for examples.

Each file can have an associated properties file – named the same except that the file extension is “.properties” (if a there is no properties file for the script then the values in the "service.config" will be used). The properties file can specify the following information;
script_description - A description of the services' functionality
db_jndi_name       - The JNDI name of the database connection pool
jdbc_pool_name     - The name of the AjaxToaster managed database connection pool
login_required     - true if a user must be authenticated before they can invoke the service
valid_users        - the list of authenticated users that can invoke the service
The db_jndi_name and jdbc_pool_name are mutually exclusive properties. If they are both specified then the db_jndi_name will be used. If neither are specified then the value from one of AjaxToaster configuration properties default_db_jndi_name or default_db_jdbc_pool will be used (as described above).

The login_required property can be set to true if you require a user to have been authenticated by AjaxToaster before they can invoke the service.

If login_required is set to true then you can specify a list of specific users that are allowed to invoke the service (should be defaulted to “*” if any logged in user can run the service). See the note in the "Known Issues" section of this release note.

Here is an example of a database service properties file;
script_description=This is a test service.
jdbc_pool_name=mydb
login_required=true
valid_users=*
An AjaxToaster database service can be invoked by a client application using a URL in the following format;
http://host:port/context/service?param=value¶m=value&etc...
Where the following parameters have special meaning;
returnxml  - forces service output to be returned as XML
returnjson - forces service output to be returned as JSON (default)
inputxml   - XML input data to pass to an update service
inputjson  - JSON input data to pass to an update service
The returnxml and returnjson parameters are mutually exclusive. If neither are specified then AjaxToaster will return data in JSON format.

The inputxml and inputjson parameters are mutually exclusive. You may either specify one of the parameters or use an HTTP POST function to send an input message to XML-to-SQL service (a file with a .xts extension). The data in the input message will be applied to the target database.

Any other parameters found in the URL will be passed to the XMLToaster script to be used as substitution variables. These variables allow you to specify “${VAR}” in an XMLToaster script and the string will be replaced with the value of the variable before the script is executed, for example in a “where clause” you might want to restrict what is selected.

Here are some examples of invoking AjaxToaster database services;
http://localhost:8089/toaster/test/test1
http://localhost:8089/toaster/test/test2?returnxml&id=123
http://localhost:8089/toaster/test/test3?inputxml=<a><b>xyz...</a>

AjaxToaster Custom Services

Custom services can be used by a client application to invoke a Java class on the server. The Java class implements the com.inverse2.ajaxtoaster.interfaces.CustomOperationInterface interface and can then perform any task. The services are specified in files with an extension of;
*.custom
The .custom file contains properties that configure the service and can contain the following information;
script_description - A description of the services' functionality
db_jndi_name       - The JNDI name of the database connection pool
jdbc_pool_name     - The name of the AjaxToaster managed database connection pool
output_style       - How to format generated messages
login_required     - true if a user must be authenticated before they can invoke the service
valid_users        - The list of authenticated users that can invoke the service
script_impl_class  - The name of the class that implements the service
The properties file can also contain any other, service specific, properties. These will be passed to the implementation class when it is initialised.

The class that implements the service interface must be on the classpath of the AjaxToaster web application (normally in a JAR in the directory "WEB-INF/lib").

Details on how to implement a custom service can be found in the "AjaxToaster Custom Services Tutorial".

AjaxToaster Default Services

AjaxToaster provides some built in custom services that can be used to get information about the Servlet's environment.

The following default services are implemented in this release;
Get/Set file contents
Get/Set properties file
Authentication services
You should note that the "service.config" file in the "services" directory specifies that all services in this directory require a client to login to AjaxToaster before they are allowed to invoke the system services. Some of the services override this setting in their own configuration file, for example the "login" service.

Get/Set File Contents
The default installation includes custom services that allows a client to retrieve the contents of a file on the server. The files that specifies these services are in the "services/system" directory and contain the following content;
GetFileContents.custom
script_description=Get the contents of a file
script_impl_class=com.inverse2.ajaxtoaster.serviceImpl.GetFileContents
start.directory=..
valid.extensions=.stx, .xts
response_format=RAW


SetFileContents.custom
script_description=Writes to a file
script_impl_class=com.inverse2.ajaxtoaster.serviceImpl.SetFileContents
start.directory=..
valid.extensions=.stx, .xts
The script_impl_class property specifies the class that implements the service. The classes that implement these services are built into the AjaxToaster JAR file.

The start.directory property says that any file name that the user specifies will be relative to the "services" directory (".." means the parent directory of where the custom script file exists).

The valid.extensions property specifies which file extensions the services will return/update. This is an important security measure.

The response_format of "RAW" indicates that the get service will return the contents of the file as "text/plain".

The SetFileContents service will write the contents of a POST request to the specified file.

The name of the file for these services to operate on must be specified in a parameter named "filename" in the URL. For example;
http://localhost:8080/toaster/system/GetFileContents?filename=recipe/RecipeList.stx

Get/Set Properties File Contents
The default installation includes custom services that allows a client to retrieve the contents of a properties file on the server. The files that specifies these services are in the "services/system" directory and contain the following content;
GetPropertiesFile.custom
script_description=Get a properties file
script_impl_class=com.inverse2.ajaxtoaster.serviceImpl.GetPropertiesFile
start.directory=..
valid.extensions=.properties, .custom


SetPropertiesFile.custom
script_description=Set a properties file
script_impl_class=com.inverse2.ajaxtoaster.serviceImpl.SetPropertiesFile
start.directory=..
valid.extensions=.properties, .custom
The script_impl_class property specifies the class that implements the service. The classes that implement these services are built into the AjaxToaster JAR file.

The start.directory property says that any file name that the user specifies will be relative to the "services" directory (".." means the parent directory of where the custom script file exists).

The valid.extensions property specifies which file extensions the services will return/update.

The SetPropertiesFile service will write the contents of a POST request to the specified file.

The name of the file for these services to operate on must be specified in a parameter named "filename" in the URL. For example;
http://localhost:8080/toaster/system/GetPropertiesFile?filename=system/GetProperties.custom

The format of the message that must be exchanged for these services is as follows;
<properties>
    <property>
        <key>...</key>
        <value>...</value>
    </property>
    ...many be many instances of property...
</properties>

Authentication Services
In the standard AjaxToaster release authentication is performed by three custom service implementations. These services use a text file to store the username and passwords of valid AjaxToaster logins and the classes for these services are included in the AjaxToaster JAR file.

For more sophisticated authentication you will have to implement your own authentication services. These services simply have to set the servlet session attributes LoggedIn and LoggedUser to true/false and the users' name respectively.

The standard classes are defined as the following services;
system/login
system/setpassword
system/logout
To login to AjaxToaster a client sends a request to the following URL;
http://localhost:8080/toaster/system/login?username=xxxx&password=yyyy
The service then checks that the username exists in the file "system/AjaxToaster.passwd" and that the base64 encoding of the SHA hash of the provided password matches the one in the file. If this is the case then the user is logged in by setting the servlet session attributes described above.

It is worth noting that the users' password is sent in cleartext, therefore it is suggested that calls to these authentication services should be done using HTTPS.

Once logged in, a user can change their password by sending a request to the following URL;
http://localhost:8080/toaster/system/setpassword?password=yyyy
A user can logout by sending a request to the following URL;
http://localhost:8080/toaster/system/logout
Currently there isn't a service implementation to create a new user, so to perform this function you have to manually generate a hash for the new users' password and add the username and password to the "AjaxToaster.passwd" file.

To generate the password hash you need to run the following from a command line prompt;
$ java -cp ajaxtoaster.jar com.inverse2.ajaxtoaster.serviceImpl.FlatFileAuthentication newpassword
The default installation comes with a single default user called admin, with a password or "admin". The contents of the default "AjaxToaster.passwd" file is shown below.
admin=0DPiKuNIrrVmD8IUCuw1hQxNqZc=

AjaxToaster Service Error Responses

If an error occurs when invoking a service then AjaxToaster returns a message in a standardised format. This format is as follows;
<error>
    <description/>
    <detail/>
</error>

JSON Callback

If you wish to invoke an AjaxToaster service using a Javascript JSON callback then you can simply add "callback=function" to the URL of the service.

For example, this HTML will invoke the AjaxToaster service and pass the returned JSON object to the "test" function;
<script type="text/javascript">
    function test(obj) {
        alert("Hello!");
    }
</script>
<script type="text/javascript"
    src="http://host/toaster/service/operation?callback=test">
</script>

RESTful Services

The services that AjaxToaster exposes can be mapped to a Uniform Resource Identifier (URI) to expose the services in a REST (REpresentational State Transfer) architecture.

As indicated in a section above, at startup AjaxToaster reads a file in the services directory named "AjaxToaster.urimappings". This file contains the mappings that allow you to map RESTful URIs to AjaxToaster services. AjaxToaster will also monitor this file for any changes and refresh its' cache of mappings if the file changes.

The URI mappings in the "AjaxToaster.urimappings" file are in the following format;
URI.HTTPMethod=AjaxToaster Service
For example, you might wish to expose a RESTful URI that returns information about a person in the following format;
/person/personId
And you might have a "person" service implemented in AjaxToasterwith the following URI;
/myservice/person?PERSONID=999
To map the RESTful URI to the AjaxToaster service you would add the following line to the "AjaxToaster.urimappings" file;
/person/{id}.GET=/myservice/person?PERSONID={id}
This indicates that when a client accesses a URI "/person/anything" with an HTTP GET request the AjaxToaster service "/myservice/person" will be called and passed a parameter named "PERSONID" populated with a value from the second part of the original URI.

You can then map the URI and another HTTP method to another service, for example;
/person/{id}.POST=/myservice/updatePerson
The content of the POST will be passed to the "updatePerson" service.

The mapped URI can be any arbitary format and you can map the following HTTP methods;
GET
POST
PUT
DELETE
For more information about creating RESTful services please see the "RESTful Services Tutorial".

Known Issues

The following is a list of issues that are known to exist in AjaxToaster.
The "Recipe" example application does not show the menu side bar when running under Internet Explorer 6.