Kauri Documentation
Book Index

Kauri Documentation

Table of Contents

1 Documentation Home

1.1 Kauri 0.4 Documentation

Welcome to the Kauri documentation.

Check our documentation service for other releases and off-line/printable (e.g. pdf) Daisy-books.

1.1.1 First Experience

If this is your first visit and contact with the project you probably want to start off with either one of our introduction trails:

1.1.2 The core

After these you should be set to integrate whatever back-end system into your own module to effectively disclose it via your own REST-full interface. For 'classic' RDBMS stuff, you will find some inspiration in the section on  JPA database resources.

1.1.3 Front-end development

Bridging the gap from web-service to web-sites these sections are recommended:

1.1.4 Miscellaneous Modules

A number of typical non-functional requirements in web development get their special attention here:

As well as a practical approach to the issue of dealing with  Temporary Resources in a REST oriented environment.

1.1.5 Deployment and Administration 

Towards deployment the relevant sections are those about:

Revisiting the   configuration section might make sense as well.

1.1.6 Reference Sections

Most of the sections mentioned above have detailed explanations on exact use (included detailed syntax samples) at the end. This list just helps you access those reference sub-sections directly:

1.2 Known Issues

Post release reported issues you should know about:

0.4-RC2

There is a glitch in the pom.xml of the archetypes.  When you are Creating a Kauri project using the archetype you should modify the pom.xml after generation so it shows the correct matching/shipped restlet version:  (ie 6950, not 6565)

<version.restlet>svn6950</version.restlet>

2 Getting started

2.1 Welcome

New to Kauri? Ready to start playing with it?  Then, this section of the documentation is for you.

We recommend reading it completely: just keep following the "Next" link in the browse-section on the right-hand side of this page.  In the process you will be guided through

The idea here is to actively get you going and leave you with a basic setup for your further exploration. 

2.2 Installing Kauri

2.2.1 Installing the Java JDK

If you have Java installed, you can skip this section.

Kauri is Java-based web application framework. To run it you need to install Sun Java version 5 or higher. To check which Java version you have installed, excute:

java -version

To download and install Java, please visit the Java download site.

If you want to develop Kauri applications, be sure to download the JDK, not just the JRE.

Set an environment variable JAVA_HOME pointing to your Java installation. You can again check everything is fine by executing:

Unix
$JAVA_HOME/bin/java -version

Windows
%JAVA_HOME%\bin\java -version

2.2.2 Installing Kauri

First download the Kauri distribution.

Then extract the downloaded zip or tar.gz archive at a location of your choice.

Optionally add the bin directory to the PATH environment variable for convenience.

2.2.3 Next

Try out the samples.

2.3 Running samples

2.3.1 Running the samples

To see Kauri in action, you can try out some of the samples.

The Kauri distribution contains the sources of the samples, so that you can check out their implementation, as well as the compiled samples, so that you can easily run them without installing Maven.

The samples can be found in the samples subdirectory. All samples can be run in the same manner, here is how to run the template samples:

On Windows:

cd kauri-<version>
cd samples
cd kauri-template-sample
..\..\bin\kauri -r ..\..\lib

On Linux:

cd kauri-<version>
cd samples
cd kauri-template-sample
../../bin/kauri.sh -r ../../lib

Surf to http://localhost:8888/ to see the home page of the sample.

At this point you can't run the samples in source mode. Ironically you first need to compile them first, because in source mode, the class files are looked up under target/class instead of in the jar file.

2.3.2 Building the samples

The source code of the samples is included in the binary distribution so that you could look at them and experiment with them.

Before you can build the samples you must set up your development environment.

All samples are built in the same way, e.g. the forms sample:

cd kauri<version>
cd samples
cd kauri-template-sample
mvn install

Now you no longer need the -r flag, and you can run the samples in source mode, like this:

On Windows

..\..\bin\kauri.sh -s module-source-locations.properties

On Linux

../../bin/kauri.sh -s module-source-locations.properties

2.3.3 Next

2.4 Developer environment setup

This section lists the things you need to start developing your own Kauri-based applications.

2.4.1 Installing Maven

You can use the build tool of your choice for your own Kauri-based applications, but using Maven will bring a lot of convenience, so we recommend it. In the Kauri documentation, we only explain how to do things with Maven.

To install Maven (version 2.0.x), please visit: the Maven site.

Maven will self-configure and download lots of components upon first use. This will make your first run exceptionally long.

2.4.2 Installing Kauri artifacts into the local Maven repository.

This step will copy the Maven repository which is included in the binary Kauri distribution to your local Maven repository. This is optional, since Maven can as well download all the needed artifacts on demand, but we recommend it anyway since it will save you time and bandwidth.

Open a Windows command prompt or Unix shell and execute the following command:

[Windows]
c:\path\to\kauri-<version>\bin\kauri-deploy-repo

[Linux]
/home/you/kauri-<version>/bin/kauri-deploy-repo.sh

2.4.3 Next

Create a new project.

2.5 Creating a Kauri project

2.5.1 Introduction

We will show how to quickly set up a new Kauri project from scratch based on a project archetype (also known as a project template or scaffolding or seeding a project).

We assume you have Kauri installed and Maven installed.

2.5.2 Create the project from a template

Open a Windows command prompt or Unix shell and go to a directory where you want to create the project. The script will generate a subdirectory, so it is not required to be an empty directory.

Execute the following commands.

[Windows]
c:\path\to\kauri-<version>\bin\kauri-project-template

[Linux]
/home/you/kauri-<version>/bin/kauri-project-template.sh

For people familiar with Maven archetypes, the kauri-project-template script just launches mvn archetype:generate with a pointer to Kauri's archetype catalog.

The first time kauri-project-template is executed, this might take a little longer since a bunch of jars will be downloaded.

At some point, the script will ask you:

Choose archetype:
1: local -> kauri-archetype-basic (A Kauri project with one module)
2: local -> kauri-archetype-prototyping (A Kauri project with typical setup to start prototyping)
Choose a number:  (1/2): 

Enter either 1 or 2 and enter. If you want a minimal project, choose the basic archetype, if you want more stuff to be put ready for you, choose the prototyping archetype.

After this, you will be asked to confirm the properties:

Confirm properties configuration:
groupId: com.mycompany
artifactId: myapp
version: 1.0-SNAPSHOT
package: com.mycompany
 Y: :

To accept the default values, press enter. To change them, answer no and you will be asked interactively for other values.

By default, a project with the name "myapp" will be created.

2.5.3 Compile it

Compiling is simple and done with the command below. Change the "myapp" to match the artifactId you entered in the previous step ("myapp" was the default).

cd myapp
mvn install

2.5.4 Run it

[Windows]
c:\path\to\kauri-<version>\bin\kauri -c conf -r %HOME%\.m2\repository

[Linux]
/home/you/kauri-<version>/bin/kauri.sh -c conf -r ~/.m2/repository

And then surf to:

http://localhost:8888/

Hint: for the -c and -r arguments, we used the default values, so you can omit them. We included them above so that it would be obvious what input Kauri makes use of to start up.

2.5.5 Develop your project

You can create project files for Eclipse or IDEA using Maven:

mvn idea:idea
mvn eclipse:eclipse

After making changes, rebuild using "mvn install" and then restart Kauri. It is possible to avoid Kauri restarts when the changes don't involve Java code or the basic runtime configuration, see source mode.

2.6 Essential Kauri theory

Kauri consists of a platform, called the Kauri Runtime, on which Kauri-based applications run. A Kauri application consists of one or more modules. A typical Kauri application will consist of at least one module, and will likely re-use a number of standard modules. Examples of standard modules supplied by Kauri are the templating module, the request-routing module and the forms module.

A module is typically packaged as a jar file (a zip file with extension .jar) but can also be loaded from a directory.

A module is started by instantiating its Spring bean container. Each module can have its own classpath configuration, describing what its classpath needs are, and can also push classpath entries onto the parent classloader common to all modules.

Modules don't live on their own, but they talk to each other, in two ways:

A module provides or exports a service and another module depends on or imports that service. Making the connection between the two is called wiring.

For basic Kauri usage, all you need to know is that you can make use of services offered by standard Kauri modules, and that your own code will also be packaged as a module. For more details about everything Runtime-related, see the Runtime documentation.

2.7 Structure of a Kauri project

The project archetype creates a standard structure for Kauri projects, which is in fact a typical Maven project structure.

.
|-- conf
|   `-- kauri
|       |-- wiring.xml
|       `-- connectors.xml
|-- module-source-locations.properties
|-- module1
|   |-- pom.xml
|   `-- src
|       `-- main
|           |-- java
|           |   `-- com
|           |       `-- mycompany
|           |           `-- module1
|           |               `-- HelloWorldResource.java
|           `-- kauri
|               |-- resources
|               |   `-- helloworld.html
|               |-- router.groovy
|               |-- spring
|               |   `-- module1-beans.xml
|               |-- templates
|               |   `-- index.xml
|               |-- representations.groovy
|               `-- router.groovy
`-- pom.xml

The pom.xml files are the Maven 'project object models', Maven's way of describing a project. In the above tree you see there are two pom.xml's, hence there are two projects. One project defines 'module1', and the other project is a parent for this module1 and potential future other modules.

When you compile the project using 'mvn install', a jar file will be built at:

module1/target/module1-1.0-SNAPSHOT.jar

This same jar file will also be deployed in your local Maven repository, at:

{user.home}/.m2/repository/com/mycompany/module1/1.0-SNAPSHOT/module1-1.0-SNAPSHOT.jar

The local Maven repository can be located somewhere else, if configured so in the HOME/.m2/settings.xml file.

The wiring.xml file describes the composition of a Kauri application, it is essential for Kauri to launch. It contains the list of modules that need to be started. In the project created from the archetype, it looks like this:

  <modules>

    <artifact id="routingModule"
              groupId="org.kauriproject"
              artifactId="kauri-routing-impl"/>

    <artifact id="templateModule"
              groupId="org.kauriproject"
              artifactId="kauri-template-service-impl"/>

    <artifact id="module1"
              groupId="com.mycompany"
              artifactId="module1"
              version="1.0-SNAPSHOT">
      <mount name="router" path=""/>
    </artifact>

  </modules>

The modules are referenced by so-called Maven coordinates, this is the triple {groupId, artifactId, version}. As you see, for org.kauriproject modules, the version can be ommitted, it will default to the version of Kauri on which is used.

At runtime, these modules will be loaded from a Maven-style repository. The Maven repository to be used is specified at startup using the -r argument:

{user.home}/bin/kauri -c conf -r {user.home}/.m2/repository

Hint: Kauri uses your local Maven repository by default, so often you can skip the -r argument.

2.8 Source mode

When developing a web application, one will often want to make changes to files and test the effect of those changes in a Web browser. These are typically templates and static resources referenced by them (CSS, images, ...).

When modifying such files, you don't want to go through the "mvn install, restart Kauri" process all the time. Therefore, Kauri supports loading a module straight from its source directory, rather than from a compiled jar deployed in a Maven repository.

It should be noted though that the "mvn install, restart Kauri" process is quite quick. Since Kauri runs your application by loading the modules straight from your local Maven repository, no expensive assembling such as war file creation needs to be done. The Kauri startup time mainly depends on how much time your own components will take to start up.

To use this, you need to create a properties file specifying the location of the source directory for each module you want to load from source.

When using the project archetype, such a properties file will be automatically created for you, called module-source-locations.properties. It contains a line like this:

com.mycompany!module1=${kauri.config.basedir}/module1

The property name follows the syntax groupId!artifactId. In the property value you can refer to the directory containing the wiring.xml file using ${kauri.config.basedir}.

2.8.1 Try it

Starting from a blank project archetype, assuming it is built, start it using the additional -s parameter:

[Windows]
%KAURI_HOME%\bin\kauri -s module-source-locations.properties

[Linux]
$KAURI_HOME/bin/kauri -s module-source-locations.properties

Surf to

http://localhost:8888/resources/helloworld.html

and notice the displayed text.

Now modify the helloworld.html file, which you can find at:

module1/src/main/kauri/resources/helloworld.html

If you refresh in your browser, you should see the results immediately, without doing "mvn install" nor restarting Kauri.

2.9 Static resources

This section assumes you have a blank project created from the project archetype.

The default project as created by the project archetype will automatically make all files below

module1/src/main/kauri/resources/*

available in the URL space at

http://localhost:8888/resources/*

This works because all requests for /resources are routed to a static file server component which reads the files from the corresponding src/main/kauri/resources directory. The routing configuration can be found in the file:

module1/src/main/kauri/router.groovy

which contains a line like:

directory(uri: "/resources", root: "module:/resources/")

The module:/ protocol allows to read the resources in the Kauri module. In the source tree these are the files from src/main/kauri, in the compiled jar these are in the KAURI-INF subdirectory.

You could try adding another routing like this:

directory(uri: "/resources2", root: "module:/resources/")

and verify that you can access:

http://localhost:8888/resources2/helloworld.html

Note: when running in source mode this will work immediately, otherwise you'll have to run "mvn install" and restart Kauri first.

2.10 Dynamic resources

Dynamic resources can be created in several ways. One is using the Restlet API, another one is using the more standard and somewhat higher-level JAX-RS API. In the examples below, we will use JAX-RS.

2.10.1 Examples

2.10.1.1 Hello World

Suppose we want to create a "Hello, world!" resource. A resource is implemented by creating a Java class, which we call a resource class.

Assuming you created a project where the default router configuration and REST-service mounts are present, you can do so by creating a Java class, for example at:

module1/src/main/java/com/mycompany/module1/HelloWorldResource.java

The name and package of the class do not matter, you can take anything you like.

The HelloWorldResource.java can be implemented as follows:

package com.mycompany.module1;

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;

@Path("helloworld")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get() {
        return "<html><body>Hello, world!</body></html>";
    }
}

The JAX-RS API makes extensive use of annotations. By adding the annotation @Path("helloworld"), the resource will be available at this path in the URI space. GET-requests will be handled by the get() method because it has an @GET annotation. The method could have had any other name. There are no interfaces to implement, nor method naming conventions to be followed. Using these annotations, you can easily turn any Java object into a Web resource.

Your module jar will be automatically scanned for classes with JAX-RS annotations, so there is no central configuration to update (see also the notes on router configuration further on).

If you add the above class to your project, build it using "mvn install", and (re)start Kauri, you can access the resource at:

http://localhost:8888/helloworld

2.10.1.2 Personalized hello

Let us make the sample somewhat more interesting, by saying "Hello, {your name}!". For this, we want to address this personalized hello-resource using an URI path like "hello/Steven". The listing below shows how this is done.

package com.mycompany.module1;

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.PathParam;

@Path("hello/{name}")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(@PathParam("name") String name) {
        return "<html><body>Hello," + name + "!</body></html>";
    }
}

To see this in action, recompile the project using "mvn install" and restart Kauri. Then go to:

http://localhost:8888/hello/Steven

The special syntax using the curly braces {} in the @Path annotation follows a specification called URI templates.

2.10.1.3 Hello via a template

Instead of using string concatenation to build the HTML, let us use a template instead.

The resource class becomes:

package com.mycompany.module1;

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.PathParam;

import org.kauriproject.representation.build.KauriRepresentation;

@Path("hello/{name}")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public KauriRepresentation get(@PathParam("name") String name) {
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("name", name);
        return new KauriRepresentation("hello", data);
    }
}

The template file should be defined at:

src/main/kauri/templates/hello.xml

The name of the template corresponds to the first argument of the KauriRepresentation constructor, plus xml extension.

Its content could be as follows:

<?xml version="1.0"?>
<html>
  <body>Hello, ${name}!</body>
</html>

2.10.2 About JAX-RS in Kauri

2.10.2.1 Decentralized URI management, routing

When using JAX-RS, the URI space is built by adding @Path annotations to individual classes. This is a decentralized approach to specifying the URI space: there is no central configuration file listing all the URIs (or URI patterns). By default, Kauri will automatically scan the module jar file for all classes having @Path annotations, and make them available in the URI space. The routing towards these JAX-RS resources is, as for the static resources, configured in:

module1/src/main/kauri/router.groovy

the relevant part is:

    jaxRs(uri: "") {
        jaxRsResource(scanPackages: "*")
        jaxRsProvider(scanPackages: "*")
        jaxRsGroovyScripts(path: "groovy-jax-rs")
    }

See also the jaxRs instruction reference documentation.

2.10.2.2 About the objects returned from resource methods

In the examples above, the get() method returned either a String object or a KauriRepresentation object.

If the return object is String, then the JAX-RS system itself knows how to create the response representation from this.

But the method can in fact return any kind of object, thus also your own "business objects" like Product, Order or User. JAX-RS has a mechanism of pluggable MessageBodyWriters that know how to convert a certain kind of object to a stream of bytes. See the JAX-RS API for more information on this. Registering these writers in Kauri is done through the jaxRs instruction in the routing configuration (router.groovy).

For the template sample, we returned a KauriRepresentation object. This is a special case, as it extends from Restlet's Representation class. The JAX-RS implementation of Restlet treats these in a special way, or better does not treat them at all, it simply passes them through to Restlet.

The KauriRepresentation is a special kind of representation: in fact, it only specifies a logical name for the representation to use (in the example above, "hello"), and based upon a configuration, this logical name is mapped to the actual representation to use. By default, this name is mapped onto a template to execute. See the representation builder for more information on this system.

3 Step by step: Kauri prototyping and application building

3.1 How to use this tutorial

3.1.1 Do as you go

In this step-by-step tutorial you will build a first Kauri application to manage a simple blog of entries and categories. It is by no means a reference guide or complete feature overview.

We do assume you follow the steps in a hands-on fashion: trying things out described in each step as we go along. This approach assumes you have downloaded and installed Kauri properly (see instructions for download and getting started)

3.1.2 Only read

Alternatively you can just read through the concepts and samples to get a first glimpse of what Kauri is about, leaving the hands-on experience for later.

The resulting "tutorial-myblog" project is included as a sample in the distribution.

3.2 Generate the project structure.

3.2.1 Creation of a template application

3.2.1.1 Generation of the project structure

With maven, Java and Kauri installed we can get started by using the maven archetype to create a standard Kauri application project layout.

The binary distribution holds a handy script "kauri-project-template" to trigger this archetype based project generation:

[Windows]
c:\path\to\kauri-<version>\bin\kauri-project-template

[Linux]
/home/you/kauri-<version>/bin/kauri-project-template.sh

in the script you'll have to choose:

Choose archetype:
1: local -> kauri-archetype-basic (A Kauri project with one module)
2: local -> kauri-archetype-prototyping (A Kauri project with typical setup to start prototyping)
Choose a number:  (1/2): 

Pick 2 to create a prototyping application. Then press 'N' to grab the opportunity to modify the defaults into the values suggested below:

Confirm properties configuration:
groupId: com.mycompany
artifactId: myapp
version: 1.0-SNAPSHOT
package: com.mycompany
 Y: : N
Define value for groupId:  com.mycompany: : org.kauriproject.tutorial.myblog
Define value for artifactId:  myapp: : myblog
Define value for version:  1.0-SNAPSHOT: :
Define value for package:  com.mycompany: : org.kauriproject.tutorial.myblog
Confirm properties configuration:
groupId: org.kauriproject.tutorial.myblog
artifactId: myblog
version: 1.0-SNAPSHOT
package: org.kauriproject.tutorial.myblog
 Y: :

Running this command generates a complete project structure. This tutorial will touch upon the relevant elements of that as we go along. A full description is in the Kauri Project Structure.

In the odd event you are running Kauri from your own source-code-checkout, you can call maven directly to create the archetype. The exact howto is explained in Using the archetype

The directory layout for the application will be created in a newly created subdirectory at the "working" directory location. (i.e. your position at the time of running the script.)

3.2.1.2 Compile and startup the application

Once the application is created, we should be able to compile it:

cd ./myblog
mvn install

And also start it up (in prototype mode)

<KAURI_HOME>/kauri run -s module-source-locations.properties -p prototype

Once you've done this, the newly created application is running by default on port 8888. By surfing to http://localhost:8888, you should see this page:

3.2.1.3 Import your application in your development environment

Use eclipse to set some (classpath) variables for your IDE:
Eclipse:

mvn eclipse:eclipse

Idea:

mvn idea:idea

After this, you can import your newly created application in the IDE you use.

3.3 Wire-framing with templates

3.3.1 Drawing a first wire-frame

3.3.1.1 Introduction

The first thing we want to address in this project is the overall behaviour of the web application: "Which pages link to where, what will be on which pages, how end-users will interact."  In web-designer and information-architect circles this work is often tackled through so called wire-frames.  

In Kauri we foster this approach and throw in our

to help speed up the process and to keep these prototyping steps as a basis for future work.  

Indeed rather then throwing these design-time files away, we will extend them during next phases and foresee an active role for them in the actual implementation.

3.3.1.1.1 Templating

During the wire framing phases itself these techniques allow you to benefit from envisioned reuse. An early opinion on visual consistency, slight variants and reuse of graphical elements can be captured in the templating language right away: making the creation of the wireframe snappier and taking considerably more active steps towards further functional development.

3.3.1.1.2 Page naming & auto-routing

Likewise, a nowadays common sensitivity for the URIs (and which parts it is composed off) is easily layed down in the folder and file names picked up by our 'pages' routing-support. 

Both of these are already activated in the generated project. If you haven't started your project yet, do so now

[linux]
$ kauri.sh run -s module-source-location.properties -p prototype 

[windows]
> kauri.bat run -s module-source-location.properties -p prototype

This keeps your project running, and (through the -s option) hooked to the source-files as you edit them: simply refreshing in the browser will show the effects of any changes immediately.

3.3.1.2 Which pages do we want?

And how will they be addressable (and indexed by search engines)?

It really doesn't matter if the sense for "cool URIs" comes from an opportunistic SEO drive or a more fundamental vision or REST awareness.

3.3.1.2.1 User Stories

Being a web-site in the works our 'myblog' project will have the archetypical "home/index"  page serving as an entry point (that was easy).  We want it to show the first x lines/paragraphes of the last 3 entries in the blog, each having a permalink pointer behind the title, and behind a 'read more>>' link.

That should lead to an entry-detail page that shows the full contents of the blog-entry (and some meta-data as author, tags/categories/keywords, publication/creation date-time.  Browsing through these entry-detail pages will be done through previous-next links on the page.

The tags should be listed on the home page, and provide links to overview-pages that will list all entries associated to that tag. The list here will look like the list on the home page.  In fact both (all) lists of entries should be sorted on publication-date (descending) and have some paging ability (ie. be cut off to say length 20, and provide a link to 'older entries')

We foresee (of course) a management interface to add new entries, and control old ones (edit, unpublish, remove).

3.3.1.2.2 URIs

Based on this minimalistic analysis we get the following list of template-pages we need to provide

NAME

@URI_TEMPLATE

=Description

home

@ /
@ /index.html?page.before=YYYY-MM-DDTHH:MM:SSZ&page.size=20

= entry-point, links to tags, older entries and details of listed entry

entry

@ /entry/{pubdate_key}/{title_for_seo}

= detail for specific blog entry, links to previous, next

tag

@ /tag/{name}?page.before=YYYY-MM-DDTHH:MM:SSZ&page.size=20

= list of entries with that tag


admin-list

@ /manage?page.before=YYYY-MM-DDTHH:MM:SSZ&page.size=20

= list of entries with options to remove/edit/unpublish/


entry-form

@ /manage/new
@ /manage/{pubdate-key}

= form to create new or update existing entry

Note the usage of the {name} placeholders in the URI-paths. These indicate the ROLE or semantics of that part of the path.  This notation comes from the uri-templates specification which is used throughout the system to describe how the URI of requests should be matched, interpreted and routed. 

By using these literally (i.e. with the { and } characters in there!) as the names for the folders and files on disk the 'pages' router in Kauri will automatically promote these pathnames-on-disk into active uri-templates.  It will thus match patterns rather then actual literals, and provide the recognized parts to the template logic as ready variables.

So in our case since the uri-template: /entry/{pubdate_key}/{title} will match a family of request-URIs like: /entry/2010-08-04T07:01:00/about-page-routing.  To obtain this we simply provide the following in our project:

[myblog]/src/main/kauri
+-- pages
    +-- entry
       +-- {pubdate_key}         # Yes, your folder name holds the { and } characters
          +-- {title}..xml       # Yes, your file-name holds two periods.

About the double-period notation: the contract is this: the second extension is removed from the actual uri-template. This trick allows to provide an extension to your file that makes it recognizable to your development tools (an xml template file to be opened in your xml editor) without having it ripple through in the URI-scheme. Check out the pages router for a full description of how file-system paths are translated into uri-templates.  The double-period ..xml thus indicates that the path will have no extension.

In the {title}..xml template we will be able to use the matched names as variables. So for the sample request URI we mentioned above we will get something like:

variable

value

pubdate_key

'2010-08-04T07:01:00'

title

'about-page-routing'

3.3.1.2.3 Benefits

Recognizing these 'uri-templates' upfront reduces the work to be done: Only single template-pages need to be developed, not a set of individual individual (copy-pasted and then ill-synced) sample instance pages

More benefit to this approach is in the fields documentation and project-management:  Marking {roles} in the paths/names of these templates communicates in a natural way (ie. built-into the project source code) more of the design-time insight to the further development process.

3.3.1.3 What is on these Templates?

So, we are ready to lay out the 'paths' and create the distinct templates, but not without some more consideration for elegance and efficiency to actually fill them up.

The previous section described how recognized templates can be captured using the built-in uri-templating: a simple mechanism to catch all same-looking pages into one {role}-named template. The next analysis effort is in recognizing the recurring zones, bits and pieces in these templates.

Like in the previous section, this will result in

Looking at our my-blog sample we see the different pages should have a lot in common.  The diagram below graphically represents the important relations between these templates:

To capture this Kauri's templating language naturally provides the t:inherit (reusable general layouts) and t:insert (reusable snippets) statements.

See the reference, starting of at the basic rules for all syntax details of the template language.

3.3.1.4 Do It Yourself

With the above thinking done, we can fully list the template files we need to create:  (we shortened some names for convenience)

main-module/src/main/kauri/
|-- pages
|   |-- entry
|   |   `-- {key}
|   |       `-- {title}..xml
|   |-- index.html.xml
|   |-- manage
|   |   `-- {key}..xml
|   |-- manage..xml
|   `-- tag
|       `-- {tag}..xml
`-- templates
    |-- layout
    |   |-- footer.xml
    |   |-- header.xml
    |   `-- layout.xml
    `-- snippet
        `-- entry-list.xml

We separate the 'pages' from the 'templates'.  The pages are the ones that are end-user-facing. They get a URI assigned to them which makes them publicly accessible. 
Even if those too just use the template language, we keep them separate from the strictly internal templates that help out managing the reusable layout and recurring snippets.

Don't delete or change any of the generated files yet. 
Just create the missing ones, and fill those with some basic XML that makes them avoid errors:

<?xml version="1.0"?>
<html xmlns:t="http://kauriproject.org/template">
  TODO 
  -- 
  preferably enhanced with some idea of what this particular page should show
</html>

As we go along these files will be further enhanced and more details of templating and routing will be touched upon.  For now we'll just show the basic principles that make up the essence of the wire-framing job:

  1. Learn how the layout inheritance works (and introducing header and footer)
  2. Learn how template inclusion works
  3. Putting down the links between the various pages.
  4. Show how the matched part of uri-templates is made available in the templating.
3.3.1.4.1 Inherit and extend a common layout

This first part is really easy because it is already in use by the generated templates:  pages/index.html.xml declares an inheritance on templates/layout/layout.xml. It does so in the first line:

<html t:inherit="module:/templates/layout/layout.xml" xmlns:t="http://kauriproject.org/template">

This layout.xml template declares the general layout structure and leaves room for so called 'blocks' that can be overridden in the templates that inherit from this template.  These just provide blocks with matching names that will replace the ones from the parent.
You can see how the layout.xml declares the blocks named title and content. And how the matching blocks in the index.html.xml page actually replace those.

To satisfy the various <<inherit>> relations in the diagram above we just apply the same layout to all the actual end-user-facing pages. This is what you do:

  1. add the above inheritance declaration (t:inherit="module:/templates/layout/layout.xml") to the root element of all the templates in the pages directory (not to the ones in templates)
  2. then move the earlier TODO text into a <t:block name="content"> ... </t.block>

Don't worry too much about the path starting with the pseudo-protocol:  module:/ for pointing to the layout-master-template.  It is explained in our section about uri-resolving.
For now it suffices to know that these absolute references a reresolved against the root of the kauri-resources of your module. (in your module source files that means, relative to [module]/src/main/kauri)

You can simply use relative paths as well for the t:inherit attribute. But depending on their position the reference to template/layout/layout.xml would need to be prefixed with one or more ../
In this case the 'absolute' version is more appropriate.

As a sample, here is how pages/entry/{key}/{title}..xml should look for now:

<?xml version="1.0"?>
<html t:inherit="module:/templates/layout/layout.xml" xmlns:t="http://kauriproject.org/template">
  
  <t:init>
    <t:variable name="page_title"  value="TODO: should become the title of the entry"/>
  </t:init>
  
  <t:block name="title">${page_title}</t:block>

  <t:block name="content">
    <h1>${page_title}</h1>
    TODO entry detail page
  </t:block>
</html>

Notice how we also override the title block and how the ${...} syntax is used as a placeholder for expression evaluation during template execution. This allows to define the page_title once and inject its value 

More details about inheriting templates (like why use <t:init>) is in the Template inheritance section.

3.3.1.4.2 Include re-useable template-snippets

Next we realize the <<includes>> relations from the diagram above.  Just drop in a <t:include> with appropriate src attribute: i.e. pointing to the template-file you want to include.

For the layout.xml page we push out the header/footer sections to different XML files.

<?xml version="1.0"?>
<html xmlns:t="http://kauriproject.org/template">

  <head>
    <title><t:block name="title">[title]</t:block></title>
    <link rel="stylesheet" type="text/css" href="${publicUri('service:/main/static/css/main.css')}"/>
    <script type="text/javascript" src="${publicUri('service:/main/static/js/basic.js')}"/>
    
    <t:block name="extraHeaders"/>
  </head>

  <body>
    <t:block name="header"><t:include src="header.xml" /></t:block>

    <t:block name="content"/>

    <t:block name="footer"><t:include src="footer.xml" /></t:block>

  </body>
</html>

Being a master-layout page it is wise to wrap the include statements into separate blocks so inheriting pages can choose to override in any way.

A similar include should be used for reusing the list of entries on the index, tag-overview and management pages. On those pages you can just leave a:

    <t:include src="/templates/snippet/entry-list.xml" />

somewhere in the content-block (i.e. <t:block name="content">)
The snippet-file itself can then look like this for now:

<?xml version="1.0"?>
<div xmlns:t="http://kauriproject.org/template">

  <!-- we will need to think about injecting title and data for this list to produce -->

  <h2>TODO injected title</h2>
  
  <ul class="entry-list" >
    <t:variable name="permalink" value="${publicUri('service:/main/entry/some-key/some-title')}" />
    <li>
      <a href="${permalink}" >TODO some-entry-title</a><br />
      TODO some entry summary<br />
      <a href="${permalink}" >read more >></a>
    </li>
  </ul>

</div>

You should see this dummy list now included on the various pages where you added the <t:include> directive.

3.3.1.4.3 Linking your pages in a module-reuse-world

Marked in the above sample we introduce an unfamiliar way to link up the pages in your design. 

${publicUri('service:/main/entry/some-key/some-title')}

What is going on? Well two things in fact.

The first observation is that we can't simply use relative links in this entry-list page.  Since it will be embedded inside different pages we cannot be sure that the base path of those will always be the same, and thus that we can pin down the correct relative path towards the detail pages.  In our example the usage inside the manage..xml template would suggest a relative permalink to "entry/**" while the inclusion in tag/{tag}..xml would need "../entry/**" to work properly.

By switching to an absolute reference "/entry/**" we can easily service both usage scenario's. Only we can't be sure about / being the actual public URI that points to the root of the service we are building. Therefor we ask the framework (who does now about this configuration aspect at run-time) explicitly to translate our URI into a public reference with the publicUri function.

People familiar with other component based web app frameworks should not be too surprised about this.

The actual mount-point for the various public services in your module is covered in the  wiring.xml file. This got generated in the first step, and is at [myblog-root]/conf/kauri/wiring.xml.  
Which services your module is providing is declared in the spring-bean xml files inside src/main/kauri/spring/** using the export-restservice tag described in the  Spring config reference

In short: you can ignore this publicUri() technique only:

"Being sure" about these aspects translates into documenting it and describing it as known limitations of your template and/or module.

So back to work: With this understanding you should be able to put down the various <<linksTo>> relations foreseen in the analysis diagram.

3.3.1.4.4 Grab the matched part of a uri-template

Finally we are ready to abuse the dynamic parts introduced by the uri-template technique.  By creating the template at pages/tag/{tag}..xml we are sure to match any /tag/my-topic. Now here is how we can use the actual matched {tag} in our template:

<?xml version="1.0"?>
<html t:inherit="/templates/layout/layout.xml" xmlns:t="http://kauriproject.org/template">

  <t:init>
    <t:variable name="tag" value="${request.attributes.tag}"/> 
    <t:variable name="page_title" value="Entries for topic ${tag}"/>
  </t:init>
  
  <t:block name="title">$page_title</t:block>
  <t:block name="content">
    <h1>${page_title}</h1>
    
    <t:include src="/templates/snippet/entry-list.xml" />
    
  </t:block>
</html>

The internal routing and matching will make the matched {tag} part from the uri-template available as a request-attribute with the matching name.

3.3.1.5 Conclusion

Kauri offers more then the simple-read-static-files support from your average file-system or bare bones web-server. By using the built-in pages-router and the template language the initial design phases of new projects (the so called wire-framing) can both 

The resulting work shows more visible traces of recognized recurring visual elements and uri-patterns.

Since all of this runs in 'source' mode no project builds or service restarts are required.  The typical fast round-trip of the designer-cycle template-save-and-test-in-browser is maintained.

Finally the wire-framing work doesn't need to be thrown away and redone in a more dynamic language. The same files can be extended and kept live (and thus up to date) as development continues.  This is especially important in environments where development of one part is in parallel with the analysis and design work on new sections and modules.

3.4 Prototype a data-service with JSON

3.4.1 Introduction

Up to now we've been using Kauri to build up the pages that will make up the 'web-site' part of our application. The application interface for the end-user interactions.

Our ambition however is to build a 'web-service' as well. Targeted for machine-machine consumption, this will deliver controlled access to the unformatted data structures (representations in json or XML format).

Still in prototyping mode, Kauri offers a simple mechanism to sketch the messages to be exchanged in these RESTful data-services.  Rather then stepping directly into entity-relation modeling or development of the database back-end we will just draft out some json structures in simple text files.  These function as 'sample' data for simulating the actual persistence features of the eventual production web-service our application needs.  This makes it possible to further enhance our wire-frame-templates making them really data-aware and dynamic: suitable for actual deploy time use.

Even better: this way of working helps define the URI space and the expected exchange messages to and from the persistent service.

We will use this prototyping mode to create blog posts (entries).  On top of this mock service (driven by our json samples) we will complete our templates and interactive pages. Later, we will explain how in production mode, the actual persistence service can be build, and swapped in.

3.4.1.1 Location of the JSON mockup data

The JSON files should be put in the /mockdata directory of the Kauri folder. By using the maven archetype for creation of our application, there is allready a /persons directory present with an example json file 1.json.

Change that into something that better fits our needs:

-- myblog
 |-- conf
 |-- main-module
      |-- src
          |-- main
               |-- kauri
                    |-- mockdata 
                          |-- entry
                               |-- 2010-08-24T14:46:32.json
                               |-- 2010-06-30T12:13:00.json

3.4.1.2 Creation of the JSON data

As hinted above we will create two sample files representing some simple blog posts.  The flexibility of the json notation allows us to easily provide additional fields to these samples as we go along.  For starters we should provide (title, content, summary, key/creation-date)

The names of the files will be used as identifiers for the entities. 

Suggested sample:

{
    "title": "Lily sees the light ... almost!",
    "summary": "This should just grab something like the first 100 characters from the content by default."
    "content": "<p>This is <b>the second day</b> of the very well organized .... (a lot more text)"
}
{
    "title": "A NoSQL Summer: Belgium/Ghent edition",
    "summary": "<p>A NOSQL Summer is a network of local reading groups, that will decipher and discuss 
    "content": "<p>A NOSQL Summer is a network of local reading groups, that will decipher and discuss .... more more more"
}

3.4.1.3 Checking the service

At this point you should restart your running Kauri-instance to let it pick up these new sample files.
To check whether you've put the files at the right place and if the router's configured correctly (this should be the case if you've created your template application with the Maven archetype), try surfing to the following URIs

http://localhost:8888/data/entry/
http://localhost:8888/data/entry/2010-08-24T14:46:32  

The response should contain the contents of the corresponding json files.

You can check what the server actually responded (like HTTP headers and stuff) with a tool like Firebug or the development tools of Chrome.

Finally you can also create new content into this service through standard PUT operations.  To do this from your browser you'll typically need some add-on like the excellent "Poster add-on" for firefox or its "Google Poster" counterpart for Chrome.

You can create or update the entities in the simulated persistence service.

Check out the images for some samples to try out:

3.5 Pulling and displaying data

Pulling data

Now that we have created the data, we can pull it and display it in the pages. The complete URI to pull a certain blog item is: http://localhost:8888/data/items/1. To get all items it is: http://localhost:8888/data/items.

Getting mock data resources

Let's first focus on the bask part of the url, which is of structure (* = 0 or more occurences, ? = 0 or 1 occurence):

/entityname(/id/propertyname)*(/id)?
Example

/items/1 will return the entity with ID 1 (i.e. entity in file mockdata/items/1.json)

/items/ will return a JSON array containing all 'items' entities  (i.e. all entities in directory  mockdata/items/)

There are lot more possibilities with these structures, check the DB resources pages in our manual if you want to know more about it.

The URI explained

The complete URI to get item with ID 1 is http://localhost:8888/data/items/1. Notice the /data part which prefixes the entity name (items) and ID (1). Where does that come from?

On the one hand, there's the mounting of services which happens in wiring.xml:

    <artifact id="module1" groupId="org.kauriproject" artifactId="module1" version="1.0-SNAPSHOT">
      <mount name="data" path="/data"/>
    </artifact> 

This mounts the data service on URI path /data. More about wiring is to be found in this section.

On the other hand, there's the spring configuration of services in services.xml. In the structure of your blog application, you'll however find 3 services.xml files. The common one will allways be used, whatever mode you are using. The one in directory /prototype will be used in case of prototyping mode  (like we are at this moment). The other one will be used when switching to production mode. The difference between the 2 is what we are using as data service. In prototyping mode we want to use our mockup (JSON) data, and not a database. That is what's defined in prototyping/services.xml:

  <bean id="data" class="org.kauriproject.dbresources.mock.DbMockFinder">
    <constructor-arg ref="restletContext"/>
    <constructor-arg ref="module"/>
    <constructor-arg value="mockdata"/>
  </bean>

When we will startup Kauri in production mode, the production/services.xml is used, and another data service is loaded.

Structure of our pages folder and naming of the pages

In our router we can find some configuration that routes everything not explicitly configured elsewhere in the router, is routed via pages.

    mode(uri: "", when: "all,-prototype") {
        pages(root: "pages")
    }

So if we'd like an URI layout

we can realize this by structuring our pages folder as follows:

-- myblog
 |-- conf
 |-- module1
      |-- src
          |-- main
               |-- kauri
                    |-- pages 
                         |-- items
                              |-- {id}.html.xml
                              |-- all.html.xml

Because of the configuration of the router, the file paths are usable as URI templates. Beacuse of  this, we can use request attributes as variables in the filenames. This explains the filename {id}.html.xml. So if we browse to url /1.html we will we routed to the page {id}.html.xml and the '1' will be used as the value for request parameter ID.

By using the pages router, each .html you browse to, will be routed to the corresponding .html.xml file on your filesystem. This is because the page templates are in fact xml files, and not html files.

How to insert data in your pages

Create a page to display one blog item: /pages/{id}.html.xml

We will use Kauri Template language to display our data in the pages. Read this section in the manual if you'd like more detail.

We'll create a page to display the content of one blog item, this is the page template situated at /pages/{id}.html.xml.

Tha blog item we need is pulled by using t:variable with the correct src attribute, in which we use {request.attributes.id} to get the request attribute ID:

<t:variable name="item" src="service:/data/items/${request.attributes.id}" overwrite="false" accept="application/json"/>

When doing this the blog item is available as a variable with name 'item':

<?xml version="1.0"?>
<html t:inherit="module:/templates/layout.xml"
      xmlns:t="http://kauriproject.org/template">

  <t:init>
    <t:variable name="item" src="service:/data/items/${request.attributes.id}" overwrite="false" accept="application/json"/>
  </t:init>

  <t:block name="title">${item.title}</t:block>

  <t:block name="content">
    <h2>${item.title}</h2>
    <h3>${item.date}</h3>

    <p>${item.content}</p>

  </t:block>

</html>

Test this by browsing to following URL: http://localhost:8888/items/1. You should see this page:

Remark that the we can display the item but our content which contains HTML is escaped. We want this variable to be displayed as html, so we have to use the t:insert instruction for that one:

<p><t:insert value="${item.content}" mode="xml"/></p>
Create a page to display all blog items: /pages/all.html.xml

To display all blog items:

  1. use the service:/data/items uri to pull all blog items
  2. use the t:forEach to iterate the array of items
<?xml version="1.0"?>
<html t:inherit="module:/templates/layout.xml"
      xmlns:t="http://kauriproject.org/template">

  <t:init>
    <!-- In prototype mode, the template is executed directly, and pulls in
         the data it needs itself. In production mode, the data will be
         supplied from the resource class (PersonResource).
         -->
    <t:variable name="items" src="service:/data/items" overwrite="false" accept="application/json"/>
  </t:init>

  <t:block name="title">Blog items</t:block>

  <t:block name="content">

	<t:forEach var="item" in="${items}">
	    <h2>${item.title}</h2>
	    <h3>${item.date}</h3>
	
	    <p><t:insert value="${item.content}" mode="xml"/></p>

	    <hr/>
	</t:forEach>


  </t:block>

</html>

After doing this, browsing to url http://localhost:8888/items/all.html gives us a list of all blog items available in our JSON files:

If you make changes to the JSON files in the data directory of your application, you won't see those changes immediately in your browser. That is because a copy of that directory is made at startup of the application, and that one is used. When you restart the application, the data folder wil be copied.

3.6 Adding data via a form

Enable the use of forms in your application

Because we used the archetype to create our application the following is present in wiring.xml:

    <artifact id="forms" groupId="org.kauriproject" artifactId="kauri-forms-framework" >
      <mount name="main" path="/kauri/forms"/>
      <inject-restservice name="jquery" ref="jquery:main"/>
      <inject-restservice name="upload" ref="tmprsrc:upload"/>
    </artifact>

    <artifact id="module1" groupId="org.kauriproject" artifactId="module1" version="1.0-SNAPSHOT">
      <inject-restservice name="forms" ref="forms:main"/>
      <inject-restservice name="jquery" ref="jquery:main"/>

      <mount name="main" path=""/>
      <mount name="data" path="/data"/>
    </artifact>

This makes the forms module services are ready for use in our module1.

Each page which is using the Kauri forms needs some scripts includes. This (and other stuff) is done by letting our template inherit from layout.xml:

<html t:inherit="module:/templates/layout.xml" xmlns:t="http://kauriproject.org/template">

This layout.xml includes headerlinks.xml, which includes all necessary scripts:

    <t:include src="service:/forms/templates/snippet/headerlinks.xml"/>

At this time, just remember to let your template inherit from the layout.xml

Make a form to edit an existing blog item

We'll start with making a page to enables us to edit an existing blog item.  Therefore, we again need a uri with template : {id}-edit.html.xml. This makes it possible to call urls /items/1-edit.html, /items/2-edit.html etc.

In the Kauri forms framework, everything is configured in Javascript, via what we call a 'form configuration object'. If wanted, you can choose to write no HTML at all and let the HTML be generated for your. That is what we will do.

You just define the members of your form, what types are coupled to these members, and what sort of control you want to use for this member. What do we want to edit a blog item:

There is no Kauri wysiwyg editor available for plugin at this moment. That's why we use a textarea control at first. In the next step we'll show how to plugin a html editor as a module.

Make a form to add a new blog item

We won't write any HTML ourselves, but just define an empty form with a specified ID:

     <form id="item-form">
     
     </form>

To create our form, we start with the form configuration:

        var fconf = {
          "createURI": "${publicUri('service:/data/items/')}",
        
          type: {
            members: {
              'id' : {
                'base' : 'integer',
                'control' : {
                  'initial' : {
                    'enable' : false
                  }
                }
              },
              'title': 'string',
     
              'content': {
                'base': 'string',
                'control' : 'textarea-control'
               },
               'date' : 'date'
            }
          }
        }; / *end fconf */

Next we create the form with as arguments

  1. the ID of the associated form 
  2. the fconf

/* create form */

        var itemForm = new jQuery.org.kauriproject.forms.Form("item-form", fconf);

Prefilling the form with data

Because we want to edit a blog item in this form, we do want the form to be prefilled with the data. Therefore we pull the data we need (remember the {id} in the URL template, which contains the ID of the blog item we are editing):

<t:variable name="item" src="service:/data/items/${request.attributes.id}" overwrite="false" accept="application/json"/>

This variable can be used to prefill the form via the setWireValue method.

        itemForm.setWireValue(${item});

FInally, we tell the form not to create (but only edit) data and what to do if the form has been submitted:

        itemForm.setCreateMode(false);
        itemForm.submitSuccess = function (data, success) {
            window.location = "${publicUri('service:/main/items/all.html')}";
        };

Result

If you now browse to http://localhost:8888/1-edit.html, you should see an edit page prefilled with the data of blog item 1:

Adding new data via the same template

We will now create a form to add a new blog item. This is quit similar to what we did above so we will reuse the same page template.  The URI template for that page was {id}-edit.html. We can specify whether we are creating or updating by defining this id as new in case of creating, so for creating a new blog item we use URI /items/new-edit.html.

All there is to it, is now checking via the template language if the request id equals 'new', and then switching to creation mode. Our result page should then be, remark the bold lines:

<?xml version="1.0"?>
<html t:inherit="module:/templates/layout.xml"
      xmlns:t="http://kauriproject.org/template">

  <t:init>
    <t:variable name="id" value="${request.attributes.id}" />
    <t:if test="${id != 'new'}">
      <t:variable name="item" src="service:/data/items/${id}" overwrite="false" accept="application/json"/>
    </t:if>
  </t:init>

  <t:block name="title">${item.title}</t:block>

  <t:block name="extraHeaders">
      <t:superBlock/>

      <script type="text/javascript">
      jQuery(document).ready(function() {
      
        var fconf = {
          "createURI": "${publicUri('service:/data/items/')}",
        
          type: {
            members: {
              'id' : {
                'base' : 'integer',
                'control' : {
                  'initial' : {
                    'enable' : false
                  }
                }
              },
              'title': 'string',
     
              'content': {
                'base': 'string',
                'control' : 'textarea-control'
               },
               'date' : 'date'
            }
          }
        }; / *end fconf */

        /* create form */
        var itemForm = new jQuery.org.kauriproject.forms.Form("item-form", fconf);


        itemForm.setCreateMode(${id == 'new'});
        itemForm.setWireValue(${item});
        
        itemForm.submitSuccess = function (data, success) {
            window.location = "${publicUri('service:/main/items/all.html')}";
        };
      });
    </script>

  </t:block>

  <t:block name="content">
     <form id="item-form">
     
     </form>
  </t:block>

</html>

3.7 Creating a module to add a HTML editor

We have created a form to add some blog items. It is of course not very user friendly to let users input HTML via a simple textarea. For that, we will use an existing HTML editor. We choose for TinyMCE here, because it has a jQuery plugin and is simple to plugin. We will create this as a separate module in our application and in this section, we'll show how to do that.

Creating the module structure

When creating our application by using the archetype, we have already added one module as default 'module1'. Beside this folder, we'll create a new module 'tinymce' with this folder structure:

-- myblog
   |-- pom.xml
   |-- conf
       |-- wiring.xml
   |-- module1
   |      ...
   |-- tinymce
       |-- src
       |   |-- main
       |       |-- kauri
       |       |   |-- spring
       |       |       |-- services.xml
       |       |-- tiny_mce
       |       |   |-- jquery.tinymce.js
       |       |   |-- tiny_mce.js
       |       |   |-- .... rest of tinyMCE code 
       |       |-- router.groovy
       |-- pom.xml

Configure the tinymce module

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0,http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.kauriproject</groupId>
    <artifactId>myblog</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../..</relativePath>
  </parent>

  <artifactId>kauri-tinymce</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>MYBLOG ::: TINYMCE</name>

  <build>
  </build>
</project>
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:kauri="http://kauriproject.org/runtime/1.0#springext"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context-2.5.xsd
                    http://kauriproject.org/runtime/1.0#springext
                    http://www.kauriproject.org/schemas/runtime/springext.xsd">

  <context:annotation-config />

  <kauri:module restletContext="context" classLoader="classloader" handle="module"/>

  <kauri:import-service id="routing" service="org.kauriproject.routing.RoutingService"/>

  <kauri:export-restservice ref="main"/>

  <bean id="main" factory-bean="routing" factory-method="createRouter">
    <constructor-arg ref="context"/>
    <constructor-arg ref="module"/>
  </bean>

</beans>
builder.router {

    directory(
            uri: "/",
            listingAllowed: true,
            root: "module:/tiny_mce/"
            
    )
}

Wire it in the myblog application

To wire the new module inside the blog application, we add the tinymce artifact to the wiring.xml and mount the rest service on the correct path:

    <artifact id="tinymce" groupId="org.kauriproject" artifactId="kauri-tinymce" version="1.0-SNAPSHOT">
      <inject-restservice name="jquery" ref="jquery:main"/>

      <mount name="main" path="/tinymce"/>
    </artifact>

Because the other artifact 'module1' depends on this one, make sure to define 'tinymce' before 'module1'

In the root pom.xml, add the module:

  <modules>
    <module>module1</module>
    <module>tinymce</module>
  </modules>

Use it in the form

TinyMCE is now available via the service protocol, so we can load the tiny mce jquery script via this URI:

    <script type="text/javascript" src="${publicUri('service:/tinymce/jquery.tinymce.js')}"></script>

When the script is loaded we can call tinymce on the textarea of the form:

        $('form textarea').tinymce({
          script_url : '${publicUri('service:/tinymce/tiny_mce.js')}',
          theme : "simple"
        });

Note that this will call tinymce for all textarea controls in your form. If you use this elsewhere, be more specific in the jQuery selector

To make sure the tinymce module copies its content to the textarea before submission of the form, we have to call the triggerSave method.

        itemForm.prevalidation( function () {
           tinyMCE.triggerSave(true, true);
           $('form textarea').change();
        });

Result

Page template {id}-edit.html now looks like this:

<?xml version="1.0"?>
<html t:inherit="module:/templates/layout.xml"
      xmlns:t="http://kauriproject.org/template">

  <t:init>
    <t:variable name="id" value="${request.attributes.id}" />
    <t:if test="${id != 'new'}">
      <t:variable name="item" src="service:/data/items/${id}" overwrite="false" accept="application/json"/>
    </t:if>
  </t:init>

  <t:block name="title">${item.title}</t:block>

  <t:block name="extraHeaders">
      <t:superBlock/>

      <script type="text/javascript" src="${publicUri('service:/tinymce/jquery.tinymce.js')}"></script>
   
      <script type="text/javascript">
      jQuery(document).ready(function() {
      
        var fconf = {
          "createURI": "${publicUri('service:/data/items/')}",
        
          type: {
            members: {
              'id' : {
                'base' : 'integer',
                'control' : {
                  'initial' : {
                    'enable' : false
                  }
                }
              },
              'title': 'string',
     
              'content': {
                'base': 'string',
                'control' : 'textarea-control'
               },
               'date' : 'date'
            }
          }
        }; / *end fconf */

        /* create form */
        if(${id == 'new'})
            fconf.createURI = "${publicUri('service:/data/items/')}";   
        else
            fconf.dataURI = "${publicUri('service:/data/items/')}${id}";
        var itemForm = new jQuery.org.kauriproject.forms.Form("item-form", fconf);


        itemForm.setCreateMode(${id == 'new'});
        if(${id != 'new'})
            itemForm.setWireValue(${item});
        
        
        $('form textarea').tinymce({
          script_url : '${publicUri('service:/tinymce/tiny_mce.js')}',
          theme : "simple",
        });



        itemForm.prevalidation( function () {
           tinyMCE.triggerSave(true, true);
           $('form textarea').change();
        });

     
        itemForm.submitSuccess = function (data, success) {
            window.location = "${publicUri('service:/main/items/all.html')}";
        };       

      });
    </script>

  </t:block>

  <t:block name="content">
     <form id="item-form">
     
     </form>
  </t:block>

</html>

Which results in:

You'll see at this point a date parse error when you load one of your entities, in the validation section we'll show how to solve this

3.8 Adding form validation and formatters

Add date formatting

In this section, we'll add some validation to our form. But for starters, we'll make sure to get rid of the date parse error. In the backend, we want to store the date in this (iso8601) format: yyyy-MM-dd. But maybe we want to show these dates in a different format in the browser (dd/MM/yyyy). We call this respectively the wire-format and user-format. We can specify a format for each one of them via the fconf. Let's show this via an example:

'publicationdate' : {
    'base' : 'date',
    'wire-format': {
        'base': 'wire-date',
        'pattern': 'yy-mm-dd'
    },
    'user-format': {
         'base': 'wire-date',
         'pattern': 'dd/mm/yy'
    }
}

the patterns used here are the ones used by jQuery date parser, documentation can be found here. By extending wire-date with the desired pattern for wire-format and user-format, we can use a different format for backend and userside.

Add validation

In this stage, we'll add some validation to our form. We'll make all of the fields except the publication date and URL, required. The e-mail field should of course contain an e-mail, and the URL a valid URL. And as last we'll check if the publication date is a future date.

Client validation

We'll mark following fields as required:

For this, we'll need to extend the fields. Our fconf for the title field still looks like this:

'title': 'string'

To extend this, you need to understand that this is in fact a shorthand for this:

'title': { 
    'base': 'string'
}

And from this, we can extend our field with validators. We add validators by specifying +validators:

'title': {
    'base': 'string',
    '+validators': { 'required': {} }
}

All types of available validators can be found in the forms reference. We need the 'required', 'isEmail' and 'isUrl' here, which results in:

        var fconf = {
          "createURI": "${publicUri('service:/data/items/')}",
          "dataURI": "${publicUri('service:/data/items/')}${id}",
        
          type: {
            members: {
              'id' : {
                'base' : 'decimal',
                'control' : {
                  'initial' : {
                    'enable' : false
                  }
                }
              },
              'title': {
                  'base': 'string',
                  '+validators': {
                      'required': {} 
                   }
              },
              'author': {
                  'base': 'string',
                  '+validators': { 
                      'required': {} ,
                      'isEmail': {}
                   },
                   'label': 'Author (e-mail)'
              },
              'url': {
                  'base': 'string',
                  '+validators': { 
                      'isUrl': {}
                   },
                   'label': 'Author (URL)'
              },
              'content': {
                'base': 'string',
                '+validators': {
                    'required': {} 
                },
                'control' : 'textarea-control'
               },
               'publicationdate' : {
                 'base' : 'date',
                 'wire-format': {
                   'base': 'wire-date',
                   'pattern': 'yy-mm-dd'
                 },
                 'user-format': {
                   'base': 'wire-date',
                   'pattern': 'dd/mm/yy'
                 }
                 
               }
            }
          }
        };
Remote validation

We'll add one last validation to the form: checking if the publication date is a future date. This is  not a standard validation, and we'll do this by using our own remote validator. Herefore we have to define a validation resource class:

/*
 * Copyright 2008 Outerthought bvba and Schaubroeck nv
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.kauriproject.myblog.validation;

import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;

public class FutureDateValidationResource extends ValidationResource {

    private final DateTimeFormatter iso8601 = ISODateTimeFormat.dateTimeParser();
    
    public FutureDateValidationResource() {
        super();
    }

    public FutureDateValidationResource(Context context, Request request, Response response) {
        super(context, request, response);
    }

    @Override
    protected Result validate(String value) {
        //JSONObject input = JSONObject.fromObject(value);
        
        if (value != null && !value.equals("")) {
            DateMidnight now = new DateMidnight();
            DateMidnight date = parseDate(value);
            
            if (date == null) {
                return new Result(false, "Date could not be parsed.");
            } else if (now.compareTo(date) > 0) {
                return new Result(false, "Date is not in future !");
            } 
        }
        
        return Result.OK;
    }
    
    private DateMidnight parseDate(String value) {
        if (value.charAt(0) == '"' && value.charAt(value.length()-1) == '"')
            value = value.substring(1, value.length()-1);
        DateTime date = iso8601.parseDateTime(value);
        return date.toDateMidnight();
    }
}

That extends a validation resource:

package org.kauriproject.myblog.validation;

import java.io.IOException;

import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.representation.Variant;
import org.restlet.resource.Resource;
import org.restlet.resource.ResourceException;

public class ValidationResource extends Resource {

    private Result validationResult;
    
    static class Result {
        static final Result OK = new Result(true);
        
        boolean valid = true;
        String msg;
        
        Result() {
            this(true);
        }
        Result(boolean valid) {
            this(valid, null);
        }
        Result(boolean valid, String msg) {
            this.valid = valid;
            this.msg = msg;
        }
        String toJSON() {
            if (valid) return "{\"valid\": true}";
            else if (msg == null) return "{\"valid\": false}";
            else return "{\"valid\": false, \"message\":\""+ msg +"\"}";
        }
    }
    
    public ValidationResource() {
        super();
    }

    public ValidationResource(Context context, Request request, Response response) {
        super(context, request, response);
    }

    @Override
    public void init(Context context, Request request, Response response) {
        super.init(context, request, response);
        setModifiable(false);
        setReadable(false);
        getVariants().add(new Variant(MediaType.APPLICATION_JSON));
        this.validationResult = null;
    }

    @Override
    public boolean allowPost() {
        return true;
    }
    
    @Override
    public void acceptRepresentation(Representation entity) throws ResourceException {
        try {
            final MediaType mediaType = entity.getMediaType();
            if (mediaType != null && mediaType.equals(MediaType.APPLICATION_JSON, true)) {
                String value = entity.getText();
                this.validationResult = validate(value);
                final Response response = getResponse();
                response.setEntity(represent());
                response.setStatus(Status.SUCCESS_OK);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new ResourceException(e);
        }
    }
    
    @Override
    public Representation represent(Variant variant) throws ResourceException {
        return new StringRepresentation(this.validationResult.toJSON(), MediaType.APPLICATION_JSON);
    }
    
    protected Result validate(String  value) {
        return new Result();
    }
}

This FutureDateValidation class is a duplicate from the one in the forms sample, used on the date-control page.

Because the validator needs the joda-time library to parse and format the dates, we have to include the dependency in the pom.xml of our myblog module:

    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>1.6</version>      
    </dependency>

Remember to build your project after adding this code: mvn install

Once this done, just add this resource to your router.groovy:

    resource(uri: "/futuredate",
        ofClass: "org.kauriproject.myblog.validation.FutureDateValidationResource");

And use the remote validator in the fconf:

'publicationdate' : {
    'base' : 'date',
    'wire-format': {
        'base': 'wire-date',
        'pattern': 'yy-mm-dd'
    },
    'user-format': {
        'base': 'wire-date',
        'pattern': 'dd/mm/yy'
    },
    '+validators' : {
        'remote' : { location: "${publicUri('service:/main/futuredate')}" }
    }
                 
}

The result

After adding these validations, you should be able to see a page which validates all fields when losing their focus:

3.9 Using jQuery UI for paging and grid editing

Add some blog categories

We will now make a page to edit some blog categories which we can use to categorize our blog posts. For starters, we need some mock data to represent this. Start with creating a new folder /categories in the mockdata folder. In this folder add some JSON files containing some categories, for example:
1.json

{
    'id': 1,
    'name': 'lily'
}

2.json

{
    'id': 2,
    'name': 'kauri'
}

3.json

{
    'id': 1,
    'name': 'daisy'
}

etc.

Add the jqgrid module

As with all modules you use, to add a new module you should add this module in 2 files:

To use the jqgrid module, add the artifact in the wiring.xml of your myblog application and mount it on path /kauri/jqgrid:

    <artifact id="jqgrid" groupId="org.kauriproject" artifactId="kauri-forms-jqgrid">
      <mount name="main" path="/kauri/jqgrid" />
      <inject-restservice name="jquery" ref="jquery:main" />
    </artifact>

And later on, inject the service into your myblog module:

    <artifact id="module1" groupId="org.kauriproject" artifactId="module1" version="1.0-SNAPSHOT">
      <inject-restservice name="forms" ref="forms:main"/>
      <inject-restservice name="jquery" ref="jquery:main"/>
      <inject-restservice name="tinymce" ref="tinymce:main"/>
      <inject-restservice name="jqgrid"          ref="jqgrid:main" />
      
      <mount name="main" path=""/>
      <mount name="data" path="/data"/>
    </artifact>

import it in your spring configuration services.xml:

<kauri:import-restservice name="jqgrid"/>

That's it.

Use the module in your template

All there is to include to use jqGrid is packed in one file you can easily include:

    <t:include src="service:/jqgrid/templates/snippet/headerlinks.xml"/>

After this, all the jqGrid magic can be used. Check the jqGrid wiki for documentation on how to use the plugin.
Notice what is important in the code below:

          jQuery("#grid").jqGrid({
              colNames: colHeaders,
              colModel: colModel,
              height: 250,

              width:650,
              viewrecords: true,
              caption: 'All blog categories',
              pager: jQuery('#pager'),
              rowNum:5,
              rowList:[5,10],
              sortname:"name",
              jsonReader: {
                  /* Works on the data returned by the datatype function,
                   where already some data conversion of the server data is performed! */
                  root: "rows",
                  page: "page",
                  total: "total",
                  records: "records",
                  repeatitems: false,
                  id: "id"
              },
              datatype: function(postdata) {
                  var parameters = {}
                  if (postdata.page != undefined)
                      parameters["page"] = postdata.page;
                  if (postdata.rows != undefined)
                      parameters["pageSize"] = postdata.rows;
                  if (postdata.sidx != undefined)
                      parameters["sort.0"] = postdata.sidx;
                  if (postdata.sord != undefined)
                      parameters["order.0"] = postdata.sord;

                  $.ajax({
                      url: datapath,
                      data: parameters,
                      dataType: "json",
                      complete: function(jsondata, stat){
                          if (stat == "success") {
                              var thegrid = jQuery("#grid")[0];
                              thegrid.addJSONData(convertToGrid(jsondata.responseText));
                          }
                      }
                  });
              }

          });

And in the html, make sure you have a container with the ID used above:

  <t:block name="content">

    <table id="grid" class="scroll" >
    </table>

    <div id="pager" class="scroll" style="text-align:center;">
    </div>

  </t:block>

Save all of this in pages/categories/grid.html.xml.

Result

Browse to http://localhost:8888/categories/grid.html and this should be the result:

Grid editing

We'll make sure that when we click a row, we can edit the name of the category inline. More documentation and example can be found in the jqGrid wiki.

For starters, don't forget to set the editable columns editable:

      var colModel =  [
          {name:'name',index:'name', width:55, jsonmap:'name', resizable:true, editable: true}
      ];

To accomplish inline editing we'll add 'onSelectRow' as parameter to the jqGrid call. This is a function that defines what to do when a row is selected in the grid, and in this case we want to call the 'editRow' function:

onSelectRow: function(id){
                  if(id && id!==lastSel){ 
                      jQuery('#grid').restoreRow(lastSel); 
                      lastSel=id; 
                  }
                  jQuery("#grid").editRow(id, true, '', '', "${publicUri('service:/data/categories/')}"+id+"?method=PUT", [], after_save);
              }

The first 3 lines make sure that only one row at a time can be selected. The last row defines what to do when a row is edited:

      var after_save = function() {
          $("#grid").trigger("reloadGrid"); 
      }

When this is done, there is a call made to the correct URL. But we need Kauri-style data to be sent to the server, so we have to make some more customisations:

              ajaxRowOptions : {
                  type :"POST",
                  contentType :"application/json; charset=utf-8",
                  dataType :"json"
              },         
              serializeRowData: function(obj){
                 var toPost = {};
                 toPost['id'] = obj.id;
                 toPost['name'] = obj.name;
                 var str = JSON.stringify(toPost);
                 return str;
              }   

This does make sure JSON is sent to the server (ajaxRowOptions), and only id and name are sent (and not more jqgrid options, like 'editmethod' etc that would be saved in our category object if we send it to the server) (serializeRowData).

Enable adding a category

We'll create a button to add a new category as well. We'll do this by adding the HTML for the button, attaching a click handler to that, and calling the needed jqGrid function to create a row.
First add the button:

    <table id="grid" class="scroll" >
    </table>
    <input type="button" id="add" value="Add a category" /> 
    <div id="pager" class="scroll" style="text-align:center;">
    </div>

In jqGrid, you can call 'editGridRow' with "new" as ID to create a new item. (see documentation jqGrid: Edit grid row)
This function needs some essential parameters:

The URL used for making the AJAX call is the "editurl" in the jqGrid options.

          jQuery("#grid").jqGrid({
....
              editurl:   "${publicUri('service:/data/categories/')}"          
....
          });
....
jQuery("#add").click( function() { 
	            
	         jQuery("#grid").editGridRow( "new", 
	              {   
	                  ajaxEditOptions : {
	                      type :"POST",
	                      contentType :"application/json; charset=utf-8",
	                      dataType :"json"
	                  },
	                  serializeEditData: function(obj){
	                     var toPost = {};
	                     toPost['name'] = obj.name;
	                     var str = JSON.stringify(toPost);
	                     return str;
	                  },
	                  closeAfterAdd : true   
	           } );
	      }); 

Attach a blog category to a blog item

We enable the use of blog categories into the blog item editor. Herefore we'll use a selection control  in the fconf:

              'category' : {
                  base: 'composite',
                  members: {
                    'id' : {
                      base: 'integer',
                      control: {
	                      "base": "selection-control",

	                      "options": {
	                          "uri": "${publicUri('service:/data/categories')}",
	                          "valueTemplate": "{id}",
	                          "labelTemplate": "{name}"
	                      }
                      }
                    }
                  }
              }  

Which results in a selection control on the form:

Note the 'composite' that in between our form and the selection control. This is because we do want to send data to the server in format {'category' : {'id' : 1}} instead of {'category': 1}. The latter would not allow us to save a BlogItem with a Category object in it (but only the ID then).

This is also why the automaticaly created html form shows the 'id' as well as the 'category' label. TODO: show how to remove it by writing HTML.

3.10 Migrate from DB mock to DB resources

Check the JPA database resources section in the Kauri documentation for more detail.

Making entities

We'll make entities for all data we have used temporary JSON files for and we use JPA for this. Annotate your POJO's with the JPA annotations where appropriate and do not forget to add an empty constructor:

package org.kauriproject.myblog.entities;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity(name = "categories")
public class Category implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	private String name;
	
	public Category(){
		// (empty) constructor needed
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

We do the same for BlogItem:

package org.kauriproject.myblog.entities;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.Cascade;


@Entity(name = "items")
public class BlogItem implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	private String title;
	private String author;
	private String url;
	private String publicationdate;

    @OneToOne(fetch = FetchType.EAGER)
    private Category category;    

	
	private String content;

	public BlogItem(){
		// empty constructor
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getAuthorEmail() {
		return author;
	}
	public void setAuthorEmail(String authorEmail) {
		this.author = authorEmail;
	}
	public String getAuthorUrl() {
		return url;
	}
	public void setAuthorUrl(String authorUrl) {
		this.url = authorUrl;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getPublicationdate() {
		return publicationdate;
	}
	public void setPublicationdate(String publicationdate) {
		this.publicationdate = publicationdate;
	}
	public Category getCategory() {
		return category;
	}
	public void setCategory(Category category) {
		this.category = category;
	}
	
}

Create database and database user and create persistence.xml

We will store our entities in a MySQL database. For this, create an empty MySQL database, and a user with sufficient privileges to create tables and data in it.
Create a persistance.xml file in src/main/resources/META-INF which contains this databasename, username and password:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
  <persistence-unit name="kauri-dbresources" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="update" />
      <property name="hibernate.show_sql" value="false" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.username" value="mysqluser" />
      <property name="hibernate.connection.password" value="mysqlpassword" />
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/myblog" />
    </properties>
  </persistence-unit>
</persistence>

Startup in production mode

Now don't forget to startup your application in production (default) mode. Or: just leave the '-p prototype' behind when starting up kauri:

/path/to/kauri run

instead of

/path/to/kauri run -p prototype

Once this is done, the application will no longer use the mockup data, but persist all data in the specified database.




3.11 Adding security to an application

TODO

3.12 Create an RSS feed

Add wanted path to router.groovy

is this needed if the path is also in the resource?

    resource(uri: "/feed",
        ofClass: "org.kauriproject.myblog.feed.BlogItemsResource");

Create a BlogItemResource

We'll create a resource class that can get a list of all blog items, this method puts this list into a hashmap. Such a method returns a KauriRepresentation, which on his turn will be mapped to a template in representations.groovy. We create a "listBlogItems" method in this resource class, annotated with a jaxrs path. This method uses JPA to create a list of blogitems.

package org.kauriproject.myblog.feed;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.kauriproject.myblog.entities.BlogItem;
import org.kauriproject.representation.build.KauriRepresentation;
import org.restlet.resource.Resource;
import org.springframework.orm.jpa.support.JpaDaoSupport;

@Path("/feed")
public class BlogItemsResource extends Resource{
    private JpaDaoSupport jpaDaoSupport;
	
	public void setJpaDaoSupport(JpaDaoSupport jpaDaoSupport) {
		this.jpaDaoSupport = jpaDaoSupport;
	}

	@Path("list")
    @GET
    @Produces("application/xml")
    public KauriRepresentation listBlogItems() {
        Map<String, Object> data = new HashMap<String, Object>();
        // load all blogitems into data
        List<BlogItem> items = jpaDaoSupport.getJpaTemplate().find("select b from items b");
        data.put("items", items);
        
        return new KauriRepresentation("atom", data);
    }
}

Add template to representations.groovy

The resource class creates a Kauri representation which in mapped in representations.groovy:

      when(name: "atom") {
          template(src: "module:/pages/atom.xml")
      }

Create atom template

pages/atom.xml explain

3.13 Add caching

TODO

see documentation for caching of static resources

4 Kauri concepts

This documents gives an overview of the core concepts and technologies provided by Kauri. See Getting started for a practical guide to start using Kauri.

Kauri is a web application framework. See wikipedia in case you don't know what a web application or a framework is.

4.1 Adhering to Web architecture

Kauri does not try to work around the constraints imposed by the Web, but embraces them. Kauri wants you to think about resources, URIs, correct use of the HTTP methods, response codes, caching, and so on. In one word, it supports RESTful development. Or if you prefer, ROA and WOA.

For this reason, Kauri does not use the classic Servlet API, but the Restlet API. Many things in Restlet will be familiar for Servlet developers: it is still about requests and responses. But at a more detailed level, its design matches better with REST and HTTP concepts. This in turn will help you to write better Web applications.

Kauri, like Restlet, does not have sessions as known in the Servlet world. Things that you might have traditionally stored in sessions, can often be rethought as resource state, kept in the client, or else stored as (preferably client-controlled) temporary resources.

4.2 Routing and resource classes

A RESTful design starts with thinking about the resources you want to expose and their URIs. Kauri thus has very good support for routing requests based on the request URI. You can find more information about routing in the routing chapter.

Kauri provides a flexible routing component. It is configured through a simple Groovy DSL. You do not have to know Groovy for this purpose. Below is a small example, you can probably guess what it does (if not, don't worry, it is all explained in the docs).

builder.router {
  directory(uri: "/resources", root: "module:/resources/")
  resource(uri: "/persons/{id}.html", ofClass: "com.foobar.Person")
}

The routing will eventually bring the request up to the Java class that will handle it. Such a class, which implements a resource, is called a resource class. In case the URI is not recognized by the system, a 404 Not Found response will be produced.

You can manually implement resource classes based on the Restlet API or the JAX-RS API. That last one is an API defined through the JSR process, and is based on annotations, providing a practical and consice means to implement a resource class. Here is an example to give an idea:

@Path("/persons/{id}.html")
public class PersonResource {

    @GET
    @Produces("text/html")
    public KauriRepresentation getPerson(@PathParam("id") String idParam) {
        ....
    }
}

Kauri also includes a component to automatically expose a database model (implemented using JPA) as RESTful resources.

4.3 The Kauri Runtime: modules

Modularization is a core tool of software engineering to keep the complexity low. By dividing an application into modules, that communicate through well-defined interfaces, a big application stays manageable.

An application can not only consist of custom-developed modules, but will often make reuse of modules provided by Kauri or other parties. Examples of modules included with Kauri are the routing module, the templating module, the forms module, and so on.

While you might not find your own application big and complex enough to bother splitting it into modules, you will still benefit from the modularization by being able to reuse existing modules. Since modules are properly encapsulated, you can do so without having to worry about their internal workings.

The core of Kauri, which manages the modules, is called the Kauri Runtime. The Kauri Runtime manages the startup and teardown of modules, the wiring of services between them, and the classloading of the modules.

The description of what modules form a certain application, and how to wire them together, is done in a file which we call the wiring.xml.

Technically, a module is a jar file containing a KAURI-INF directory which can contain:

At startup, Kauri reads the classloader configuration of all modules and builds the classloader setup. Then it starts the modules, which comes down to booting the Spring container of each module. The service wiring is done by making available the dependencies as beans in the Spring container.

Up to here, nice, but nothing exceptional. The differences come from Kauri Runtime's support for REST-services and the Maven repository.

REST-services

REST-services are similar to classic Java services: a module can provide REST-services, and depend on REST-services. A REST-service can answer to REST-style requests (i.e. GET/POST/PUT/... on an URI-identified resource), not just for a single URI but an entire URI-space. When a module depends on a REST-service, you can either wire it to a REST-service provided by another module, or to an arbitrary URI.

In fact, everything you want to make available over HTTP should be provided by a module as a REST-service and is then mounted on a specific path.

Maven repository

The Kauri Runtime loads all modules and their classpath needs from Maven-style repositories. A Maven repository is a repository containing artifacts, which typically are jar files. By using the Maven repository, the jars are clearly identified by ID and version, rather than relying on file names. Another advantage is that after building your project using Maven, you can immediately run it. There is no no need for additional copying, as is the case with wars.

Internal protocols

The Kauri Runtime provides two special protocols for use within modules: The “module:” protocol to load resources from the module jar, and the “service:” protocol to access REST-services.

4.4 Templates

As most other web frameworks, Kauri has a template language, in which you will find the familiar constructs. More detailed information on templates is found here.

It is not the kind of template language like JSP, in which you can embed arbitrary (Java) code, but rather a restricted one in which you can use a limited set of constructs like loops, if's and expressions. We do reuse JSP's expression language (EL).

Kauri's template language is a standalone, reusable library not tied to any other parts of Kauri.

XML-based

The template language is XML-based. Each template file has to be a well-formed XML file. The advantage of this is that the template output will always be well-formed markup (start and end tags match, proper escaping of special characters), common formatting rules are enforced (an empty script tag should have a close tag, things like that), and the output is produced as SAX-events instead of characters, allowing to connect it to other XML transformation components (such as XSLT) in an efficient way.

Template inheritance

To support a common layout across pages, we support template inheritance, inspired by Django's template language. With template inheritance, you can define a base template in which there are regions which can be overridden by child templates.

As an example, take this base template:

<?xml version="1.0"?>
<html xmlns:t="http://kauriproject.org/template">

  <head>
    <title>
      <t:block name="title">The title</t:block>
    </title>
  </head>

  <body>
    <t:block name="main">Main content</t:block>
  </body>
</html>

The listing below shows a template inheriting from this base template. Notice the t:inherit attribute on the root element. The content of the t:block elements will replace that of the base template. All content outside the t:block's will be ignored. This allows to add body tags etc. so that the inherited template can be viewed stand-alone too.

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns:t="http://kauriproject.org/template"
      t:inherit="module:/templates/layout/layout.xml">

  <t:block name="title">My page</t:block>

  <t:block name="main">My interesting content</t:block>

</html>

Multiple inheritance, calling the “super” block and cross-block initialization are supported. All this is explained here.

Link translation

A module does not know on beforehand where in the URI space its resources will end up. In case it reuses REST-services from other modules, it will even less know where those will end up in the URI-space. Therefore, the template langauge has a special publicUri() function to translate from internal paths to public paths. REST-services are internally addressed using a service protocol, so a publicUri() call looks like:

<a href="publicUri('service:/main/person/john.html')">John</a>

4.5 Forms

Forms play an important role in web applications. Plain HTML forms are rather basic and don't offer a lot of help with common issues such as data validation, custom controls, composite and collection structures, and so on. Kauri Forms solves these problems for you.

In contrast to the forms support of many web application frameworks, Kauri Forms is a Javascript library which runs in the browser. It is not a Java framework which manages a server-side model of your form. Kauri Forms makes the radical assumption that Javascript is available.

The form-controller sits in the browser, and directly GETs and POSTs/PUTs data to resources.

Besides the usual basic widgets, you will find things such a Google Maps widget or an Ajax-enabled upload widget.

A form's structure can be defined in Javascript (JSON), but it can also be implictly derived from annotations on a HTML form.

Below we show an example of a Javascript-defined form. A form consists of widgets, which have an ID and extend from built-in widgets. In the sample below, the IDs of the widgets are name, email and birthday. The email widget has a special property “+validators”, which means we add the listed validators to those of the base type, rather than replacing them.

var fconf = {
    createURI: "${publicUri('service:/data/contact/')}",
    type: {
        members: {
            name: "string",
            email: {
                base: "string",
                "+validators": { isEmail: {} },
                label: "e-mail"
            },
            birthday: {
                base: "date",
                yearRange: "-100:+0",
                label: "What is your date of birth?"
            },
        }
}};

In the HTML page, you put placeholders where the widgets should be inserted. These placeholders use special 'kauri-' attributes to refer back to the form module, like this:

<label kauri-role="label" kauri-idref="name"/>
<input kauri-idref="name"/>

4.6 Holistic approach

Besides supporting RESTful design, another important goal of Kauri is to support all players and all steps of a web application project, as described in more detail in the vision document.

Prototyping

The holistic vision is in part realized by the "prototyping mode" of Kauri. In prototyping mode, the focus is on designing the web front-end.

The development of a Web front-end is an iterative process. Often starting from a napkin wireframe, some first HTML pages are designed. The static HTML pages might be replaced with executable templates to support extracting the common layout and other reusable snippets. Feedback from the client is used to refine the design. Up to here, nothing too special.

The prototyping mode of Kauri allows you to turn your HTML page mockups into a real working prototype. The effort involved in this is not lost, as the development of the real application will re-use the same artifacts.

Here are some of the tools offered for prototyping:

There is no fixed line between what is possible in a prototype, and what not. A prototype can make use of Kauri Forms and Ajax.

As an example, suppose we have a resource person which we want to make available in the URI space as person/{id}.html

For this we create a template file at src/main/kauri/pages/person/{id}.html.xml1. During prototyping, template files are executed directly, without going through a resource class. This is sometimes refered to as Model 1 or PHP-style.

<?xml version="1.0"?>
<html xmlns:t="http://kauriproject.org/template">
  <t:variable name="person"
              src="service:/data/persons/${request.attributes.id}"
              overwrite="false"
              accept="application/json"/>

  <body>
    <h1>Person: ${person.name}</h1>

    <p>City: ${person.city}</p>
  </body>
</html>

Pay attention to the t:variable instruction: rather than defining the value of the variable using an expression, we tell it to load its data from a URI.

The person data is defined by creating a file src/main/kauri/mockdata/persons/1.json

{
  "name": "Mr Foo Bar",
  "city": "Foobar City"
}

4.7 Technology choices

We think it is useful if some choices have not to be made over and over for each project. Therefore, we have made a selection of third-party technologies which we push forward as the default solution to use in Kauri. This comes without obligation, but it will be useful to reduce learning curve, increase developer familiarity, and increase reuse of dependencies among modules.

More specifically, we have selected jQuery as the Javascript library.

As CSS framework, we use Blueprint CSS.

4.8 Developer convenience

4.8.1 Quick test cycle

When working on things which require lots of interactive testing, such as templates, CSS, etc. you can immediately try changes without having to rerun your build. This is called running from source. With a simple command line switch, you let Kauri know that it should read module resources directly from your source tree, rather than from the compiled jar.

4.8.2 Project templates

Project templates (Maven archetypes) generate the basic structure for new projects.

4.9 Open Source

Kauri is available for free with source code included. The sources are released under the business-friendly Apache license.

4.10 Other

5 Prototyping

TODO: we should write a nice intro to the prototyping concepts. The ingredients are:

5.1 Prototyping: step-by-step

5.1.1 Introduction

Creating a web application prototype using Kauri can be done by anyone with some "web skills", i.e. HTML, CSS, maybe some Javascript and familiarity with template languages.

This step by step guide will get you started from zero. If you experience any difficulties, you're welcome to share them on our discussion group.

5.1.2 Prerequisites

If you have not done so already, install Kauri and install Maven.

We will assume you have added Kauri's bin directory to your PATH environment variable.

5.1.3 Create a project

Create a project as described here. When asked 'Choose archetype', select the "kauri-archetype-protototyping" archetype (at the time of this writing, option 2).

Also build and try out the created project as described over there.

5.1.4 Start Kauri in prototype mode

Kauri can be started in different modes: either "prototype" or "production" (the default).

Depending on the mode, different parts of the routing will be activated, different Spring configurations can be loaded, etc.

Since we will be prototyping, we start Kauri in prototype mode, and to avoid having to rebuild and restart Kauri when making changes, we start Kauri in source mode.

Here's the command:

kauri(.sh) -p prototype -s module-source-locations.properties

5.1.5 Create templates

In prototyping mode, the URI space is defined by the files and directories inside the pages directory, located at:

module1/src/main/kauri/pages

If you create a new file there, for example hello.html.xml, you will be able to access it in your browser as http://localhost:8888/hello.html

Every file you create in this directory will be executed as a template, so it has to be a valid template file. Basically, this means it has to be a well-formed XML file.

But you can do smarter things than this. By putting {variables} in file or directory names, you can define URI patterns.

As an example, suppose we create an "order resource", that is, a page showing the details about an order. We want this to be available at the URI /orders/{orderid}.html

For this, we create an orders subdirectory inside the pages directory, and in that directory, a file called {orderid}.html.xml. You can use the { and } characters in a file name, so this is no problem. To summarize, we create the following file:

module1/src/main/kauri/pages/orders/{orderid}.html.xml

The purpose of the double file extension is as follows: the first extension will be part of the URI path, the second is for having a correct association with applications on your computer. If both extensions can be the same, you only need to use one extension. If you want the URI path to have no extension, but want an extension on the file system, you can use {orderid}..xml (= nothing between the two dots).

Put the following in the {orderid}.html.xml file, our first mockup of an order page:

<html>
  <body>
    <h1>Order number: 12345</h1>
    <h2>Bill to</h2>
    Name: John Doe
    <br/>
    Address: 123 Foobar Street

    <h2>Items</h2>
    <table>
       <tr><th>Nr</th><th>Description</th><th>Price</th></tr>
       <tr><td>324</td><td>Chair</td><td>50</td></tr>
       <tr><td>17</td><td>Table</td><td>250</td></tr>
    </table>
  </body>
</html>

You can now browse to the following URI to see the order page:

http://localhost:8888/orders/12345.html

In fact, you can change the 12345 by any string (excluding the slash character), since the template will be executed for any request matching the {orderid}.html pattern.

5.1.6 Split off data from templates

Now we go a step further, and make our order page screen mockup into a real template, which retrieves its data externally.

First we will create a mock order entity. To define order entities, we create the following directory:

module1/src/main/kauri/mockdata/orders

In this directory, create a file called 12345.json, containing the following data:

{
  billTo: {
    name: "John Doe",
    address: "123 Foobar Street"
  },
  items: [
    {
      code: "324",
      description: "Chair",
      price: "50"
    },
    {
      code: "17",
      description: "Table",
      price: "250"
    }
  ]
}

Now we adjust our template {orderid}.html.xml to make use of this data:

<html xmlns:t="http://kauriproject.org/template">
  <


t:variable name="order" src="service:/data/orders/${request.attributes.orderid}"/>

  <body>
    <h1>Order number: ${order.id}</h1>
    <h2>Bill to</h2>
    Name: ${order.billTo.name}
    <br/>
    Address: ${order.billTo.address}

    <h2>Items</h2>
    <table>
       <tr><th>Nr</th><th>Description</th><th>Price</th></tr>
       <t:forEach in="${order.items}" var="item">
         <tr><td>${item.code}</td><td>${item.description}</td><td>${item.price}</td></tr>
       </t:forEach>
    </table>
  </body>
</html>

Because of a limitation in the current Kauri version, you need to restart Kauri after making changes to the the JSON mock data. Remember that you need to start Kauri with the -p prototype argument, otherwise this will not work.

To try it out, browse again to the same URI (assuming you called your entity 12345.json):

http://localhost:8888/orders/12345.html

Some explanation about the template:

You can now create some additional mock orders in the directory mockdata/orders, and verify you can view them in the browser.

5.1.7 Listing all orders

The mock JSON entities are not simply static files which we load into our templates. They are managed by the DB Mock component, which provides a RESTful interface on top of them, supporting CRUD operations, query operations including paging and entity-linking possibilities.

We will now show how to create a page listing all orders.

Create a file at

module1/src/main/kauri/pages/orders.html.xml

containing:

<html xmlns:t="http://kauriproject.org/template">
  <t:variable name="orders" src="service:/data/orders?sort.1=billTo.name"/>

  <body>
    <h1>Orders</h1>

    <table border="1">
      <tr><th>Order ID</th><th>Client</th></tr>
      <


t:forEach var="order" in="${orders}">
        <tr>
          <td><a href="${publicUri('service:/main/orders/')}${order.id}.html">${order.id}</a></td>
          <td>${order.billTo.name}</td>
        </tr>
      </t:forEach>
    </table>
  </body>
</html>

Try it out at:

http://localhost:8888/orders.html

Some explanation about the template:

5.1.8 Defining layout

We want the various pages in our application to share a common layout. Kauri's template language has an interesting " template inheritance" feature for this. You can write a base template in which certain regions, called blocks, can be redefined by child templates.

As part of generating the project, a layout template is already created for you at:

module1/src/main/kauri/templates/layout.xml

If you open this file, you will see it contains the following blocks:

<t:block name="title"/>

and

<t:block name="content"/>

You can of course create as many blocks as you like, and freely choose their names.

Now let's adjust our order pages to inherit from this base layout.

We will show this for the orders.html.xml, you can do the same thing for {orderid}.html.xml

<html xmlns:t="http://kauriproject.org/template"
      t:inherit="module:/templates/layout.xml">

  <t:init>
    <t:variable name="orders" src="service:/data/orders"/>
  </t:init>

  <t:block name="title">Orders</t:block>

  <t:block name="content">
    <h1>Orders</h1>

    <table border="1">
      <tr><th>Order ID</th><th>Client</th></tr>
      <t:forEach var="order" in="${orders}">
        <tr>
          <td><a href="${publicUri('service:/main/orders/')}${order.id}.html">${order.id}</a></td>
          <td>${order.billTo.name}</td>
        </tr>
      </t:forEach>
    </table>
  </t:block>

</html>

Some explanation about this template:

After you have made these changes, the pages will still pretty much look the same. You can adjust the layout.xml to apply a more fancy style.

5.1.9 Editing entities: Kauri Forms

Most web applications will contain forms, and thus while prototyping the front-end, you will eventually also be designing some forms. You could define these forms simply as HTML. But you could also start using Kauri Forms right away. Together with DB Mock, this will to some extent give the impression of a real working application, as you can load and store data. It also makes that you can to a large detail develop the front-end before, or in parallel with, the back-end.

Let us create a form for editing an order. Create a file at

module1/src/main/kauri/pages/orders/{orderid}-edit.html.xml

and put the following in it:

<html xmlns:t="http://kauriproject.org/template"
      t:inherit="module:/templates/layout.xml">

  <t:init>
    <t:variable name="id" value="${request.attributes.orderid}"/>

    <t:if test="${id != 'new'}">
      <t:variable name="order" src="service:/data/orders/${id}"/>
    </t:if>
  </t:init>

  <t:block name="content">
    <t:include src="service:/forms/templates/snippet/headerlinks.xml"/>

    <script type="text/javascript">
      jQuery(document).ready(function() {
          // Define form configuration
          var fconf = {
              "createURI": "${publicUri('service:/data/orders/')}",
              "dataURI": "${publicUri(txt:concat('service:/data/orders/', id))}",
          };

          // Create the form
          var editForm = new jQuery.org.kauriproject.forms.Form("edit-form", fconf);

          // Modify some form properties
          editForm.submitSuccess = function (data, success) {
              window.location = "${publicUri('service:/main/orders.html')}";
          };
          editForm.setCreateMode(${id == 'new'});

          <t:if test="${id != 'new'}">
            // Load data into the form
            editForm.setWireValue(${order});
          </t:if>
      });
    </script>
    
    <form id="edit-form">
      <div kauri-role="input" kauri-idref="/" kauri-type="composite">
        <h1>Order number: ${id}</h1>

        <h2>Bill to</h2>
        <div kauri-idref="billTo" kauri-type="composite" kauri-role="input">
          Name: <input kauri-idref="name" kauri-type="string"/>
          <br/>
          Address: <input kauri-idref="address" kauri-type="string"/>
        </div>

        <h2>Items</h2>
        <table kauri-idref="items" kauri-type="collection" kauri-role="input">
           <tr><th>Nr</th><th>Description</th><th>Price</th><th/></tr>
           <tr kauri-role="layout">
             <td><input kauri-idref="code" kauri-type="string"/></td>
             <td><input kauri-idref="description" kauri-type="string"/></td>
             <td><input kauri-idref="price" kauri-type="string"/></td>
             <td><a kauri-role="delete" href="#" onclick="return false;">delete</a></td>
           </tr>
        </table>
        <a kauri-idref="items" kauri-role="add" href="#" onclick="return false;">add item</a>

        <p><input type="submit" value="Submit"/></p>
      </div>
    </form>

  </t:block>

</html>

This form supports both editing existing orders and creating new orders.

To edit an existing order, browse to:

http://localhost:8888/orders/12345-edit.html

(the 12345 should correspond to an existing JSON file in mockdata/orders)

To create a new order, browse to:

http://localhost:8888/orders/new-edit.html

You will see how the existing data is loaded, or the new data is saved and appears in the order overview. You will also see that you can add and remove items to the order.

In the template above, you see a script element containing some Javascript. A variable fconf is created, whose purpose is (mostly) to describe the form structure. In the example here, there is actually nothing of form structure described in the fconf. When this is the case, Kauri Forms will automatically derive the form structure from your HTML form, based on the kauri-idref and kauri-type attributes.

Kauri Forms can load and save form data from and to JSON. The IDs of the form widgets (in the kauri-idref attributes) correspond to the properties of the JSON object. In case you are editing an existing order, the data is loaded into the form by the setWireValue(${order}) call. The ${order} is evaluated by the template engine, so it will be replaced by the actual form data in the HTML sent to the browser.

We won't explain Kauri Forms in more detail here. If this example has wet your appetite, check out the forms documentation to learn more about it.

5.1.10 From prototype to real application, and back again

Up to now we have been running Kauri in prototype mode. If you want to stop working in prototype mode, simply don't pass the "-p prototype" argument.

5.1.10.1 From DB Mock to real data resources

Some things will then however be broken, especially all templates where you load data from DB Mock, since DB Mock is only available in prototype mode. You will have to replace the mock 'data' service by a real one. The way this works is that some Spring configuration is loaded based upon the runtime mode:

module1/src/main/kauri/spring/[prototype|production]

With the project generated by the prototyping-archetype, there is one sample entity present ("Person") which works in both modes. It makes use of JPA for the real entity, backed by an in-memory HSQLDB.

5.1.10.2 From direct template execution to resource classes

During prototyping, the templates in the "pages" directory are executed directly, without first going through some resource class (somewhat similar to what other frameworks call controller).

For some pages this is fine, and can stay this way. However, the more common way of working is to first perform logic and gather data in a resource class, which is then passed on to a template. In a resource class, it is easy to take decisions such as producing an error, redirecting to somewhere else, and so on. A template on the other hand directly starts producing output (and thus sending it to the browser), and hence does not allow to make such decisions anymore.

The same template file can however be reused. You do not need to copy it to another location or so: you can literally reuse the same file. When not in prototyping, the request routing will first look for resource classes to handle the request, before resorting to the direct execution of the templates in the pages directory (in prototyping mode, it works just the other way around).

There is one trick involved though. During prototyping, we define variables with the 'src' attribute to load data. When not prototyping, this data will be passed on from the resource class. Therefore we need to tell the variable not to overwrite the data if is is already previously defined, using the overwrite attribute:

<t:variable name="order" src="service:/data/orders/${id}" overwrite="false"/>

Again, the prototyping-archetype generated an example of this, see the PersonResource class.

5.1.10.3 Switch between prototype and production mode at any time

Since the same template files can be used for prototype and production mode, you can switch between them at any time.

5.2 Prototyping: how it works

TODO: this should explain how prototyping works to a technical audience: what kauri features support the prototyping: mock dbresources, 'pages' and 'mode' and 'passThrough' in routing, mode-dependent spring configs, runtime mode, ...

6 Routing

6.1 What is routing?

In Kauri, routing means the problem of mapping an incoming request to a resource class.

Routing is usually done based on the request URI, in particular its path component.

   http://kauriproject.org/documentation/tutorial.html?foo=bar&foo2=bar2
   <--> <----------------><--------------------------><---------------->
  scheme    authority              path                  query string

If you are familiar with other web-frameworks supporting configurable routing, you are probably wondering how the routing is configured in Kauri. For completeness, you should know there are multiple levels of routing (see next section), but the most interesting one is how routing is done within a module. For this, Kauri provides a standard routing infrastructure which is configured with a syntax like this:

builder.router {
    resource(uri: "/user/{name}", ofClass: "mystuff.UserResource")
    resource(uri: "/order/{orderId}", ofClass: "mystuff.OrderResource")
}

The syntax of this file is Groovy using the Groovy Builder convention. The uri patterns are defined using URI template syntax, in which the parts in brackets {} represent wildcards.

This is a very basic example, there are lots of other possibilities described later on.

6.2 The full picture: how a request is routed

To refresh your memory, a Kauri setup consists of a number of modules which can provide restservices. These restservices are mounted on a certain path on a certain virtual host. From this sentence, we can already distinguish two levels of routing which happen:

  1. an incoming request is routed based on the virtual hosts configuration. If you have not configured any virtual hosts, you don't need to worry about this item, every request will go to the one and only default virtual host.

  2. next, the request is routed to a certain restservice based on the path on which the restservice is mounted

Once the request arrives at the restservice, it is up to the restservice to decide how the request should be handled further.

Power users will appreciate the fact that they can implement any sort of behavior as desired. However, this is rather low-level work and quickly recurring patterns will appear, therefore Kauri provides a standard routing infrastructure (= the one configured with the Groovy syntax) which should suffice for just about all routing requirements.

6.3 Routing first steps

6.3.1 Outline

For the purpose of this routing introduction, we assume you have already a working Kauri project with at least one module.

If you set up a project using the archetype, then all the steps below will already have been done.

The steps to use the routing are as follows:

  1. add the routing module to your wiring.xml file
  2. import the routing service in your module's Spring container
  3. create a router instance as Spring bean using the routing service
  4. export the router as a restservice
  5. mount the exported restservice on a path
  6. (optional) customize the default built-in routing by creating a routing.groovy file

These are all small steps, most of which you are already familiar with. We explain them in detail below.

6.3.2 The steps to introduce routing

6.3.2.1 Add the routing module to wiring.xml

In your wiring.xml file, add the following module inside the <modules> element, before any other modules where you want to make use of the routing.

<artifact id="routing"
          groupId="org.kauriproject"
          artifactId="kauri-routing-impl"/>

6.3.2.2 Import routing service in your module

Edit your module's Spring XML configuration, which can be found in the KAURI-INF/spring directory.

In your module's Spring XML configuration, add the following Java service import, which makes the RoutingService, supplied by the routing module, available within the Spring container as bean id 'routingService'.

<kauri:import-service id="routingService"
                      service="org.kauriproject.routing.RoutingService"/>

6.3.2.3 Create a router instance

We're still in your module's Spring XML configuration.

If it is not the case already, add a kauri:module tag somewhere in it. If you have already a kauri:module tag, make sure it contains at least the attributes listed below.

<kauri:module restletContext="restletContext"
              handle="module"/>

Then create the actual router by adding this:

<bean id="router" factory-bean="routingService" factory-method="createRouter">
  <constructor-arg ref="restletContext"/>
  <constructor-arg ref="module"/>
</bean>

As you can probably figure out yourself, the values of the constructor-arg's need to match the values of the attributes of the kauri:module.

6.3.2.4 Export the router as a restservice

Still in your module's Spring XML configuration:

<kauri:export-restservice name="router" ref="router"/>

6.3.2.5 Mount the exported restservice on a path

In the wiring.xml, inside the declaration of your own module, add a mount statement to mount the router on a certain URL path. Thus only the bold section should be copied in your wiring.xml file.

<artifact id="mymodule" groupId="...." artifactId="..." version="...">
  <mount name="router" path="/router"/>
</artifact>

You can of course change the "/router" path to whatever you desire, in fact "/router" is not a very good name.

6.3.2.6 Try it out

Even though we have not made an router configuration yet, you could already try out the router because a default routing configuration is used in absence of a custom one.

This default routing configuration, among other things, will make all resources in KAURI-INF/resources available on your router on the path "/resources". So suppose you create a file helloworld.txt in that resources directory, than you can already access it in your browser using the following URL:

http://localhost:8888/router/resources/helloworld.txt

Before trying this URL, you should as usual build your module (unless you're working in source mode) and restart Kauri.

6.3.2.7 Customize the routing

Now you can start customizing the routing according to your own needs. This is done by creating a file KAURI-INF/router.groovy in your module.

Here's a small example:

builder.router {
    restlet(uri: "/helloworld", handle: { request, response ->
        response.setEntity("Hello world from inside the router",
                           mediaType.TEXT_PLAIN)
    })
}

This example makes use of the ability to implement a Restlet inline in the router definition, which is not really a good and common practice (usually the restlets are implemented in separate Java classes), but is handy for this sort of examples.

The example can be accessed using:

http://localhost:8888/router/helloworld

6.4 JAX-RS first steps

6.4.1 About JAX-RS

The official description for JAX-RS (a.k.a. JSR-311) is that it "defines a set of Java APIs for the development of Web services built according to the Representational State Transfer (REST) architectural style".

The reason to talk about JAX-RS in this section about routing is because it defines an alternative way to describe routing. Kauri's routing configuration is a central configuration of the routing structure. In contrast to this, with JAX-RS one adds annotations to classes to describe to which paths they react, hence providing a decentralized routing configuration.

6.4.2 Trying it out

Let's illustrate JAX-RS with a simple example. Let's assume you have added routing to your module as described in Routing first steps. Make sure you do not have a routing configuration at KAURI-INF/routing.groovy, so that the default routing is used.

Now create the directory KAURI-INF/groovy-jax-rs

In this directory, create a file named HelloWorldResource.groovy, and put the following in it:

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;

@Path("helloworld-groovy")
public class HelloWorldScriptResource {
    @GET
    @Produces("text/plain")
    String plainHelloWorld() {
        return "Hello world from a groovy-based JAX-RS class!";
    }
}

If you are not working in source mode, rebuild your module and restart Kauri.

Now you should be able to access the just-created resource at:

http://localhost:8888/router/helloworld-groovy

This works because the default routing configuration contains a JAX-RS configuration which automatically scans the directory groovy-jax-rs for JAX-RS-annotated classes. In fact, the same is true for Java classes in your module (which always require to rebuild the module and restart Kauri).

6.4.3 More on JAX-RS

Even without having learned about JAX-RS, you can figure out a lot from the HelloWorld example above. The URI path to which the JAX-RS class should be bound is defined using the @Path annotation. The method which should handle GET requests is annotated using @GET.

The GET method simply returns a String. In fact, it could have returned any kind of Java object, since JAX-RS allows to implement classes to convert the returned object to the desired response mime-type. A number of default implementations of such convertors are provided however, one is for handling Strings.

A class with an @Path annotation is called a resource class. Upon each request, JAX-RS makes a new instance of the resource class. In Kauri, these instances are created via your module's Spring container, as a consequence of which auto-wiring of dependencies is supported.

To learn more about JAX-RS, you can read the specification which (at the time of this writing) can be found on the JAX-RS reference implementation development site. The specification is not very long or complex, so it's easy to learn JAX-RS just from there.

6.4.4 Relationship between JAX-RS and Kauri routing

The JAX-RS system is in Kauri used by means of creating a jaxRs routing component.

The main advantages of using JAX-RS over, say, plain Restlet's or Restlet Resource classes are:

6.5 Some background

6.5.1 Routing structure

From a conceptual point of view, a routing structure can contain the following types of components:

All these components can be freely nested inside each other, in order to form a hierarchical routing structure. The request handlers are the leaves of the routing structure.

When you think a bit about it, there is no fixed line where the routing ends. A request handler in itself might contain code which makes decisions based on request properties and delegates to other methods or classes. We don't consider this to be part of the routing anymore though since it is not visible in the routing configuration and hence Kauri doesn't know about it.

6.5.2 Groovy as routing configuration syntax

The configuration syntax for the routing is not a plain data file like XML, but rather an executable program in the form of a Groovy script. Groovy has a standard pattern for describing tree-structures in an easy-to-read manner, which will look like a plain data syntax unless you start making use of more advanced features. This way of using an existing programming language in such a way that it looks like a specialized syntax is called an internal DSL.

Groovy as syntax: pro and con

Some of the pro's of using Groovy as syntax are:

To be fair, some cons are:

Groovy performance

You might have heard that Groovy is slow and hence naively think that doing the routing in Groovy will introduce a bottleneck in the system. This is a false reasoning, since the Groovy script is executed only once and serves to create the internal routing structure. It is really just an alternative for other e.g. XML syntax. The internal routing structure doesn't make use of Groovy and could be built up by other means as well.

6.6 Default routing

When you create a router without specifying a custom location for the router configuration, the routing will be searched at KAURI-INF/router.groovy. If this file does not exist, a default built-in configuration will be used as fallback, which is the following:

builder.router {
    directory(uri: "/resources", root: "module:/resources/")

    jaxRs(uri: "") {
        jaxRsResource(scanPackages: "*")
        jaxRsProvider(scanPackages: "*")
        jaxRsGroovyScripts(path: "groovy-jax-rs")
    }
}

This default routing makes available all files in KAURI-INF/resources as /resources, and automatically scans the module jar for any Java classes with JAX-RS annotations, as well as any Groovy scripts with JAX-RS annotations in KAURI-INF/groovy-jax-rs.

6.7 Routing examples

If you read the documentation in order, you will already have encountered some examples of routing configuration. For the full description of all possible things, you can consult the routing reference documentation. However, some examples can be useful to show how everything glues together.

[TODO: add one or more examples. I'm thinking of multiple hierarchical routers, filters, restlets, ... all together]

[See the routing sample included with Kauri for now]

6.8 Spring integration

For a Restlet or a resource class to do something useful, it will likely need access to the beans declared in your module's Spring container.

The module's Spring container is used for instantiating all classes specified in the routing configuration using the ofClass attribute, as well as the JAX-RS resource and provider classes.

What this means is that Spring will create the instance of the class, and honor the Spring-related annotations on it. Spring will however not manage the complete life-cycle of the object, so e.g. @Destroy annotations will not be honored.

The  most useful is Spring's Autowired annotation. Below is an example of its usage. The system will automatically look up a bean in your Spring container of the 'MessageService' type. If there would be multiple of those, then there are additional annotations to select the correct implementation. See the Spring documentation for more information.

import org.springframework.beans.factory.annotation.Autowired

public class MessageResource {
    private MessageService messageService

    @Autowired
    void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }
}

6.9 URI template syntax

Routers in Restlet and Kauri match URIs based on URI templates.

A URI template is basically a string containing named wildcards, called variables, between { and }. An example:

/users/{id}

By default, the variable {id} will only match URI segments, basically any text not containing the slash character.

You can define various options for the variables. The options are specified by adding them comma-separated after the variable name: {var,option1,option2,option3}.

The options are (in sequence of usefulness):

The options can be specified in any order. It does not make sense to specify multiple variable type options.

For example, to decode a variable and match all URI path characters (thus possibly multiple path segments), use:

/users/{id,uri_path,decode}

Variable types

Option name

Description

all

Matches all characters.

alpha

Matches all alphabetical characters.

alpha_digit

Matches all alphabetical and digital characters.

comment

Matches any TEXT excluding "(" and ")".

comment_attribute

Matches any TEXT inside a comment excluding ";".

digit

Matches all digital characters.

token

Matches any CHAR except CTLs or separators.

uri_all

Matches all URI characters.

uri_fragment

Matches URI fragment characters.

uri_path

Matches URI path characters (not the query or the fragment parts).

uri_query

Matches URI query characters.

uri_scheme

Matches URI scheme characters.

uri_segment

Matches URI segment characters.

uri_unreserved

Matches unreserved URI characters.

word

Matches all alphabetical and digital characters plus the underscore.

6.10 Routing reference

6.10.1 Basic syntax rules

As mentioned elsewhere, the routing configuration syntax is essentially a program written in the Groovy language.

However, don't let that scare you away with the thought of having to learn yet another language, since you get can a long way without knowing Groovy.

You can pick up the syntax by looking at some examples, such as this:

builder.router {

   restlet(uri: "/helloworld1", ofClass: "org.mycomp.HelloWorld1")

   restlet(uri: "/hello/world2", ofClass: org.mycomp.HelloWorld2")

   router(uri: "/hello") {
     restlet(uri: "/world3", ofClass: org.mycomp.HelloWorld3")
   }
}

In case you're wondering, this example will react on URIs starting with:

/helloworld1
/hello/world2
/hello/world3

From this example you can see the basic rules:

6.10.2 Setting generic properties on routing components

The documentation of the individual routing components describes the parameters supported by those components. Besides what is documented, the system will automatically try to call a setter method on the routing component for any other parameters you specify.

For example, if you would have a look at the API documentation of Restlet's Router class, you would see it has the following setter method:

public void setRetryDelay(long retryDelay)

You can set this parameter as follows:

builder.router(retryDelay: 50) {
    [...]
}

In general, most of the commonly useful parameters can be found in Kauri's documentation, so you only need to know this for advanced usage.

6.10.3 Variables available in the script

[TODO]

moduleContext: the Restlet context of the Kauri module.

confRegistry: the ConfRegistry associated to the module. (see Configuration )

inSourceMode: a boolean indicating if the module in which the routing is created was loaded in source mode or not.

6.10.4 Advanced things

Since the router configuration is Groovy code, you can write any control structures in it as you like. We advise however to keep the routing configuration as close to static data as possible. This will make it easier to understand for users with no or less knowledge about Groovy.

But just for fun and general knowledge, let us look at some examples.

The following example will create 10 restlets attached to 10 different URIs on the router: "/helloworld0", "/helloworld1", ..., "/helloworld9". The loop is executed during the building of the routing structure, thus not during actual routing.

builder.router {
    10.times { i ->
        restletRoute = restlet(uri: "/helloworld" + i,
                               handle: { request, response ->
            response.setEntity("Hello world from inside the router " + i,
                                mediaType.TEXT_PLAIN)
        })
    }
}

The following example shows two things: the currently constructed component is available inside its following {} part as a variable named current, and it shows how to print things to the console. Again, the print is executed only once, during the building of the routing structure.

builder.router {
     print("The current routing component is: ${current}")
}

6.11 Common parameters

The following parameters are supported by many of the routing  components.

Name

Description

ofClass

Specifies a fully qualified class name of an object to create (e.g. a restlet, filter, resource, ...). The class will be instantiated by the Spring container, so supports auto-wiring annotations.

ofBean

Specifies the ID of a bean in the Spring container. This can be used instead of ofClass.

postAttach

Applies to components nested in routers. See the router documentation for more details.

uri

match

autoAttach

Surprisingly, this won't do something with a car, but rather is a boolean that can be used to disable the automatic attaching to a router of the components nested within it.

6.12 challenge

You should use Kauri Security rather than this challenge mechanism for more complex use-cases.

'challenge' creates a Restlet ChallengeAuthenticator, which is a special purpose filter.

Name

Description

realm

Realm to send in HTTP Basic and HTTP Digest challenges.

scheme

Authentication scheme to use.

verifier

The verifier to use (implementation of org.restlet.security.Verifier)

Syntax / Examples

Protect a single resource:

import org.restlet.data.ChallengeScheme;
import org.restlet.security.MapVerifier;

builder.router {

    def verifier = new MapVerifier();
    verifier.localSecrets.put("scott", "tiger".toCharArray());

    def chlng = challenge(
      uri:"",
      scheme:ChallengeScheme.HTTP_BASIC,
      realm:"Restlet Tutorials",
      verifier: verifier);

    chlng.next = router() {
          uri: "/",
          match: "equals",
          data: "module:/resources/greeting.json",
          template: "module:/templates/index.xml",
          mediaType: "text/html"
    )
}

Protect multiple resources (a TemplateRestlet at "/" and a DirectoryResource at "/resources")

import org.restlet.data.ChallengeScheme;
import org.restlet.security.MapVerifier;

builder.router {

    def verifier = new MapVerifier();
    verifier.localSecrets.put("scott", "tiger".toCharArray());

    def chlng = challenge(
      uri:"",
      scheme:ChallengeScheme.HTTP_BASIC,
      realm:"Restlet Tutorials",
      verifier: verifier);

    chlng.next = router() {
        template( // The home page
          uri: "/",
          match: "equals",
          data: "module:/resources/greeting.json",
          template: "module:/templates/index.xml",
          mediaType: "text/html"
        )

        directory(uri: "/resources", root: "module:/resources/")
    }
}

Avoid hardcoding the secrets (still bad, we still use plaintext passwords)

import org.restlet.data.ChallengeScheme;
import org.restlet.data.ChallengeScheme;
import org.restlet.security.MapVerifier;

builder.router {

    def verifier = new MapVerifier();
    def accounts = new Properties();
    accounts.load(new FileInputStream("/tmp/accounts.properties"));
    for (String key: accounts.key) {
       verifier.localSecrets.put(key, accounts.getProperty(key).toCharArray());
    }

    def chlng = challenge(
      uri:"",
      scheme:ChallengeScheme.HTTP_BASIC,
      realm:"Restlet Tutorials",
      verifier: verifier);

    chlng.next = router() {
        //...
    }
}

6.13 directory

'directory' creates an org.restlet.Directory, which is a static file server. It supports content negotiation and directory listings.

Parameters

Name

Description

root

The root of the directory, specified as URI. Access to resources in upper directories (using ../) is prevented.

Examples:

file:///etc
module:/resources  (-> files in the KAURI-INF/resources
                    directory in the module archive)
Example
router {
  directory(uri: "/resources", root: "module:/resources/")
}

6.14 filter

'filter' is used to create an org.restlet.Filter. A filter delegates request handling to another routing component, but can do something before and after delegating the request.

Filters are ideal for initializing some context needed by anything further down the URI space, to check authentication or authorization, to customize error handling, etc.

Parameters

Name

Description

after

Closure implementing the Filter.afterHandle method. (see Restlet API docs for details).

before

Closure implementing the Filter.beforeHandle method.

handle

Closure implementing the Filter.doHandle method.

Syntax

For a filter implemented in Java:

filter (ofClass: "my.package.MyFilter") {
 
    [... nest exactly one other component ...]

}

For a filter implemented directly in the router:

import org.restlet.routing.Filter

[...]

filter(uri: "",
       before : { request, response ->
          println("Going through a filter");
          return Filter.CONTINUE;
       }) {

    [... nest exactly one other component ...]

}

The nested component can be any other kind of routing component (= any kind of Restlet), including a router or another filter.

This example filters all requests for "/admin" to check authentication information:

import org.restlet.routing.Filter

[...]

builder.router {

    filter(uri: "/admin",
           before : { request, response ->
              // TODO implement authentication check
              return Filter.CONTINUE;
           }) {

        router {
            resource(uri: "/adminPage1", ofClass: "my.package.AdminPage1")
            resource(uri: "/adminPage2", ofClass: "my.package.AdminPage1")
        }
}

For authentication purposes, there is a pre-made challenge filter.

6.15 jaxRs

'jaxRs' creates a JAX-RS subsystem, which handles requests (routing and response representation production) based on JAX-RS annotated classes.

The JAX-RS resource classes and provider classes can be listed manually, or can be auto-scanned from your module. Groovy-based JAX-RS classes are also supported.

See also JAX-RS first steps.

Syntax
jaxRs(uri: "") {

   jaxRsResource(ofClass: "fully.qualified.ClassName")
   jaxRsResource(scanPackages: ["my.package1", "my.package2])

   jaxRsProvider(ofClass: "fully.qualified.ClassName")
   jaxRsProvider(scanPackages: ["my.package1", "my.package2])

   jaxRsGroovyScripts(path: "groovy-jax-rs")
}

The nested elements specify the various resource and provider classes to use. You can repeat the jaxRsResource and jaxRsProvider as many times as needed.

You can specify classes manually by using the ofClass parameter:

jaxRs(uri: "") {
    jaxRsResource(ofClass: "my.package.Resource1")
    jaxRsResource(ofClass: "my.package.Resource2")
    jaxRsResource(ofClass: "my.package.Resource3")
}

Alternatively, you can let the system scan packages (non-recursively) for JAX-RS classes using the scanPackages parameter which takes one string or a list of string as parameters. By specifying the value "*' for scanPackages, the complete module jar will be scanned:

jaxRs(uri: "") {
  jaxRsResource(scanPackages: "*")
}

Note that class scanning is limited to classes within the module jar. If there are JAX-RS classes within the module's classpath, they will hence need to be listed manually (which is best anyway to avoid suprise-resources).

Using jaxRsGroovyScripts you can specify a (= one) path containing Groovy-implemented resource classes. The Groovy files should follow the rules for being loadable by the Groovy ClassLoader, basically meaning they should have '.groovy' as extension and the filename should correspond to the class name.

Note that Groovy files which are compiled as part of building your module are simply supported the same as regular classes, the jaxRsGroovyScripts element is only for runtime compiled code.

When running in source mode, the Groovy directory will be watched for changes so that the JAX-RS system will be recreated.

The uri specifies on which path to mount the JAX-RS resources. See the  router documentation for more details. Consider the following configuration (with BarResource having a @Path("bar") annotation):

jaxRs(uri: "foo") {
    jaxRsResource(ofClass: "my.package.BarResource")
}

Because the "start" matching mode will be used, both foo/bar and foobar will match the above uri-template. You can easily avoid the second match by adding a slash to the uri:

jaxRs(uri: "foo/") {
    jaxRsResource(ofClass: "my.package.BarResource")
}
Debug

In case you're wondering if the JAX-RS system has found your classes, you can enable the debug output for the JAX-RS component by adding the following options when starting Kauri:

-l debug -m org.kauriproject.routing

The most common mistake is forgetting the required annotations: for a GET request, the class needs to have at least the @Path annotation, and one method with @GET and @Produces.

JAX-RS @Path should not start with a slash, the jaxRs router should be mounted on a path ending with slash

While this is not specific to JAX-RS, it might be helpful to repeat it here anyway:

The reason for this is that otherwise the URIs constructed by JAX-RS would start with a slash, and hence be absolute. This gives problems constructing correct response URIs (e.g. the Location header).

To give a bad example: suppose the @Path annotation of a resource class is "/bar", and the jaxRs router is mounted on "foo", giving a base URI (in Rest: Request.resourceRef.baseRef) of http://localhost/foo. Combining both would give http://locahost/bar, not the expected http://localhost/foo/bar, because /bar is absolute and thus replaces the existing path.

6.16 mode

'mode' creates a filter which passes execution on to the next (= nested) component depending on what Runtime mode is enabled.

Syntax
mode(when: "...") {
  [nested component]
}

The when parameter can contain a comma-separated list of runtime mode names for which the execution should continue.

Valid mode names are: prototype, production.

The special value "all" is used to denote the set of all modes. This is useful in combination with the ability to substract modes by adding a minus in front of them. For example:

mode(when: "all,-prototype") {
  [nested component]
}

This mode filter will pass on execution for all modes but the prototype mode.

If the current Kauri Runtime mode does not match the modes in the list, then the filter will set a status of "404 Not Found" on the response, as well as the special response attribute necessary for the passThrough-feature of the router, these features together allow to activate different components depending on the current mode.

Example

Below is an example taken from a testcase.

Since the mode is a routing component like any other, it needs a uri attribute to attach it to the containing router.

builder.router {
    mode(uri: "", passThrough: true, when: "prototype") {
        pages(root: "/site/pages", ignore: ".svn CVS ignorethis")
    }

    resource(uri: "/person/{id}.html",
       ofClass: "org.kauriproject.routing.test.testmodules.routing2.PersonResource")

    mode(uri: "", when: "all,-prototype") {
        pages(root: "/site/pages")
    }
}

6.17 pages

'pages' creates a component which, based on a file system directory, offers the following functionality:

This might sound complicated, but is actually very easy to use.

An example will make this more obvious. You can have a file system structure like this:

/person/{name}.html
/person/{name}-edit.html
/persons.html

Yes, you see that right: we use the { and } characters within file names.

The pages component will build a standard Restlet router based on this file structure, the file paths are actually directly usable as URI templates.

The files are treated as templates which are executed 'as is', without first going through a controller. To pull data into the templates, you can use the variable instruction with src attribute. The {variables} from the path are accessible in the template using ${request.attributes.name}.

With the pages component, we don't want to promote "Model 1"-style development, but this component gives extra power to people wireframing or prototyping a web front-end.

The template output is usually serialized as HTML, except if the URI path ends on ".xml", in which case it is serialized as XML.

Syntax

The basic syntax is this:

builder.router {
  pages(uri: "", root: "pages")
}

The root parameter specifies a directory, below KAURI-INF, to be used as root for the filesystem-based routing. This cannot be an arbitrary URI. If you run the application in source mode, changes are automatically picked up without restart.

Optionally, you can specify a parameter 'ignore' containing a space-separated list of file names to ignore, in this star (*) can be used as a wildcard. If not specified, default excludes are used, among which .svn, CVS, .DS_Store, ...

Double extensions

In some cases you might want files to have a different extension on the filesystem and the URI space (because of application-associations), or to have no extension at all in the URI space, while still having an extension on the file system.

We allow to do this using double extensions. Some examples will make this clear:

Filesystem path             URI path
/person/{id}.html.xml       /person/{id}.html
/person/{id}..xml           /person/{id}
index.html

URI paths ending on /index.html are also automatically assoicated with the same URI without "index.html".

6.18 read

'read' is a shortcut to create a Restlet which reads a resource.

Parameters

Name

Description

source

The URL from which to read data to return to the client. This is an URI template.

mediaType

optional, allows to change the response media type to something else. Its value should be a Restlet MediaType object. Example: mediaType.TEXT_PLAIN or mediaType.TEXT_HTML

Example
read(uri: "/resources/{path}", source: "module:/resources/{path}",
     postAttach : { route ->
         Variable variable = new Variable(Variable.TYPE_URI_PATH, "", true, false)
         route.getTemplate().getVariables().put("path", variable)
     })

6.19 redirector

'redirector' creates an org.restlet.Redirector, whose purpose is to create a redirect response.

Parameters

Name

Description

mode

One of:
redirectorMode.MODE_CLIENT_PERMANENT (301)
redirectorMode.MODE_CLIENT_FOUND (302)
redirectorMode.MODE_CLIENT_SEE_OTHER (303)
redirectorMode.MODE_CLIENT_TEMPORARY (307)
redirectorMode.MODE_DISPATCHER (= Restlet internal redirect)

targetTemplate

A URI template to define the URI to redirect to.

Which redirect-mode to use?

Good question.

Traditional redirects as done by servlets typically result in a 302 response, though 303 and 307 are usually better choices. See resources such as the RWS book for a detailed treatment.

Variables availabe in the targetTemplate

The variables are resolved in the following order:

Allowed redirect-locations

The resolved targetTemplate will end up as the Location: header in the HTTP response.  In actual responses over the wire this always needs to be an absolute URI (including scheme and host!), but for convenience the kauri runtime will help out making correct absolute public URIs based for:

(This is similar to the  URI Resolving in the templates)

Examples
builder.router {
    redirector(uri: "/redirect-me",
               mode: redirectorMode.MODE_CLIENT_TEMPORARY,
               targetTemplate: "http://www.google.com/search?q=linkto:{ri}")
}

The {ri} variable in this example returns the resource identifier, basically the complete request URI.

So suppose the router is mounted such that the following request addresses the redirector:

http://localhost:8888/myrouter/redirect-me

Then the client would be redirected to:

http://www.google.com/search?q=linkto:http://localhost:8888/myrouter/redirect-me

6.20 resource

'resource' is used for adding subclasses of org.restlet.resource.Resource to the routing.

Both org.restlet.resource.Resource and org.restlet.Restlet (as supported by the restlet routing instruction) allow to implement code to handle a request. Resource is different from Restlet in that it is:

Typically the Restlet class will be used for more system/infrastructure-level work, while the Resource class should be used for everyday resource implementation work. An alternative for Resource is the JAX-RS API.

Parameters

(There are parameters available to implement resources inline in the routing using closures, but we recommend using ofClass/ofBean instead)

Example

The following example of a Resource implementation is stolen from the Restlet project:

package org.restlet.example.book.restlet.ch4;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.ResourceException;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;

public class HelloWorldResource extends Resource {

    public HelloWorldResource() {
        // A default constructor is required in this case.
    }

    public void init(Context context, Request request,Response response) {
        super.init(context, request, response);
        // Declare all kind of representations supported by the resource
        getVariants().add(new Variant(MediaType.TEXT_PLAIN));
    }

    @Override
    public Representation represent(Variant variant) throws ResourceException {
        Representation representation = null;
        // Generate the right representation according to the variant.
        if (MediaType.TEXT_PLAIN.equals(variant.getMediaType())) {
            representation = new StringRepresentation("hello, world",
                    MediaType.TEXT_PLAIN);
        }
        return representation;
    }
}

It is attached to a router as follows:

router {
  resource(uri: "/helloworld",
           ofClass: "org.restlet.example.book.restlet.ch4.HelloWorldResource")
}

6.21 restlet

'restlet' is used to create any type of org.restlet.Restlet. You can refer to classes, to Spring beans or implement a Restlet inline using a closure.

You should also consider using resource.

Parameters

Name

Description

handle

Closure implementing the Restlet.handle() method.

Syntax

A Restlet implemented inline:

...
    restlet(uri: "/helloworld", handle: { request, response ->
        response.setEntity("Hello world from inside the router", mediaType.TEXT_PLAIN)
    })
...

A Restlet implemented in Java:

...
    restlet(uri: "/helloworld", ofClass: "com.mycompany.MyRestlet")
...

Just one instance of this Restlet class will be created, the instantiation is delegated to Spring so things like autowiring annotations will work.

6.22 router

'router' creates an org.restlet.Router. This is the central part of the whole router configuration.

The components created by the other routing configuration elements are usually attached to a Router. An exception is that components can also be attached as delegate to a filter.

When attaching a component to a router, certain parameters can be specified, most importantly the URI, as shown in this example which creates a router with two resources attached to it:

builder.router {
    resource(uri: "/user/{name}", ofClass: "mystuff.UserResource")
    resource(uri: "/order/{orderId}", ofClass: "mystuff.OrderResource")
}

The uri parameter of the resources is not an attribute for the resources themselves, but for attaching the resource to the router. So certain parts of the router-related configuration are specified on the components nested inside the router. The main reason for explaining this is because this part of the configuration will be discussed here, rather than repeating it for each component.

By default, a router will match URI patterns in "starts" mode. This means the URI pattern will match for a given request URI if the request URI starts with the URI pattern. So a request URI of "/fooxyz" will be matched by the URI pattern "/foo". The matching mode can be changed for the router as a whole or for each individual route of a router. For the above example, it is better to change the match mode to "equals", like this:

builder.router(match: "equals") {
    resource(uri: "/user/{name}", ofClass: "mystuff.UserResource")
    resource(uri: "/order/{orderId}", ofClass: "mystuff.OrderResource")
}
Parameters for the router itself

Name

Description

type

The kind of router to create. Supported values:

  • "restlet": creates a normal Restlet Router.
  • "kauri": creates a Kauri-specific subclass of the Restlet Router, which has some specific behavior and functionality.

The default is "kauri".

routingMode

This parameter only applies when the router type is set to restlet. When the router type is kauri, it is always the first matching pattern which is used.

Set this to one of: routingMode.BEST|CUSTOM|FIRST|LAST|NEXT|RANDOM

match

Sets the default matching mode for all Routes within this Router. Its value can be the string "equals" or "start". The default is "start". This can be overridden for each individual Route.

todo: explain more is possible, see Restlet docs for full details.

Parameters for components attached to a router

The following are parameters which can be supplied to any sort of component attached to a router.

Name

Description

uri

A URI pattern, in URI template syntax. See URI template syntax.

postAttach

A closure which will be executed after the component has been attached by the router. See detailed explanation below.

match

Sets the matching mode for this router. Its value can be the string "equals" or "start". The default is "start", though this default can be overridden by adding a match parameter on the router, see above.

passThrough

This parameter only applies when the router type is kauri.

If this boolean parameter is set to true (default is false) and after the attached restlet has been called the response is "404 Not Found" and additionally the response carries an indication that the 404 is because the URI pattern is not recognized, then the router will continue the matching process with the routes that follow the current one, in sequence.

The "special indication" is a response attribute org.kauriproject.routing.no_route with as value Boolean.TRUE. Various components created through the routing config support this: router, jaxRs, mode.

This feature can be useful when the attached restlets perform (some sort of) routing themselves. For example, the following snippet delegates all requests to JAX-RS, and if there was no resource class to handle the request, goes on matching the routes that follow it.

router {
  jaxRs(uri: "", passThrough: true)

  pages(uri: "", root: "pages")
}
Fine-grained configuration via postAttach

Attaching a component to a router creates a Route object, via this Route object various options can be set. In the routing configuration, this can be done by specifying a closure via the postAttach parameter. The name postAttach comes from the fact that it is a closure which will be called after (= post) the attaching of the component to the router. The closure takes one argument, the Route instance.

One of the more interesting things which can be done via postAttach is setting options on the Template contained in the Route. The Template object represents the URI template expression.

As an example, see this illustration from the read component:

read(uri: "/resources/{path}", source: "module:/resources/{path}",
     postAttach : { route ->
         Variable variable = new Variable(Variable.TYPE_URI_PATH, "", true, false)
         route.getTemplate().getVariables().put("path", variable)
     })

For full information on all the capabilities, see the Restlet API documentation: Route class, Template class, Variable class.

6.23 template

'template' is a shortcut to create a Restlet which will execute a Kauri template, optionally passing it the data retrieved from a certain URL.

To use the template instruction, you need to pass a template service implementation when constructing the router. If you're not sure this is already the case, then see here.

IMPORTANT WARNING: there's some chance that this class will be removed in the near future to replace it by a more powerful system to support wireframe-based application prototyping.

Parameters

Name

Description

template

The URL from which to read the template. This is a URI template.

mediaType

The mediaType to send in the response. Default is text/xml.

data

The URL from which to read the data. This is a URI template. This is optional.
The data should be a JSON file.
The data will be made available to the template as a context attribute "data".

dataMediaType

The mediaType for the data. If the data URL would not return a correct media type and you don't control the called service, then you can override the media type using this parameter.

Example
template(uri: "/template/{templateId}", template: "module:/templates/{templateId}.xml",
         mediaType: "text/html", data: "module:/templates/{templateId}.json")

6.24 Routing module

6.24.1 Introduction

In Routing first steps you could read how to introduce the routing module in your wiring.xml and import its RoutingService in your own module. The remainder of the documentation is mainly about the Groovy-based router configuration syntax. There are few things which can be interesting about the module itself though.

6.24.2 Routing configuration options

When constructing the router, you can pass a RoutingConfig instance on which you can set various optional properties.

The below snippet shows all the options. You only need to set those properties which you are interested to change.

<bean id="router" factory-bean="routingService" factory-method="createRouter">
  <constructor-arg ref="restletContext"/>
  <constructor-arg ref="module"/>
  <constructor-arg>
    <bean class="org.kauriproject.routing.RoutingConfig">
      <!-- The location of the Groovy router configuration.
           The specified location should be a path somewhere
           below KAURI-INF, using arbitrary URIs is not possible. -->
      <property name="configPath" value="myrouter.groovy"/>

      <!-- If the router configuration file is not found, should the
           built-in default be used instead? If not, an exception will
           be thrown. -->
      <property name="fallBackToDefault" value="true|false"/>

      <!-- Some routing instructions need a template service in order to
           perform their work. In that case, you need to supply it using
           this property. -->
      <property name="templateService" ref="templateService"/>

      <!-- Provide custom factories for the routing language
           implementation. This allows to extend the routing config
           with your own instructions. -->
      <property name="customFactories">
        <map>
          <entry key="myinstruction" ref="..."/>
        </map>
      </property>
    </bean>
</bean>

6.24.3 Step by step: supplying a template engine to the routing

Assuming you are already using routing in your module, but the router has no access to the template engine yet, then here you can find how to set this up.

Make sure you have the template module declared in your project's wiring.xml (if it's already there, then skip this step):

<artifact id="templateModule" groupId="org.kauriproject" artifactId="kauri-template-service-impl"/>

In the spring container of your module, import the template service using kauri:import-service (again, if it's already there, skip this step):

<kauri:import-service id="templateService"
                      service="org.kauriproject.template.service.TemplateService"/>

When constructing the router, pass the templateService via the RoutingConfig.

<bean id="router" factory-bean="routingService" factory-method="createRouter">
  <constructor-arg ref="restletContext"/>
  <constructor-arg ref="module"/>
  <constructor-arg>
    <bean class="org.kauriproject.routing.RoutingConfig">
      <property name="templateService" ref="templateService"/>
    </bean>
  </constructor-arg>
</bean>

6.24.4 Multiple routers in one module

Since you can specify alternative routing configuration file locations, as explained above, it can make sense to create multiple routers. This can be done by creating multiple router beans and exporting them as multiple restservices, which is obvious if you know a bit of Spring.

6.24.5 Extending the routing DSL

It is possible to extend the routing DSL (= domain specific language) with your own elements.

[Not sure if we should document this in more detail since this might lead to a proliferation of the routing language.]

7 Representation builder

7.1 What is a representation

Kauri has a flexible system for producing resource representations. For developers familiar with other frameworks, this is similar to what is often called the "view", the V in the MVC pattern.

Here is a nice description of what a representation is:

"REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components. A representation is a sequence of bytes, plus representation metadata to describe those bytes. Other commonly used but less precise names for a representation include: document, file, and HTTP message entity, instance, or variant." (Fielding)

So for example, a representation is both the HTML page transferred to your browser when doing a GET request, as well as the body of a form posted towards the server.

The representation builder system described here focuses on the production of representations served towards the client, and not handling of representations submitted towards the server.

7.2 The need for a representation builder module

7.2.1 Moving the mechanics of representation production out of resource classes

In the core Restlet API, a resource class is responsible for creating the response representation and setting it on the response object. This is done by creating an instance of a subclass of Representation.

For very simple and very complex cases, it makes sense to do this directly in the resource class. In a typical web application, you will often produce representations using a template. In Kauri, this means the resource class should have a handle to (= dependency on) the TemplateService and use that to create a TemplateRepresentation.

This works just fine. However, it is a very 'manual', hardcoded and somewhat laborious way of constructing the representation. It would be easier if the resource class only needs to return a logical representation name and the data objects. The mapping of the logical name to the real implementation can then be done somewhere else, outside of the concern of the resource class. And this is exactly what Kauri's representation module provides.

For people familiar with Spring MVC, this is similar to the ModelAndView and the ViewResolver. For people familiar with Apache Cocoon, this is similar to the sendPage call. For people familiar with JAX-RS, this is somewhat the same role as the MessageBodyWriter providers.

7.2.2 Creating representations in case of errors and exceptions

Resource classes may throw (runtime) exceptions or set an error response status without specifying a body. See also the section on error handling.

The representation builder will catch all throwables and set an error response status code and response body.

In case an error response status is set, but no response body is present, the representation builder can create the response body.

For both cases, the response to be created is configurable.

7.3 First steps

7.3.1 Adding the module

This part needs to be done once for your project. If you have generated a project using the archetype, this will already be in-place.

7.3.1.1 Add the representation builder module to wiring.xml

In your wiring.xml file, add the following module inside the <modules> element, before any other modules where you want to make use of the representation builder.

<artifact id="representation-builder"
          groupId="org.kauriproject"
          artifactId="kauri-representationbuilder-impl"/>

7.3.1.2 Import representation builder in your module and install it

Edit your module's Spring XML configuration, which can be found in the KAURI-INF/spring directory.

If it is not the case already, add a kauri:module tag somewhere in it. If you have already a kauri:module tag, make sure it contains at least the attribute listed below.

<kauri:module handle="module"/>

Add the following tags, which import the RepresentationBuilder service (which is supplied by the kauri-representationbuilder-impl module) and installs it in the current module.

<kauri:import-service id="representationBuilder"
                      service="org.kauriproject.representation.build.RepresentationBuilder"/>
<bean factory-bean="representationBuilder" factory-method="install">
  <constructor-arg ref="module"/>
</bean>

7.3.2 Making use of the representation builder

To make use of the representation builder, you need to do two things:

  1. in a resource class, create a KauriRepresentation instance containing a logical name identifying the representation and the data objects necessary to produce the representation
  2. configure the representation builder so that this logical name is resolved to an actual representation.

7.3.2.1 Creating a KauriRepresentation instance

If your resource class is implemented using the core Restlet API, then you need to create the instance and either:

Here's an example of the second case:

import org.kauriproject.representation.build.KauriRepresentation;

...

    public Representation represent(Variant variant) throws ResourceException {
        Representation representation = null;
        if (MediaType.TEXT_PLAIN.equals(variant.getMediaType())) {
            Map<String, Object> reprData = new HashMap<String, Object>();
            reprData.put("message", "Hello world!");
            return new KauriRepresentation("helloworld", reprData);
        }
        return representation;
    }

If your resource class is implemented using the JAX-RS API, then you can simply return a KauriRepresentation instance:

import org.kauriproject.representation.build.KauriRepresentation;

...

    @GET
    public KauriRepresentation get() {
        Map<String, Object> reprData = new HashMap<String, Object>();
        reprData.put("message", "Hello world!");
        return new KauriRepresentation("helloworld", reprData);
    }

7.3.2.2 Configure logical name to actual representation mapping

In case you don't create a specific configuration, there is a default mapping which will map the logical name to a template file name.

For the above examples, helloworld is used as the logical name, and will result in the template module:/templates/helloworld.xml to be used.

If you want to customize the mapping, or make use of non-template based representations, you will need to create a custom configuration.

7.4 Some background

TODO [explain use of filter + little diagram of where the filter fits in]

7.5 Default configuration

When you use the representation builder in a module without specifying a custom location for the configuration, it will be searched at KAURI-INF/representations.groovy. If this file does not exist, a default built-in configuration will be used as fallback, which is the following:

builder.representations {
    select {
        when(name: "{name,all}") {
            template(src: "module:/templates/{name}.xml")
        }
    }

    exceptions {
        exception {
            template(src: "clap://thread/org/kauriproject/representation/defaulterrorpage.xml")            
        }
    }

    errors {
        error {
            template(src: "clap://thread/org/kauriproject/representation/defaulterrorpage.xml");
        }
    }
}

This default configuration will try to map the logical representation name to a template file in KAURI-INF/templates. In case of an exception or an error status, a built-in template will be used to generate an error page.

7.6 Configuration reference

7.6.1 Overview

7.6.1.1 Location of the configuration file

The default location for the configuration file is KAURI-INF/representations.groovy. In the Maven source tree layout, this is at src/main/kauri/representations.groovy.

If you do not have such a configuration file, it suffices to create it and it will be automatically used. If you are running in source mode, this change will be picked up immediately, if you're not running in source mode you need to rebuild the module and restart Kauri.

7.6.1.2 Syntax

The configuration file is a Groovy program, using the GroovyBuilder pattern. This is the same as for the routing. The routing documentation contains details on motivation and basic syntax information. However, everything you need to know for normal usage can be found below.

7.6.1.3 Examples

Below you'll find the basic reference information. To see examples of how this all fits together, check out the samples included with Kauri.

7.6.2 Basic structure

The configuration consists of three sections:

  1. A section for mapping logical representation names to actual representations.
  2. A section for mapping exception classes to representations.
  3. A section for mapping error status codes to representations.

This is the minimal structure containing the placeholders for those three sections:

builder.representations {
    select {
    }

    exceptions {
    }

    errors {
    }
}

7.6.3 Mapping logical representation names to representations

The basic tool for this mapping is a switch-structure using 'select' and 'when' as the syntactic elements:

select {
  when(name: "foo") {
    template(src: "module:/templates/foo.xml")
  }

  when(name: "bar", mediaType: "text/html") {
    template(src: "module:/templates/bar.xml")
  }

  when(name: "something/{remainder,all}") {
    select {
      when(name: "something/A/B/C") {
        template(src: "module:/templates/A.xml")
      }

      when(name: "something/X/Y/Z") {
        template(src: "module:/templates/X.xml")
      }
    }
  }
}

Here is everything you need to know about the 'when' node:

A 'when' node should contain exactly one child node, which can be:

It is not invalid for a when node to contain no child, but it won't do anything meaningful either, the matching process will continue with the next when node.

7.6.4 Mapping exceptions to representations

For mapping exceptions to an appropriate representation, a selection process based on the exception class name is available. Here is some example syntax:

exceptions {
  exception(classes: ["my.company.WrapperException"], unroll: true)

  exception(classes: ["my.company.FooException", "my.company.BarException"]) {
    template(src: "module:/templates/error_not_found.xml", statusCode: 404)
  }

  exception {
    template(src: "module:/templates/error.xml", statusCode: 500);
  }
}

The matching works as follows:

  1. The system runs over the exception nodes. If its classes parameter lists a class which is the same as the exception class, or a superclass thereof (= instanceof check), then the exception node matches. An exception node with no (or an empty) classes parameter will always match, except when searching for causes (see step 2).
  2. If the exception node matches and has an "unroll: true" parameter, the system will get the cause of the exception (= the first nested exception), if it exists, and go back to step (1). If there is no cause, or the handling for the cause didn't return anything, processing will continue here.
  3. If the exception node matches and has a child element specifying the representation to create, then that will be the representation used.
  4. If the exception node matches and has no child element, then the system moves on to the next exception node.

7.6.5 Mapping error status codes to representations

This mapping is very straightforward: it maps a status code or a list of status codes to a representation.

errors(overwrite: false) {
    error(status: 404) {
        template(src: "module:/templates/error_not_found.xml")
    }

    error(status: 500..599) {
        template(src: "module:/templates/server_error.xml")
    }

    error {
        template(src: "module:/templates/error.xml")
    }
}

The matching rules are as follows:

The errors node can have an optional attribute 'overwrite', indicating that error responses should always be overwritten with the representations configured here. By default this is false, thus if there is already a response representation present, it will be left untouched.

The representations used inside error { } should not carry a statusCode parameter, so it is disallowed to override the status code.

7.6.6 Multiple formats for exceptions and errors

Sometimes you might want exception and error responses to be formatted differently depending on who makes the request: if it is an Ajax call, an error response formatted as JSON will likely be preferred over a human-oriented HTML error page.

When a module contains only resources intended for use in Ajax calls or only resources intended for human display, you can always format exceptions and errors in the same way.

But when the resources might be accessed in different ways, it is more useful to let the client specify how it wants errors to be formatted. This format is not necessarily related to the format requested: an Ajax call might retrieve a blurb of HTML but still want an error formatted as JSON.

This client-specified error and exception formatting is possible by having multiple exceptions and errors sections in the configuration, carrying a media attribute.

/* This exception section will be used when the client does not specify a preferred format */
exceptions {
}

exceptions(media: "json") {
}

errors {
}

errors(media: "json") {
}

The client can specify the requested format (media) in two ways:

The representation builder will then use the matching exceptions/errors section.

7.6.7 Representations

To create an actual representation, a few built-in solutions are available, and a way to refer to your own classes to create the representation.

7.6.7.1 template

This creates a template representation, the most common way of producing an HTML or XML response. This uses Kauri's template engine.

Syntax:

template(src: "uri")

The src parameter specifies the template file location, typically this will be a URI using the module protocol such as module:/templates/foo.xml

7.6.7.2 resource

This creates a representation which returns a static resource.

Syntax:

resource(src: "uri")

7.6.7.3 custom

This allows to use your own code to create the representation.

Syntax:

custom(ofClass: "fully qualified class name")
custom(ofBean: "spring bean name")

You can either specify a class or refer to a bean in the Spring container by name. Either way, the resulting object should implement the interface org.kauriproject.representation.RepresentationFactory. See its javadoc for more information.

7.6.7.4 json

Formats an exception or error as json. This should only be used in the exceptions or errors sections.

Syntax:

jsonStatus(statusCode: 500)

The output produced is of the following kind:

{
  status: "(HTTP status code)",
  description: "",
  throwable: {
    message: "(exception message)",
    type: "(exception fully qualified class name)",
    stackTrace: [
      {class: "...", method: "...", native: true|false, file: "...", line: number}
    ],
    cause: { (nested throwable description) }
  }
}

The description and throwable will only be present when available.

7.6.7.5 Reusing matched values

In the src attributes of the template and resource representations, you can refer to match values from the when nodes, using URI template syntax.

Example:

    select {
        when(name: "{name,all}") {
            template(src: "module:/templates/{name}.xml")
        }
    }

If you have nested select's, you can use "../" syntax to walk up in the select node stack.

7.6.7.6 Common syntax

On each representation-creating node, you can use the following optional parameters.

Name

Description

statusCode

an integer, specifying the HTTP status code for the response. For normal representations this is by default 200, for exceptions this is by default 500.

mediaType

the media type for the response. (todo: behavior and defaults depend on representation implementation)

8 Templates

8.1 Introduction

Kauri has its own template engine. It has the usual things you can expect from a template engine, both towards the user as towards the developer (e.g. template pre-compilation).

Unique about Kauri's template engine is that it is XML-based, which has the advantage of providing guaranteed XML/HTML well-formed output, avoidance of HTML-injection, performant XML-pipeline processing of the template output, and abstraction of some HTML serialization rules (e.g. close tag required for <script>).

The default expression language is EL, as implemented by JUEL. For those cases where you need to do something more powerful, you can use Groovy.

The Kauri template engine is a stand-alone library, which can be easily used in other projects without pulling in all of Kauri.

8.2 Template features

The Kauri template engine is still under construction, so not all expected features are already implemented. You can get an overview of the features here, including their current state and an indication of the importance we have given it. Using our mailinglist or issue tracker, you are invited to do feature requests in case we have missed something, or convince us that we should give higher priority to a certain feature. Contributions are also welcome.

8.3 Usage

8.3.1 Using templating in Kauri

The integration of the template engine within Kauri is offered by the kauri-template-service-[api|impl] modules.

Normal usage

For normal usage scenario's, you will not use the template-service immediately, but rather make use of the representation builder. If you generated a project using an archetype, this will already be configured for you, and you can simply use it as shown in this hello world sample.

Calling template-service immediately

If you are in a situation where you can't or don't want to make use of the representation builder, you can call the template-service immediately.

Add the template-service in the kauri.xml. If you are already using the template service via the representation builder, this will already be present:

<artifact id="templateModule" groupId="org.kauriproject" artifactId="kauri-template-service-impl"/>

Add a dependency to kauri-template-service-api to your module's pom.xml:

    <dependency>
        <groupId>org.kauriproject</groupId>
        <artifactId>kauri-template-service-api</artifactId>
        <version>${version.kauri}</version>
    </dependency>

Import the template service in your module's Spring config:

<kauri:import-service id="templateService" service="org.kauriproject.template.service.TemplateService"/>

Now you can pass this bean to your own classes to use the TemplateService.

8.3.2 Using templating from CLI

You can use it in CLI mode: java DefaultTemplateService <templateLocation> [var=value [var2=value2 [...]]]

For example:

java -cp "$YOUR_JAVA_CLASSPATH" org.kauriproject.template.DefaultTemplateService person_template.xml "first=James" "last=Dean"

8.3.3 Using templating in standalone Java

Add the kauri-template-<version>.jar to your project. If you use maven, you get the transitive dependencies automatically. If not, you have to add them to the classpath yourself.

The kauri template engine has only dependencies on log4j, commons-lang, commons-logging and juel. If you want to use groovy expressions, you will need groovy-all as well.

You can then use the kauri template engine by calling it's service: org.kauriproject.template.DefaultTemplateService .

Example use from java code:

// create a template service
TemplateService service = new DefaultTemplateService();
// create a template context and add your properties to the context
TemplateContext templateContext = new DefaultTemplateContext();
templateContext.put("first", "James");
templateContext.put("last", "Dean");
// add this template context to the execution context
ExecutionContext executionContext = service.createContext();
executionContext.setTemplateContext(templateContext);
// execute
service.generateTemplate("person_template.xml", executionContext);

8.4 Syntax reference

8.4.1 Basic rules

8.4.1.1 Templates are valid XML files

The Kauri template language is XML-based.

A template file must be a well-formed XML file. So you cannot do things like:

<html>
   <body ${some expr}="value">

   <t:if test="${some expr}">
     </body>
   </t:if>
</html>

The errors in the above snippet are that you can't create dynamic variable names this way, and that the body and t:if elements are not properly nested.

8.4.1.2 Namespace for template instructions

A simple template might contain just some ${...} expressions, but as soon as you want to use any instructions, you will need to declare the Kauri template namespace, which is:

http://kauriproject.org/template

Here's an example of how to bind the namespace to the "t" prefix and use instructions:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:t="http://kauriproject.org/template">
  <t:forEach begin="1" end="5" step="2">
    <p>do something</p>
  </t:forEach>
</root>

8.4.2 Expression language

Expressions can be used to insert dynamic content into the generated output or to provide arguments to template instructions (e.g. the "test" attribute of an <if> instruction).

Kauri template supports two expression languages:

Normally, you should have enough with EL and never touch Groovy.

Groovy offers a powerful escape for those who know what they're doing.

8.4.2.1 EL

The default expression language is the Unified Expression Language (EL), which is the same as used by JSP.

You can type your EL expressions using the ${...} or #{...} delimiter.

Note: when just using the expression language (thus no template directives), there is no need to declare the template namespace. The ${} and #{} delimiters will be picked up automatically when passed to the template engine. If you want to use the $ or # character as regular text, you have to escape it with  a backslash: \$ and \# .

8.4.2.1.1 Expressions

Some of the supported expressions are:

You can access objects that are supplied to the context of the tempate engine by referencing their keys. With the dot-operator, you can access the properties of those objects, e.g.: you can use the expression ${request.clientInfo.acceptedMediaTypes} when there is a request object supplied to the execution context.

8.4.2.1.2 Functions

There are also some convenience functions available. These are called using prefix:name(), for example txt:concat('foo', 'bar').

8.4.2.1.2.1 Text functions
8.4.2.1.2.2 Math functions

Actually all the functions of java.lang.Math are available as EL functions with prefix math. While this is very handy and powerful, you have to keep in mind that this also means that newly added math functions will be only available depending on the JRE used to run your application.

8.4.2.1.2.3 Date/time functions
8.4.2.1.2.4 JSON functions

Remember to escape '<', '>' and '&' characters when using EL expressions in XML files.

8.4.2.1.3 Kauri-specific functions

These are functions only available when using the template engine within Kauri (using the kauri-template-service module).

8.4.2.1.3.1 publicUri(uri)

If the argument is a URI that uses the service protocol, then the URI will be translated to a public URI, this is a URI that can be used to call the service from outside Kauri. This will only work if the REST-service addressed by the URI is mounted on a path (in the wiring.xml). If the REST-service would be mounted on a virtual host which differs from the host of the current (non-internal) request, then the URI will also include scheme and hostname.

Just as for URI resolving, the publicUri() function will automatically resolve the URI within the context of the correct module when including templates contained in other modules.

8.4.2.1.3.2 inSourceMode()

This function returns a boolean argument indicating if the module containing the template file was loaded in source mode.

8.4.2.1.3.3 conf()

See accessing config from templates.

8.4.2.1.3.4 i18n() and format()

See i18n templates integration.

8.4.2.2 Groovy

When you want to unleash greater power in the templates, you can use groovy expressions: $g{<groovy-exp>} or #g{<groovy-exp>}.
e.g. $g{"groovy "*3} prints 'groovy groovy groovy'.

8.4.3 Template inheritance

8.4.3.1 Introduction

The goal of this feature is to be able to split of the common layout of multiple pages to one shared base template, to avoid repetition.

Disclaimer: this feature borrowed quite some ideas from Django's template language.

8.4.3.2 Basic terminology

8.4.3.3 Syntax

8.4.3.3.1 The basics
8.4.3.3.1.1 The base template

The base template is a template that contains t:block elements to define regions that can be overridden by child templates.

....
<t:block name="content">
  [ default content for when block is not overridden]
</t:block>
...
8.4.3.3.1.2 The child template

A child template is a template with on the root element a t:inherit attribute. The value of the t:inherit attribute is the URI of the base template. This attribute is evaluated at runtime, so it can contain expressions to dynamically determine the base template.

The child template can contain t:block elements to replace the t:block elements with the same name from the base template.

All content outside of the blocks will not be used.

It is not an error to have blocks which do not exist in the base template, these will be ignored.

It is not required for a child template to define all the blocks from the base template. If a block is not overridden, the block-content from the base template will be outputted.

The t:block start tag and end tag themselve are never outputted, only the content of the block is outputted.

The child template can have html, body, and other tags which facilitate viewing or editing the child template as an individual page.

Each block has its own scope: variables defined within the block will not be visible to other blocks.

<html t:extends="base.html">
  <t:block name="content">
     ....
  </t:block>

  <t:block name="navigation">
    <t:superBlock/>
  </t:block>

</html>
8.4.3.3.2 Calling the block from the base template: t:superBlock

When overriding a block, it might be that you want to keep the content from the block in the base template, and only add to it.

This is possible using the t:superBlock element.

Example:

Suppose this base template:

<html>
  <t:block name="foo">
    base template content
  </t:block>
</html>

And this child template:

<html>
  <t:block name="foo">
    Hello world. This is the content from the base template:
    <p><t:superBlock/></p>
  </t:block>
</html>

Will produce this output:

<html>
  Hello world. This is the content from the base template:
  <p>base template content</p>
</html>

As this example illustrates, the <t:superBlock/> element can be located at any position and depth within the overriding block.

8.4.3.3.3 Cross-block initialization: t:init

Suppose you have a child template with a few blocks:

<html>
  <t:block name="block1">
    ...
  </t:block>

  <t:block name="block2">
    ...
  </t:block>

  <t:block name="block3">
    ...
  </t:block>
</html>

Remember that only the content of the t:block elements from the child template is executed. Often, you will run in the situation that you want to define some variables and macro's to use in multiple of these blocks. This is possible by defining them in a t:init element.

<html>
  <t:init>
    <t:variable name="foo" value="bar"/>
  </t:init>

  <t:block name="block1">
    ...
  </t:block>

  <t:block name="block2">
    ...
  </t:block>

  <t:block name="block3">
    ...
  </t:block>
</html>

When executing a template that uses inheritance, the template engine will first execute the t:init blocks from each of the templates, starting with those from the top-level base template. This allows child templates to redefine variables and macro's defined by the base templates.

The t:init element can contain any template instructions, but will be executed in silent mode, which means it will produce no output. Typically it will contain variables and macro's, but it can for example be useful to conditionally define a variable using t:if .

If one template file contains multiple t:init elements, they will simply all be exeucted.

TODO:

8.4.4 URI resolving

At various locations in the template language, you can specifies URI's, such as for include and import, inherit, variable and insert.

These URI's can either be absolute or relative. Relative URI's will be resolved against the URI of the template that contains them. So if you define, for example, a macro in one template and call it from another template, any relative URI's within that macro will be resolved against the URI of the template containing the macro, not the one making the macro call.

In general URI's are resolved at runtime rather than at compile-time, so you can specify URI's using expressions, allthough this depends on the specific template instruction.

This section contains an explication of how the resolving of the URI's works. Most template users will not have to worry about this, since it should work as you expect.

At a technical level, the template library defines an interface SourceResolver, the concrete implementation provided will determine how the URI resolving works.

When using the template library within Kauri through the kauri-template-service module, a Kauri-specific SourceResolver is used, which supports Kauri's special service protocol and module protocol.

The resolving of the service and module protocols depends on the module within which they are used: the module protocol fetches resources from the current module, and the service protocol addresses REST-services from the current module's service registry.

So for example, two different modules might both contain a resource at templates/layout.xml, which can be fetched using the URI module:/templates/layout.xml. Depending on the module within which this URI is used, data from a different layout.xml file will be returned.

When you execute a template within a certain module, it is most logical that all URIs contained within it are also resolved within the context of that module.

However, imagine the following scenario:

This would not work if we evaluate this second include within the context of module A (where the template is being executed). Therefore, we have made it such that, when including templates via the service protocol, and the service protocol addresses a service from another module, the source resolving of URIs in that included template will be done within the context of that other module.

This of course works any number of includes deep. However, it only works if the template engine can be aware of the "module switch". Thus if you write a restservice which in itself retrieves data from a restservice in another module, then the template engine won't be aware of the switch. But that is a rare case, which can be worked around by using a template with an include instead.

8.4.5 Whitespace handling

Kauri Template sometimes removes whitespace-only text occurring in template files, so that the template output would not contain an abundance of irrelevant whitespace. But if you want to keep the whitespace, it is possible to do so.

The rule for whitespace removal is as follows: if the text between two tags consists of only whitespace characters, then this text is removed while parsing the template. Whitespace characters are space, tab, line feed (a.k.a. new line or end of line) and carriage return. Other forms of whitespace, such as non-breaking spaces, are not considered as whitespace.

From the moment the text between two tags contains a non-whitespace character, the text will be left alone. It will not be trimmed.

The whitespace stripping happens during parsing of the template, not on the output produced by the template. As a consequence, whitespace occurring in text that is inserted via expressions or other constructs is never touched.

There are two mechanisms available to tell the template language that whitespace should be preserved: the xml:space attribute and the t:text instruction.

xml:space

The xml:space attribute is defined by the XML Recommendation. If you add an attribute xml:space=”preserved” on a start-tag, all whitespace between that start-tag and its matching end-tag will be preserved. It is possible to revert this effect at a lower level by adding the attribute xml:space=”default”. The xml:space attributes will not occur in the template output. In case you do want to produce an xml:space attribute in the output, you can do so by creating the attribute via t:attribute.

Examples
<p xml:space=”preserve”>
   All whitespace <span> </span> will be preserved.
   But here it will be stripped: <span xml:space=”default”> </span>.
</p>

In case you're wondering, the “xml:” namespace prefix is a special one that does not need declaration.

t:text

The t:text instruction will preserve all whitespace occurring within it, but the t:text instruction will not occur in the output. It is hence an alternative for xml:space=”preserve” for those cases where you don't have an element to add the xml:space attribute on, while also being shorter to write.

Examples

In the example below, the words very and important would stick together in the template output, as the whitespace-only text between the </strong> and <em> tag is removed:

<p>
  <strong>very</strong> <em>important</em>
</p>

This can be avoided as follows:

<p>
  <strong>very</strong><t:text> </t:text><em>important</em>
</p>

In the example below, in case the if-test evaluates to true, the output of the template would contain a newline character, two spaces, the text “More than three” and another newline. This is because the whitespace is not trimmed.

<t:if test=”x > 3”>
  More than tree
</t:if>

If you want to avoid this, you can wrap the text into a t:text tag:

<t:if test=”x > 3”>
  <t:text>More than tree</t:text>
</t:if>

The t:text tag is here not used to preserve the whitespace within it, but rather to introduce whitespace-only nodes before and after it, which will be stripped.

8.4.6 @inherit

The t:inherit attribute, to be used on the root element of a template, is part of the template inheritance feature.

8.4.7 attribute

The attribute instruction can be used to add attributes to an element in a dynamic way.

Specifying the attribute name at runtime

Using t:attribute, the attribute name can be specified using expressions:

<div>
  <t:attribute name="my-${something}" value="music"/>
</div>

The name can include a namespace prefix. As usual for attributes, the default namespace (= no prefix specified) does not apply.

Adding attributes conditionally

You can surround the attribute with conditional logic (such as an if) to conditionally add the attribute:

<div>
  <t:if test="${1 < 3}">
    <t:attribute name="class" value="music"/>
  </t:if>
</div>

Attribute instructions should be the first children of an element, thus immediately follow a start-tag. They can not be used anymore once child content for the element is generated. So the following is not possible, as there is no start-tag to add the attribute to:

<div>
  Hello world.
  <t:attribute name="my-${something}" value="music"/>
</div>

If you don't need the above mentioned dynamism when adding an attribute, you can as well add the attribute directly on the element. So you can then simply do:

<div class="music">
</div>

8.4.8 block

The t:block instruction is part of the template inheritance feature.

8.4.9 choose (when... otherwise...)

<t:choose>
  <t:when test="${false}">
    <p>first case - false</p>
  </t:when>
  <t:when test="${true}">
    <p>second case - true</p>
  </t:when>
  <t:otherwise>
    <p>other</p>
  </t:otherwise>
</t:choose>

TODO: describe behavior (only first matching when executed etc.), is otherwise optional, is content between the when's allowed and what happens with it

8.4.10 comment

Produces a comment in the output.

Any comments in template, using the <!-- comment --> syntax, will not be part of the template output. To produce a comment in the template output, you need to use t:comment.

t:comment can in itself contain any template instructions, the contents will be serialized as XML and used as comment text.

Example:

<t:comment>This is a comment</t:comment>

8.4.11 element

Allows to create elements in the output using dynamically determined name.

<t:element name="${some.thing}">
  Foo bar!
</t:element>

The element name will be namespace-resolved following the normal XML rules. If the name does not include a prefix and a default namespace is active, then the element will be in this default namespace.

8.4.12 forEach

8.4.12.1 Kinds of loops

8.4.12.1.1 Counting loops
<t:forEach begin="1" end="5" step="2">
  <p>do something</p>
</t:forEach>
8.4.12.1.2 Iterating loops
<t:forEach var="item" in="${mylist}" [begin="1"] [end="5"] [step="2"]>
  <p>do something with ${item}</p>
</t:forEach>

8.4.12.2 Supported list types

You can loop over:

8.4.12.3 Loop status

Inside the forEach, you have access to a variable called loopStatus providing the following fields:

8.4.13 if

Conditionally evaluate some part of the template.

<t:if test="${true}">
  <p>always say hello</p>
</t:if>

8.4.14 include, import

include and import allow to include other template files into the current one, hence supporting modularisation and re-use.

An include/import will cause the included template to be executed at the moment the include/import instruction is encountered. Any output produced by the included/imported template will be inserted at that location.

The difference between include and import is that and import will never override macro definitions from the template it is included in. An include on the other hand behaves as if the content of the included template would be inserted at the location of the include instructions: any macro will override previously defined macro's with the same name.

Syntax
<t:include src="..." mode="..."/>
<t:import src="..." mode="..."/>

Attributes:

Usage

Includes and imports can occur at any location in a template file. They are not only useful for including macro libraries, but also for reusable snippets.

The same template can be included multiple times.

Supress root element trick

If you have a "snippet" template to be included in other templates, but you don't want the template to produce a root element, you can use a t:if element as root for your template:

<?xml version="1.0"?>
<t:if test="${true}" xmlns:t="http://kauriproject.org/template">
  Hello world!
</t:if>
See also

For reusable layouts, be sure to check out the template inheritance feature.

8.4.15 init

The t:init element is part of the template inheritance feature.

8.4.16 insert

<t:insert>

The t:insert instruction is used to insert some file or variable into the output of the template.

The inserted file/variable is treated as static content: template instructions or expressions contained in it are not evaluated.

The file/variable will by default be parsed as XML, this can be changed to text or html inclusion using the mode attribute.

@src|@variable :  The content to insert

To insert contents from a file or network-stream use the @src attribute and let it point to some absolute or relative URL (protocols supported are 'http', 'file', 'module', and 'service', see URI resolving for more details)

<foo>
  <t:insert src="bar.xml"/>
</foo>

To insert a variable use the @value attribute and let it contain a string value or some expression that evaluates to a string value.

<foo>
  <t:insert value="${item.html}"/>
</foo>

Using the @src takes precedence over the @value.  

@mode: The type of content to insert

The @mode attribute allows to specify in which way the content will be regarded during the import. The possible values for the mode are:

The mode to apply is determined according to the following fall-back strategy:

  1. The mode specified with the @mode attribute takes precedence. If not specified:
  2. The Mime-Type found on the retrieved input source (This only when the @src is used.) is mapped onto xml, html or text
  3. If still no match is found (e.g. @value is used, and no @mode is specified) then mode="txt" is assumed.
<foo>
  <t:insert src="http://somewhe.re/over-the/rainbow" mode="html" /> 
</foo>

In html mode the inserted content is automatically limited to the contents of the <body> element of the page.  The output can thus easily be producing mixed-content-model XML. Your template should provide a proper root element to coop with that.

@encoding: The character-set to apply

A similar approach is taken towards the used encoding to read the content to be inserted. Here the fallback-strategy is as follows:

  1. The encoding specified with the @encoding attributes is used. If not specified:
  2. The encoding found on the retrieved input source is used.
  3. If none is specified the default encoding (java system property file.encoding) of the VM running the template will be used.

None of this applies to @value content because that is already present as character-content to the templating engine. In this case the characters to insert do not need to be decoded from some (external) byte-stream.

<foo>
  <t:insert src="module:/myfile-in-Cp1252.txt" encoding="Cp1252" />
</foo>

8.4.17 macro (callMacro, parameter)

<t:macro name="...">
  <t:parameter name="..." value="..."/>
</t:macro>

<t:callMacro name="...">
  <t:parameter name="..." value="..."/>
</t:callMacro>

Macro's can be defined at any location in the template. They are immediately available everywhere: the location where they are defined in the template does not matter.

Macro's can be called recursively.

The purpose of t:parameter is as follows:

Implementation problems

There are still some rough edges on the current implementation.

Recursive macro example

Suppose we have a tree of nodes, where each node has a property name, and a property parent pointing to its parent node. When a node has no parent, the parent property is null.

The follow template fragment shows how to display the name of a node (theNode) and its ancestor nodes.

<t:callMacro name="displayNode">
  <t:parameter name="node" value="${theNode}"/>
</t:callMacro>

<t:macro name="displayNode">
  <t:parameter name="node"/>

  <p>${node.name}</p>

  <t:if test="${node.parent != null}">
    <t:callMacro name="displayNode">
      <t:parameter name="node" value="${node.parent}"/>
    </t:callMacro>
  </t:if>

</t:macro>

8.4.18 protect

Conditionally evaluates the contained content, depending on the access control decision.

<t:protect access="...">
  [content here]
</t:protect>

The access attribute contains a comma separated list of values. These could for example be role names.

To use the t:protect instruction, you need to provide an AccessDecider to the template engine, which will take the access decision based on the values in the access attribute. There is no built-in behavior.

For the template engine as integrated in Kauri, see here.

8.4.19 superBlock

The t:superBlock instruction is part of the template inheritance feature.

8.4.20 variable

Introduction

The variable instruction associates a value with a name.

The value can be specified using the value attribute or, if not present, in the content of the variable element. It can be a literal string or contain expressions.

The value can be of any type (i.e., not just strings), depending on the expression.

<t:variable name="foo" value="${bar}"/>
<t:variable name="sometext">bla</t:variable>
<t:variable name="data" mode="json">{"parsed": "value"}</t:variable>
<p>foo = ${foo}</p>
<p>and here is some text: ${sometext}</p>
<p>and some parsed data: ${data.parsed}</p>
Loading variable data from a URI

The data of a variable can also be loaded from a URI instead of specifying it in the value attribute, or nesting it in the <t:variable> tags.  You do so by specifying the URI in the @src attribute.

The mime-type of the loaded data will determine the way the content is handled (i.e. parsed/interpreted). This behavior van be forced or overridden by using explicit @mode attribute mentioned below

Handling the data

The way the retrieved data is handled is covered by the @mode attribute. It can contain the following values:

@mode

by default for mime

handling

json

application/json

the data will be parsed as JSON (object or array) and hence you can use expressions to walk over the JSON data. The JSON library we use will map the data onto Java Objects.

xml

*text/xml*, *application/xml*, or  **+xml

the data is parsed into a (namespace-aware) DOM-tree

html

text/html

the data is parsed into a (namespace-aware) DOM-tree, but will apply smart tag balancing in the process.

txt

any other text/*

the data is not parsed at all, but just read in as text (using the source-declared encoding)

The middle column declares which @mode will be assumed if it is not specified, based on the retrieved @src

Syntax example:

<t:variable name="foo" src="http://somewhere/data.json"/>
${foo.someproperty}

When the resource would support content-negotation, you can specify your preferences in an accept attribute:

<t:variable name="foo" src="http://somwhere/data" accept="application/json"/>

The accept attribute takes a comma-separated list of media types. Specifying a quality factor, as in the HTTP Accept header, is currently not supported.

Fallback for loaded data.

Both of the attributes @value and @src can be used together, in which case the remote loading (@src) will be favored. The expression in the @value attribute will only be evaluated when the remote loading failed.
Note: in absence of the @value expression, a failure to load the data from  @src will throw an exception that prevents further template execution.

Only set a variable if it is not yet defined

It is possible to say that a variable should only be assigned if it does not have a value yet. The previous value might be assigned by an earlier variable instruction, but more interestingly, might be provided as parameter by the executor of the template. This makes it possible to define defaults for variables within a template, while allowing to provide custom values from outside the template.

Syntax:

<t:variable name="..." value|src="..." overwrite="false"/>

When the overwrite attribute is not specified, it defaults to true.

9 Database resources

9.1 Introduction

Kauri's database resources (often called DB resources) provide an easy way to expose database entities as RESTful resources.

Two implementations are provided:

9.2 Interface

Here we describe the interface which is common to all database resource implementations.

9.2.1 URI structure

The URI structure can be summarized as follows (* = 0 or more occurences, ? = 0 or 1 occurence):

/entityname(/id/propertyname)*(/id)?

The following table shows some examples of what is possible:

/myentity

list of all myentity records

/myentity/1

the entity myentity with id = 1

/myentity/1/myproperty

assuming myproperty is a property of myentity, and that myproperty is an entity by itself, this will return the entity associated through myproperty. If myproperty is a list, it will return the list of all such entities.

/myentity>/1/myproperty/2

Same as the previous, but assumes myproperty is a list, and will only return the entity with id = 2.

9.2.2 Methods

The HTTP methods have their usual meaning. GET, PUT, POST, DELETE, HEAD and OPTIONS are all supported

Creating a new entity is done by posting to a list-URI. So the ID of the new entity is assigned by the server.

9.2.3 Querying

Querying (searching) for entities is done using the query string on list-URIs.

The name of the property to search on should be preceded by "q.".

Searching on a single property:
/myentity?q.propertyname=value

Searching on multiple properties:
/myentity?q.propertyname1=value1&q.propertyname2=value2

9.2.4 Sorting

When lists of entities are returned, you can specify sorting options to influence the order.

The parameters are:

sort.{seqnr}=propertyname
order.{seqnr}=asc|desc

where seqnr is 1, 2, ...

Specifying the order is optional, default is ascending.

Example:

?sort.1=prop1&order.1=desc&sort.2=prop2

9.2.5 Paging

When lists of entities are returned, you can use paging options to avoid that the complete list is returned.

The paging options are specified using the following request parameters:

page

The page number, the first page is numbered 1. If the page number is larger than the number of available pages, an empty result will be returned.

pageSize

(optional) The size of a page, default is 10.

When the page request parameter is present, the plain list result will be wrapped in a container describing the page.

For example, for the JSON format, this container is as follows:

{
  page: 1,
  pageSize: 10,
  totalPages: 5,
  totalRows: 46,
  data: [ { ... }, { ... }, ...]
}

9.3 JPA database resources

9.3.1 Setup

Using the JPA database resources is straightforward, simply follow the steps below.

If you have generated a project using an archetype, then depending on the selected archetype these steps might already have been done for you.

9.3.1.1 Create some JPA entities

In your Kauri module, add some POJO's you want to persist. Annotate them with JPA annotations, only @Entity is required.

9.3.1.2 Create a persistence.xml

Add a META-INF/ persistence.xml file and configure your persistence unit (connection-url, username, pasword)

The default persistence-unit name is "kauri-dbresources". If you use another one, you need to define it using a Spring bean named "persistenceUnitName", see below.

9.3.1.3 Update the pom.xml

In the pom.xml of your module, add a dependency on the kauri-dbresources-impl artifact:

    <dependency>
      <groupId>org.kauriproject</groupId>
      <artifactId>kauri-dbresources-impl</artifactId>
      <version>${version.kauri}</version>
    </dependency>

9.3.1.4 Spring bean configuration

In your spring bean configuration (src/main/kauri/spring/...), add the following import:

<import resource="classpath:org/kauriproject/dbresources/jpa/services.xml"/>

If needed override the default persistenceUnitName by adding:

<bean id="persistenceUnitName" class="java.lang.String">
  <constructor-arg value="{your-persistency-unit-name-here}"/>
</bean>

9.3.1.5 wiring.xml

The import we did in the Spring configuration will automatically export a REST-service called jpaRestlet.

In the wiring.xml, you can mount this REST-service on a path of your choice.

Inside the XML-element defining your module, add:
<mount name="jpaRestlet" path="/data"/>

9.3.1.6 Try it out

After doing an "mvn install" and (re)starting Kauri, browse to:

http://localhost:8888/data/myentity

where myentity corresponds to the name of an entity as annotated on your Java classes, such as @Entity(name = "myentity")

9.3.2 JPA database resource interface specifics

The JpaRestlet provides the JPA database resources. It implements the common database resource interface.

All resources have three representations:

Content negotiation (the HTTP Accept header) can be used to indicate your preferred representation.

In case you can't set the Accept header, you can work around this by specifying it in the URI, for example ?media=json

Entities that are serializable, can also be retrieved as serialized Java objects.

For POST/PUT operations, the payload can be JSON, XML or serialized Java objects.

9.3.3 Limitations

Currently database resources are in initial stable phase. We are aware of certain restrictions and imperfections, but before we tackle those issues we'd like to have a better view on where this module is going and what features users want to see in it.

The database resources are vulnerable to SQL injection.

The database resources only work with Hibernate as JPA provider.

9.3.4 persistence.xml examples

Here you can find some persistence.xml examples that can help you get started with Kauri database resources in your project.

9.3.4.1 In-memory database (used in samples)

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
  <persistence-unit name="kauri-dbresources" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />
      <property name="hibernate.show_sql" value="false" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
      <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:kauri-sample" />
      <property name="hibernate.connection.username" value="sa" />
      <property name="hibernate.connection.password" value="" />
    </properties>
  </persistence-unit>
</persistence>

9.3.4.2 MySQL database

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
  <persistence-unit name="kauri-dbresources" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="update" />
      <property name="hibernate.show_sql" value="false" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.username" value="sqluser" />
      <property name="hibernate.connection.password" value="sqlpwd" />
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/kauritest" />
    </properties>
  </persistence-unit>
</persistence>

9.3.4.3 Interesting links

9.4 Mock database resources

9.4.1 Introduction

The mock database resources (often called DB Mock) allow to provide database resources without having a database and code in place.

They are useful at early stages in the project, when the real database resources are not yet available. It can also be useful at later stages in the project, to experiment with new entities or to work on the front-end without access to the database. Since they provide the same RESTful interface as the real DB resources, smooth transition between the two is possible.

Creating mock data resources is simply a matter of creating a directory structure containing JSON files. DB Mock will automatically provide the CRUD (create-read-update-delete) and query operations, so that your prototype will raise above the level of static data. Linking between entities is also supported, using {$ref: "..."} objects. There is no description of the type of the entities [required/necessary/possible].

While the mock database resources behave to a some extent as real database resources, it is by no means a perfect substitute for them. The goal of DB Mock is that an application can function (in the sense of being able to click through everything) in absence of real database resources, not that all displayed data would be correct at all times.

9.4.2 Setup

Follow the steps below to use DB Mock.

9.4.2.1 Update the pom.xml

In the pom.xml of your module, add the following dependency:

<dependency>
  <groupId>org.kauriproject</groupId>
  <artifactId>kauri-dbresources-impl</artifactId>
  <version>${version.kauri}</version>
</dependency>  

9.4.2.2 Spring bean configuration

Add the following to your module's Spring configuration (src/main/kauri/spring/...):

  <kauri:export-restservice ref="data"/>

  <bean id="data" class="org.kauriproject.dbresources.mock.DbMockFinder">
    <constructor-arg ref="restletContext"/>
    <constructor-arg ref="module"/>
    <constructor-arg ref="mockdata"/>
 </bean>

The first two constructor-arg's refer to the beans made available by the kauri:module tag.

The third constructor-arg is the path within the module resources where the mock entities are stored. By convention we usually store these in mockdata, which means in your project source tree you have to add these below src/main/kauri/mockdata.

9.4.2.3 wiring.xml

In the wiring.xml, you can mount the "data" REST-service (that we exported using kauri:export-restservice) on a path of your choice.

Inside the XML-element defining your module, add:
<mount name="data" path="/data"/>

9.4.2.4 Try it out

Just to try things out, you might want to create some test mock data.

For example, create the directory src/main/kauri/mockdata/persons, and add a file 1.json to it, containing:

{
  name: "John",
  city: "New York"
}

Build by executing "mvn install", (re)start Kauri, and browse to:

List of persons:
http://localhost:8888/data/persons

Person by id:
http://localhost:8888/data/persons/1

Persons called John:
http://localhost:8888/data/persons?q.name=John

9.4.3 Defining entities

9.4.3.1 General structure

The JSON entities are defined by creating one subdirectory per kind of entity in the src/main/kauri/mockdata directory.

The listing below shows the directory structure of a module containing three types of entities: contacts, tasks and projects.

Within these directories, you create one JSON file per entity instance. The name of the file (without .json extension) is the ID of the entity.

.
|-- contact-module
|   `-- src
|       `-- main
|           `-- kauri
|               |-- mockdata
|                   `-- contacts
|                       `-- 1.json
|                       `-- 2.json
|                       `-- 3.json
|                   `-- tasks
|                       `-- 1.json
|                       `-- 12.json
|                       `-- 13.json
|                   `-- projects
|                       `-- 1.json
|                       `-- 2.json
|                       `-- 3.json

9.4.3.2 JSON entities

Here is an example of a project entity that contains a label, description, start, finish, type, status, importance and a set of subtasks:

{
    label: "Defining prototype module requirements",
    description: "Investigating which requirements we have towards prototyping a Kauri project",
    start: "2008-09-01",
    finish: "2008-09-30",
    type: "research",
    status: "busy",
    importance: "+++",
    subtasks: [
        {label: "Explore", description: "run the kauri samples, make it work!"},
        {label: "Try a prototype", description: "hands on, try to make a prototype"}
    ]
}

9.4.3.3 Linking between entities

In the example above, we could imagine that the subtasks are also entities itself, which we want to CRUD by themselves. Then we would like to create a reference to these entities instead of repeating them. This can be accomplished by linking entities using objects with a  $ref property. If the name of the name-value pair in a JSON object is '$ref' then the value is a reference to another entity.

9.4.3.3.1 Example
{
    "label": "Defining prototype module requirements",
    "description": "Investigating which requirements we have towards prototyping a Kauri project",
    "start": "2008-09-01",
    "finish": "2008-09-30",
    "type": "research",
    "status": "busy",
    "importance": "+++",
    "subtasks": [
        {$ref: "/tasks/3"},
        {$ref: "/tasks/3"}
    ]
}

Of course in this case we have to have a file /entities/tasks/3.json:

{
    "label": "Explore", 
    "description": "run the kauri samples, make it work!"
}

When GETting the project entity, the entities linked via $ref will be merged within the project JSON.

9.4.4 Interface & behaviour

9.4.4.1 General

DB Mock implements the common database resources interface. The entity names correspond to the directory names.

Unlike the JPA database resources, the mock data resources provide only one representation: application/json.

9.4.4.2 Retrieving data (GET)

9.4.4.2.1 id property

When GETting an entity, DB Mock will automatically add a property id to the JSON object, with as value the name of the file (without .json extension).

So for a file called 1.json, this will give:

{
  "id": "1"
  ...
}
9.4.4.2.2 Merging of linked entities

{$ref: "..."} objects will be replaced by the entity to which they link.

9.4.4.3 Updating data (PUT, POST, DELETE)

DB Mock supports PUT, POST and DELETE operations, so it is possible to actually update the data. The updates are however only effective for the currently running Kauri, restarting Kauri will loose the updates. At the time of this writing, this is implemented by copying the resources to a temporary location and applying the updates on this copy.

When you GET an entity, any entities linked within it using {$ref: "..."} will be merged. However, when creating or updating an entity, these merged entities will not be split out again in separate files. This is because the system has no knowlege of which properties are linked entities.

The PUT and DELETE operations are smart enough to apply updates within files, if the addressed entity would be a part of a JSON file instead of a file on its own.

10 Forms

Intro

The Kauri Forms module implements a browser targeted (Javascript based) form framework.

The framework provides a formal and systematic approach to end-user data-entry. It is not serving more generic end-user interaction and UI effects, but we bundle  jQuery and jQuery UI as separate Kauri packages.

So with the Kauri forms framework you build browser-based interaction screens that allow the end-user to read, modify and save (or create) some kind of data-structure. This data-structure is exchanged between the form-framework and the back-end in the known JSON format.

Requirements

By design this framework clearly assumes modern browser technology to be available:

These assumptions boil down to:

  1. we assume a fairly modern browser supporting Ajax requests
  2. Javascript support is enabled in the browser

We think this largely fits today's common practice.

NOTE:
At the time of writing this module does not do an effort to support some graceful degrading towards browsers/deployments that do not meet these requirements. Rest assured though, like all Kauri modules it is entirely optional to use it or not.

RIA meets ROA

The above proceeds on one of our believes: that ROA (resource oriented architecture) designs assume smarter clients that are able to control their own application state. The latter are commonly grouped under the term Rich Internet Applications (RIA).

These RI-Architectures come in many implementation variants, some of which offered through specific (some paying) development environments. Most of those have a flexible way to deal with back-end (Ajax) requests and will thus invariantly be usable with the mid-tier-service modules delivered with Kauri.

Further reading:

Check up on the related samples in the Kauri distribution.

10.1 Concepts

Goals and Features

Made for data-entry: managing a data-structure

As explained in the introduction the Kauri Forms framework is about creating interaction screens to allow management of structured data. A typical example of such structured data in JSON notation would look like this:

{
  "name": "John Doe",
  "sex": "Male",
  "birth": "19700605",
  "hobbies": ["family", "reading" , "math", "stars", "trains", "photography"],
  "address": {
    "street": "Longstreet",
    "number": "5758",
    "zip": "TX 3007",
    "city": "Hometown",
    "country": "Belgium"
  }
}

As the example shows these data-structures are by nature composed of different members that in their own right can be either

Assuming the REST services to manage these entities (store, retrieve, query, secure, ...) are available the forms-framework is there to help create browser based interaction screens and logic

  1. to modify these structures,
  2. validate the data-entry and finally
  3. communicate with the available back-end services
Made for real life applications

The difference between good and great applications appeals for the kind of end-user interaction that goes beyond assuring the dull correctness of data entry, and aspires to make a difference that matters in how the end-user can efficiently perform his daily work.

In our experience the nowadays web-based front-end designers up for the challenge have a great deal of low level HTML, CSS and Javascript experience. In order to support them, the framework should allow them to leverage that experience and focus on making 'the difference'. In other words: the dull stuff should be handled correctly out of the box and extras and customisations should be easily possible.

In practice we allow

  1. Extending the framework with custom controls and features.
  2. Extensively configuring the available components.
  3. Standard HTML/CSS editing of the visual UI components.
  4. Wiring up events between the various form controls internally, or between the form-controls and custom Javascript functions and non-Kauri UI libraries.

How all that is done we explain in this section, after some general introduction.

Essential Framework Concepts and terminology

The framework introduces 3 distinct concepts with their own specific goals and responsibilities:

  1. Fields
  2. Controls
  3. The Form
A Field

A 'Field' in Kauri Forms groups the 'data-type' aspects of each individual low-level member in the data-structure. These aspects are:

  1. value properties, e.g.
  2. formatting properties
  3. validation properties
  4. extra convenience properties

For handling some recurring data-types, the framework already offers a number of standard 'Field' implementations:

Next to these, own fields can be added.

The core task of these Fields is to keep track of the 'value' being offered for editing in the form. This involves triggering and managing validation, but also converting the value to-from the (string) representations of it that are either entered/seen by the end-user or communicated to the back-end.

Note that both towards the backend (json/wire-format) and to the end-user (keyboard-entry and screen-feedback) all communication is essentially string based (or 'untyped' if you like).

For this purpose the Field knows about two distinct 'formatter's that handle formatting (to string) and parsing (from string) of the actual value. These two are known respectively as the:

  1. wire-formatter: to convert the local value to-from the value as passed over the wire (ie. JSON)
  2. user-formatter: to convert the local value to-from the value as shown and edited by the end-user.

Note that any occuring formatting and parsing errors will be presented to the end user in the same way as validation errors: both indicate invalid data in the form and require a similar action to get resolved.

Just like the formatting logic, the actual validation logic is provided in separate (reusable) classes that implement a simple validation interface. Its responsibility is to evaluate a single value leading to either an ok or to a validation-message.

A Control

A 'Control' then will, for each distinct member in the data-structure, offer the graphical screen elements to show its value and allow changing it. In more detail this involves:

  1. Produce a specific UI Control (set of activated HTML elements) to allow the required end-user interaction. This includes input-elements, specific action triggers, labels, format or validation feedback, ...
  2. Rely on a specific 'Field' to properly handle the data-type related aspects of the values being modified through the control.
  3. Bind to user-input events to trigger formatting, validation and fire events.
  4. As well as bind to events from other controls
  5. And depending on the specific control: load reference data from specific configured URI's

More or less matching the earlier mentioned typical Fields (datatypes) the Kauri-forms module offers these 'Control' implementations:

Just like with the Fields, your own custom controls can be added.

The Form

Finally the Form object in this framework is the corner-piece in the whole setting that organizes the various controls on the screen and handles the communication to the rest-services. For that it will:

  1. Act as a top-level composite Control holding the first-level members.
  2. Read the HTML template for matching elements and extract a basic "configuration" from it.
  3. Apply an optional external form-configuration.
  4. Create and set-up all nested controls. (including the top-level control provided by itself)
  5. And maintain a registry of controls to allow lookup and referencing between them.
    (Useful in e.g. event-binding and handling)
  6. Last but not least, it will communicate to the back-end upon form-submit.

Form Configuration (aka fconf)

To make the Form manage the data-structure of your choice (i.e. show the correct fields, and apply the desired formatting and validation) you need to give it the proper "configuration".

This configuration holds a number of things:

  1. a description of the various members of the data-structure and how the form should allow modifying them.
  2. the service URIs needed for data-submission
  3. specific form properties

Matching the sample data-structure from the first paragraph, below you find a rough structure of an appropriate matching form configuration:

var fconf = {
  /* described data structure */
  "members": {
    "name":    {   /* some string input */          },
    "sex" :    {   /* Male or Female choice */      },
    "birth:    {   /* date input */                 },
    "hobbies": {   /* flexible list of strings */   },
    "address": {   /* nested structure of street, number, zip, city and country */...}
  }  

  /* communication properties */
  "createURI": "${publicUri('service:/data/person/')}",

  /* Additional custom types */
  "controlTypes": {
     "name-of-control": {  /*   definition */   }
  }
}

Roughly speaking there are 3 main sections in this configuration:

  1. The listing of form-members and their (inline) field-type descriptions.
  2. Form-specific properties, mainly to configure the communication end-points for form-submit.
  3. Possible additional custom types (for fields, controls, formatters and validators) to reference to.

See the reference 'form config' for a more detailed explanation of what should go in each section. Additionally check the reference on each of the controls you want to use to learn about how they can be configured and tuned. Below you just find some simple examles as a first introduction into the nested field-description:

...
  "members":   {
     "name": "string",   //a shorthand for { "base": "string" }

     "birth": {
       "base": "date",
       "yearRange": '-100:+0',

       "label": 'What is your date of birth?'
     },

     "address": {
       "base" : "composite", 
       "members": {
         "street"   : "string",
         "nr"       : "string",
         "zip"      : "string",
         "city"     : "string",
         "country"  : "string"
       }
     }
   }
...

Note how the composition/nesting of members in this structure enables to give each control in the hierarchy a unique absolute-id by concatenating them into 'paths'. We call the resulting full-identification the control "index". So in the above example the following ones will have been created.

  /name
  /birth
   ...
  /address
  /address/street
  /address/zip
   ...

These "indices" will turn up again when we talk about the HTML Template binding further down.

Finally, to complete the 'form' explanation we just need to explain how to turn this form-configuration into a live form. This involves:

  1. the following lines of Javascript:
      var form=new $.org.kauriproject.forms.Form("my-form", fconf);
  2. and an HTML <form> element that matches up with the id (mentioned as first argument):
      <form id="my-form" />

HTML Form Creation

As shown above the matching <form/> element can be kept empty. In that case the Javascript framework will create all the required HTML elements to enable the needed end-user interaction. (as hinted above this is under the responsibility of the different controls)

TODO: describe current match/create algorithm that decides when to start creating elements --> some of this still under discussion (see mail-list, see issue?)
+ position and importance of "input" element

HTML Template Binding

Of course those elements will be created and positioned in some standard way as coded inside the specific controls (each of them might allow some configuration to tweak that a bit). Instead of sticking to that default the framework allows to "bind" the interaction behaviour of the distinct controls to specific (and arbitrary positioned) HTML elements in a custom provided page.

To make the binding work however these HTML elements need some additional mark-up that declares them as:

  1. Being tied to a specific control. By using the @kauri-idref attribute.
  2. Being created to fulfill a specific function or role. Through the @kauri-role attribute.

As an example:

<label kauri-idref="name" kauri-role="label">Name:</label>
<input kauri-idref="name" kauri-role="input" />
<span  kauri-idref="name" kauri-role="messages" />

This allows the front-end designer to arbitrarily position the label, input-box and feedback messages (typically format and validation errors) associated to the control.

For ease-of-typing the kauri-idref attribute is inherited down the nodes in the HTML structure. This means that the value can be placed on a common parent for various nested elements:

<div kauri-idref="name"> 
  <label kauri-role="label">Name:</label>
  <input kauri-role="input" />
  <span  kauri-role="messages" />
</div>

Remember that controls can be nested (This is how composite controls manage composite values.) In this case the member-names are combined into an absolute id or "index" for the control.

The @kauri-idref value should point to this index, but can choose to do so in a relative way. By default the kauri-idref value will be appended to the one of any parent element in the HTML structure. Only if the value kauri-idref starts with a '/', the value is considered to be absolute.

Note:
Relative-path-traversing syntax (i.e.: './' or '../' prefixes) are NOT supported in the @kauri-idref
Further explanation on the kauri-idref, plus a complete list of the supported 'kauri-roles' is to be found in the 'form HTML' reference.

Blending HTML Template and Configuration

The more people make use of the customization possibilities of the HTML template, or more technically: the more nested kauri-idref attributes are found on the HTML elements nested in the <form> tag, the more of the data-structuring information the system can derive from it.

This derived structure is effectively taken into account and thus avoids the double typing of providing the complete structure in the form-config as shown above.

While these kauri-idref values are a simple and flexible alternative for expressing some implicit structure, they are no match for the expressiveness of the JSON form-config for more elaborate stuff like specific control settings. To match up the best of both worlds we allow the @kauri-type attribute to associate pre-configured control-types to the identified (by kauri-idref) controls.

These pre-configured control-types are listed (using their name as a property-key) in the fconf['controlTypes'] object.

For more details, check the 'form HTML' and 'form config' reference for more details on this usage.

Event Handling and wiring

For the event-handling kauri-forms just relies on the jQuery event mechanism.

All regular jQuery event handling applies, and any additional kauri-specific events are bound and triggered through the matching "input" element.

Getting a handle to this element is easy:

  1. First lookup the control you want to bind to with CONTROL#findControl(path). This path argument can be absolute (starting with '/') or relative (NOTE: traversing the hierarchy with '../' is supported here)
  2. on the found control the method CONTROL#getElement() will return the jQuery wrapped HTML element handling the 'input' role which is passing on all the events.

In a code-sample:

  var form = new $.org.kauriproject.forms.Form("my-form", fconf);
  var wzip = form.findControl('/address/zip');
  wzip.getElement().valueChanged(function() {
    alert("The zip value changed to: ", wzip.getValue());
  });

Further reading:

10.2 Standard Usage

The simplest scenario to create a form is to let the framework generate all HTML for you. This is possible by defining the structure you want in javascript and call the form creation mechanism.

10.2.1 Defining the form configuration

The form configuration is defined in a javascript object. All members of our form are defined in the members field. Per member we define at least the field type we need.
For example: our form needs a simple textfield 'name'. Then we define:

 var fconf = {
     members: {
         'name': 'string'
     }};

That's it for the form configuration.  In fact that's a shorthand for this:

 var fconf = {
     members: {
         'name': {
             base: 'string'
         }
     }};

in which 'name' is an object and can contain more then just the base type.

If we want to create a form with 6 basic form fields: a textfield name, a textfield with e-mail validation e-mail, a datepicker for a birthday, a checkbox and an textarea control, we use the structure below:

      var fconf = {
              members: {
                  'name': 'string',
                  'email': {
                      base: 'string',
                      '+validators': { 'isEmail': {} },
                      label: "e-mail"
                  },
                  'birthday': {
                      base: 'date',
                      yearRange: '-100:+0',
                      label: 'What is your date of birth?'
                  },
                  'mondaysok': {
                      base: 'boolean',
                      label: 'Do you like mondays?'
                  },
                  'description': {
                      base: 'string',
                      control: 'textarea-control',
                      label: 'Describe yourself in 10 words'
                  }

          }};

Each member contains at least a base type. Other fields in this example are: a label, a validator 'isEmail' and a control. The latter needs a little explanation. Each fieldtype is by default coupled to a control type. E.g. a 'string' fieldtype is by default coupled to a 'input-control', or a 'date' fieldtype is coupled to a 'date-control'.  But the description field in this example, does not need a simple input-control (which is the default), but needs a textarea-control.
Thus, by leaving the 'control' field, you fallback on the default controltype for the fieldtype.

In the form configuration we need one last info: where to post the form to on submit. This is defined in the createUri, which is defined next to the type-field. This results in the fconf below:

    var fconf = {
          "createURI": "${publicUri('service:/data/contact/')}",
 
          members: {
                  'name': 'string',
                  'email': {
                      base: 'string',
                      '+validators': { 'isEmail': {} },
                      label: "e-mail"
                  },
                  'birthday': {
                      base: 'date',
                      yearRange: '-100:+0',
                      label: 'What is your date of birth?'
                  },
                  'mondaysok': {
                      base: 'boolean',
                      label: 'Do you like mondays?'
                  },
                  'description': {
                      base: 'string',
                      control: 'textarea-control',
                      label: 'Describe yourself in 10 words'
                  }

          }};

10.2.2 Creating the form

10.2.2.1 Creating the Kauri form by giving the id to the Form constructor

When configured the form, all that rests is to create the form by calling the Form constructor with 2 arguments:

  1. the id of the form in html
  2. the fconf (form configuration) we created above
     jQuery(document).ready(function() {
          var basicForm = new jQuery.org.kauriproject.forms.Form("basic-form", fconf);
      });

And the html for this form looks as simple as this:

    <form id="basic-form" method="get" action="" >
    </form>

10.2.2.2 Creating the Kauri form with jQuery

Another possibility is to create the form in jQuery and passing this jQuery wrapper to function kauriform:

var basicForm = $("<form/>").appendTo($("div#someId")).kauriform(fconf);

10.3 Building Custom Controls

Before you start

Before venturing into creating own/custom controls for the kauri-framework we advise to

  1. Get an understanding of how the system works (read about the concepts, this document, the hackerguide and maybe even the actual code)
  2. Scan what is already there (both references and code) to make sure that what you need is not yet available. Maybe you'll find a close match from which your development can start.

Analyse The Value

The first aspect to consider is deciding which kind of value (type, structure) the control is expected to be editing.

Things to consider:

Write down the structure and a few samples, and note down the different "formats" of this value. I.e. the 'user-format' (i.e. its representation to the end-user) and the 'wire-format' (i.e. the representation-format sent in the json structure to-and-from the data-service)

Note that the user-format only is relevant when the user-interface actually foresees a string-representation of the value that is in some way end-user facing. This includes feedback-only purposes where the user-format is only read, never entered by the user.

Taking the sample of a date:

Understand how this 'value' step is also instrumental in the decision if you really should make a custom control or not:

If you can't come up with a specific value to be edited, then that probably is because there is no value at all. In such cases a kauri-control is not what you are looking for and you should probably investigate into creating some custom User Interface effects through applying jQuery or jQuery-UI stuff and investigate into blending that with your form-controls.

Formatters and Validators

Related to this value-structure you might want to evaluate if the control you envision requires any custom formatters or validators to ensure a correct (and guided) entry of new values.

To get up to speed with creating those we advise to read:

Responsibilities

The core job of your custom control is to manage the bridge between the HTML elements on the page (showing feedback to the user, and receiving his/her input) and the actual typed value kept inside the control.

The control base-class to start from does many of this already in a correct and consistent way. What makes your custom control 'different' however will be the custom look and interaction possibilities it will offer. That is what you will need to focus on.

Value Access

The first aspect to cover is how your control should deal with the value as being entered and fed back to the end-user. This is done through two methods:

  1. void setUserValue(value)
    This should take the passed string-value (it will already be formatted to string by the user-formatter) and use that to update the UI elements so it shows the new value.
  2. String getUserValue()
    This needs to read the (string) value as entered by the end user a return it to the caller.

To do so, both methods should typically operate on the 'input' element (@kauri-role) found in the HTML DOM/tree and associated to the control (@kauri-idref)

Standard initialization will make a reference to that element (jquery-wrapped) available through the getElement() method.

HTML Template Binding and/or Element Creation.

In fact that standard initialization process will have automatically found (or created) all associated HTML elements (i.e. the ones with the different roles as well).

For each kauri-role, this algorithm will use the 'select' and 'create' hints found in the 'elements' property of your control:

  elements[role] = {
     "select" : jQuery-selector-string,
     "create" : jQuery-creator-string (used when selector doesn't find the elements)
  }

After initialization all the found or created elements are available through the 'getElement(role)' method. (When omitted the role for the retrieved element is assumed to be 'input')

After this initial element-binding has happened the initElements(create) method will be called. In this method any additional lookups, element creation or other HTML/DOM initialization can occur. The passed argument 'create' is a boolean indicating if the control is operating in 'create' mode or not. This mode indicates that no matching 'input' element was found, and that all further not-found role elements are expected to be created by your code.

The 'binding' between control and matching HTML elements needs to work in two ways though. Up to now we've explained about the form looking up (or even creating) associated elements so DOM manipulation on them will make sure the UI reflects state changes are reflected in those elements.

The binding however also needs to work the other way around: when the user interacts with the HTML (i.e. mostly <form><input>) elements, the control should be triggered to perform value-parsing, validation, etc etc.

Therefore your control should register event-listeners with these elements. The default initialization already takes care of the change() event on the 'input' element associated to the control, but if you have other HTML elements to track, then you should use the initEvents() method to get that organized.

We advise using the jQuery event mechanism for registering your listeners.

Exposing events

The control itself will publish a 'valueChanged' event (which is distinct from the more low level HTML 'change' event). As we use the jQuery event mechanism for this as well, we 'tunnel' the event through the actual 'input' element of the control.

Your control might want to expose specific events when certain state-changes occur. By convention we advise to use the same 'input' element to do so. Depending on your case either initElements() or initEvents() will be the most logical place to put this standard snippet of code to introduce your own "myEvent"

      this._makeEventHandler("myEvent", optionalBindDataObject);

Triggering the event is done with:

       this.getElement().myEvent();

Or with the more verbose variant from jQuery in case you want to pass optional eventData

       this.getElement().trigger("myEvent", optionalEventData);

Registering a listener will typically happen from outside:

       var siblingControl = this.lookupControl('../sibling-name');
       this.getElement().myEvent(function() {
           // handling the event 
       } );

Event-handlers will be executed in the context of the $input element (i.e. the this reference will point to the control's input element to which the event is bound) and be passed two arguments:

  1. an Event Object (see jQuery documentation). 
  2. a so-called event-data object holding the merger of the optionalBindData and optionalEventData objects.  If not overwritten in the event-data, this will hold a reference to the control in evt.data.control itself.
Control Event Wiring

The form will initialize all its containing controls in an order that matches the logical top-down structure of the composing members. It is important to understand that this order is likely not to be in sync with the (rather arbitrary) dependency-sequence of different controls listening to each other's events.

More clearly: your control's own initElements() and initEvents() methods might be called well before those of the control emitting events it wants to listen to.

To avoid the issue where one is registering for an event that has not been exposed yet, a specific initEventWiring() method is foreseen on your control. This method is assured to be called only after all controls in the form have gone through their respective initElements() and initEvents().

Wrapping up:

  1. Event-declaration code should go into initElements() or initEvents().
  2. While initEventWiring() should be used to register your event-handler on some other control.

Coding

The framework offers an easy base-class for your controls to derive from. Below you find the typical (and minimal) frame of your own custom control.

;
( function( $) {

    var kf = $.org.kauriproject.forms;
    var controlTypes = kf.controlTypes;

The anonymous function construct above is a known technique to ensure no top level naming conflicts will occur. The variables we declare form a shorthand for the namespaces relevant for Kauri.

    $.inherit(MyControl, kf.Control);

    function MyControl( id, form, conf) {
        this['<super.init>'](id, form, conf);
    }

With the $.inherit we declare our control to be a subclass of the base control class.
Your constructor method can just delegate to the base implementation through the <super.init> call.
(One of the features of our prototype-inheritance system)

    MyControl.prototype.elements = {};
    $.extend(MyControl.prototype.elements, kf.Control.prototype.elements);
    $.extend(MyControl.prototype.elements, {
        "some-role" : {
            create :"<div class="my-control">html to create control element for role "some-role"</div>",
            select :"div.my-control"  // jQuery selector to find the some-role element without @kauri-role: if possible
        }
    });

Above you see how to inherit the base-class 'elements' and add specific element directives for your control.

    MyControl.prototype.initElements = function(create) {}

    MyControl.prototype.initEvents = function() {}

    MyControl.prototype.initEventWiring = function() {}
    

These steps in the control initialization have been explained above.
As well as the required user-value handling code below.

    MyControl.prototype.getUserValue = function() {

        var $input = this.getElement();
 
        // logic to read the value entered by the user from the HTML element

        return value; // should typically be a string
    }

    MyControl.prototype.setUserValue = function( value) {

        value = value || "";
        var $input = this.getElement();

        // logic to update the HTML element so it shows to the user what the current value is
    }


    kf.controlTypes.put("my-control", MyControl);

Finally the above line will register your new control which makes it available for referencing it from the fconf.

})(jQuery);

Internally our code uses exactly the same way of working, so check up on the already provided base-controls for more complete and complex examples.

10.3.1 Custom Formatters

Responsibility

The formatters in the kauri forms framework are simple and straightforward components that handle conversion between typed values and their string-representations.

The 'field' section of the Form Concepts page explains where those conversions fit in.

Formatters are expected to cover the conversion in both directions. Therefore two methods should be implemented:

  1. format:
  2. parse:

During either conversion one can decide that the offered input argument isn't suitable (This will most likely occur during 'parse' from string to typed value only.)  In such cases the implementation should just 'throw' a String-message, which will be displayed to the end user in the same way as a validation error.

Coding

The framework offers a base class to start your own formatter from.  Its main advantage is a re-usable 'fail' method that will ensure the required raising of validation error in the correct manner (and some recurring features like i18n, parameter injection etc etc)

;
( function( $) {

    var kf = $.org.kauriproject.forms;
    var formatters = kf.formatters;

The anonymous function construct above is a know technique to ensure no top level naming conflicts will occur. The variables we declare form a shorthand for the namespaces relevant for Kauri.

    $.inherit(MyFormatter, kf.Formatter);
    function MyFormatter( ) {
    }

With the $.inherit we declare our control to be a subclass of the base control class. 

The needed parse/format methods can then just be implemented as needed:

    MyFormatter.prototype.parse() = function(valstr) {

        // Expected behaviour is to trim input and intrerpret empty strings as containing "No Value"
        valstr = $.trim(valstr);
        if (valstr == "")
            return undefined;

        var value = ..... // code doing the parsing

        //in case of error:
        this.fail("this input: {0} is does not meet this pattern: {1}", [valstr, pattern]); // messages starting with 'i18n:' will be translated

        // or 
        this.fail("i18n:message-key", [args-to-inject]); // messages starting with 'i18n:' will be translated

        // or if all just works smoothly:
        return value; // should be a typed value
    }

    MyFormatter.prototype.format = function(value) {

        // Expected behaviour is to communicate 'no-value' as an empty string to the end-user
        // Actually: in case of wire-value formatting this rule does not apply, 
        //    however this will be checked in the system and undefined will be returned automatically.
        //    Like this you can re-use formatters for both purposes: 'wire' and 'user'
        if (val == undefined)
            return "";
        return val.toString();
    }

Note: the above is the default implementation for format: so if your typed value implementation has a fitting toString() then you don't need to code any additional format() method.

    kf.formatters.put("my-format", MyFormatter);

Finally the above line will register your new control which makes it available for referencing it from the fconf.

})(jQuery);
Declaring

Alternatively the formatter can be specified inside the form-config by placing it in the 'formatters' section. In that case the behaviour of the described base class will be automatically applied to it, allowing you to leav out quite some boiler-plate code:

Assuming the dafult format() is ok, you could deal with it like this:

var fconf = {
    ...

    'formatters':    {
        'my-formatter' : {
            'parse': function(valstr) {
                   // implementation here, including available calls to this.fail();
            }
        }
    }
}

10.3.2 Custom Validators

Responsibility

Validators are there for validating the input of end-users.

The ' field section' of the Form Concepts page explains where those validations fit in.

Validators have various events to report validation progress and results to the control holding the validator.

Coding

The framework offers a base class to start your own validator from.  Its main advantage that your only need to implement a validation method and return the validation status using calls to notifySuccess() or notifyFail(msg)
The anonymous function construct is a technique to ensure no top level naming conflicts will occur. The variables we declare form a shorthand for the namespaces relevant for Kauri.

;
( function( $) {

    var kf = $.org.kauriproject.forms;
    var validators = kf.validators;
    kf.validators.putAll( {
      "isPrime": { "validate": function(value) { 
        var primeFunc = function(n,f) {
          f = f || 2;
          if (n == f) return true;
          if (n%f==0||n==1) return false;
          return primeFunc(n, f+1);
        };
        if (primeFunc(value)) {
          return this.notifySuccess();
        } else {
          return this.notifyFail("That is not a prime number");
        }
      }}
    });
})(jQuery);
Declaring

Alternatively the validator can be specified inside the form-config by placing it in the 'validators' section. In that case the behaviour of the described base class will be automatically applied to it, allowing you to leav out quite some boiler-plate code:

Assuming the dafult format() is ok, you could deal with it like this:

var fconf = {
    ...

    'validators':    {
        'isPrime' : {
            'validate': function(valstr) {
                   // implementation here, including calls to this.notifySuccess() and this.notifyFail(msg);
            }
        }
    }
}

10.4 Forms Reference

Control types

Field types

Formatters

Validators

Name
autocomplete-control
case-control
collection-control
common for all controls
composite-control
date-range-control
datetime-control
dblselect-control
gmap-control
input-control
output-control
radioselection-control
selection-control
slider-control
textarea-control
upload-control
Name
boolean
case
collection
composite
date-range
datetime
decimal
file
integer
integer-range
location
string
time
Name
numeric
numeric-range
pattern
pattern-date
pattern-date-range
short-date
short-date-range
time
true-false
wire-date
wire-date-range
wire-date-time
Name
dateRange
dateRangeOrder
dayOfWeek
fieldComparer
isDate
isEmail
isInt
isIntRange
isOption
isUrl
length
range
regex
remote
required

Validators

Error messages

All validators have the possibility to customize their error message.
For example if you add the required validator and you want to set the error message "This field is absolutely required!".

"+validators" : 
{
   "required" : {"message" : 'This field is absolutely required!'}
}

Note: for some validators it is also possible to use some {0}, {1} arguments to show a configured value of the control.

10.4.1 Form configuration object

General sections

What goes into the form-config structure?

var fconf = {
  /* communication properties */
  "createURI": "${publicUri('service:/data/person/')}",

  /* described data structure */
  "members": {
    "name":    {   /* some string input */          },
    "sex" :    {   /* Male or Female choice */      },
    "birth:    {   /* date input */                 },
    "hobbies": {   /* flexible list of strings */   },
    "address": {   /* nested structure of street, number, zip, city and country */...}
  }  

  /* Additional custom types */
  "controlTypes": {
     "name-of-control": {  /*   definition */   }
  }
}
Form Specific properties

uri for create and read/write

Composite Control Config
Member Data Structure
Specific Config

(if any?)

Additional Custom Types

named, referable and extensible custom 'formatters, validators, fields and controls'

howto define?
howto use/refer?

10.4.2 Forms API

Control
Properties Methods

reset()

Sets the control back to its initial value. e.g. form.reset()

findControl(path)

Finds another control by its path.

  • path A path is a slash-separated list of control identifiers, e.g.
Examples:

  var street = form.lookupControl("/personal/addresses/2/street");
  var city = street.lookupControl("../city");

getWireValue()

Returns the current wire value of the control

setWireValue(wireValue[, noValidation])

Sets the current wire value of the control, optionally triggering validation.

  • wireValue: the wire value
  • noValidation: boolean indicating no validation is required

String getId()

Returns the control's id

Control getParent()

Gets the parent of the current control. Identical to this.lookupControl("..")

Control getForm()

Gets the form control that contains this control

Array getOptionValues()

If this control has an options object, return the values. (FIXME: wouldn't it make more sense to have getOptions().getValues()?)

Validator

Properties

Methods

notifySuccess()

Reports a validation success to the validation listener and returns true

notifyFail(msg, args)

Reports a validation failure to the validation listener.
  • msg: The message to display (See Message API)
  • args: Arguments for the message

notify(result, msg)

Reports a validation failure or success to the validation listener and returns 'result'.

  • msg: A Message object (See Message API)
  • args: Arguments for the message
ValidationListener

Each Validator uses validation listener to report validation results

Properties Methods

validationSuccess()

Event indicating a successful validation

validationFail()

Event indicating a failed validation

validationStart()

Event indicating validation is started

validationCompleted()

Event indicating validation is completed

validationIgnored()

Event indicating validation is ignored (this happens when a remote validation result arrives after a new validation round has already been triggered)

Formatter

Formatters are used to convert user input (strings) to objects and back. A control uses two formatters: one for converting between strings and user-values and one for converting between strings and wire-values.

Properties Methods

parse(str)

Parse the user input and return an object representation.

  • str: the string to parse

format(obj)

Convert the object to a string representation.

  • obj: the object to format

fail(msg, args)

A formatter should call this method when the parse or format functions can't complete normally.

  • msg: A Message object (See Message API)
  • args: Arguments for the message
Field

No properties or methods available in the public API

FieldType

No properties or methods available in the public API

Options
Properties

boolean shared

Indicates this options object is used by multiple controls

String uri

The uri template where the option's data are synchronously retrieved

Methods

boolean refreshable()

returns true if 'uri' is defined

void refresh()

fires an ajax request to refresh the values and labels

boolean updateable()

returns true if 'uri' is defined or if 'fixed' is false.

Events

update(eventHandler)

If the Register an event handler

  • eventHandler: An event handler for update events

use option.update() to manually trigger the update event.

10.4.3 Common Control Properties

TODO

10.4.3.1 Common Formatter Settings

TODO

10.4.3.2 Common Validator Settings

TODO

10.4.4 Fields

10.4.4.1 boolean

Specifications
Registered name

boolean

Properties
Control

checkbox-control

User-Format

true-false

Wire-Format

-

10.4.4.2 case

Specifications
Registered name

case

Properties
control

case-control

Default configuration

-

selector

fieldtype specifying the case selector

cases

object containing possible cases

User-Format
Wire-Format
Example
"cases": {
    "text" : {
        "base": "string",
        "label": "Text"
    },
    "number" : {
        "base": "decimal",
        "label": "Number"
    }
}

10.4.4.3 collection

Specifications
Registered name

collection

Properties
Control

collection-control

User-Format
Wire-Format

10.4.4.4 composite

Specifications
Registered name

composite

Properties
Control

composite-control

User-Format
Wire-Format

10.4.4.5 date-range

Specifications
Registered name

date-range

Properties
Base

composite

members
Control

composite-control

User-Format Wire-Format

wire-date-range

10.4.4.6 datetime

Specifications
Registered name

datetime

Properties
Base

composite

members
Control

composite-control

User-Format
Wire-Format

wire-date-time

10.4.4.7 decimal

Specifications
Registered name

decimal

Properties
Base

string

Control

input-control

Default configuration

-

User-Format

numeric

Wire-Format

numeric with rawFormat

10.4.4.8 file

Specifications
Registered name

file

Properties
Control

upload-control

10.4.4.9 integer

Specifications
Registered name

integer

Properties
Control

input-control

Default configuration 
User-Format

numeric

Wire-Format

numeric with rawFormat

10.4.4.10 integer-range

Specifications
Registered name

integer-range

Properties
Base

string

Control

slider-control

Default configuration 
User-Format

numeric-range

Wire-Format

numeric-range with rawFormat

10.4.4.11 location

Specifications
Registered name

location

Properties
Control

gmap-control

Inherits

composite

Members

User-Format

-

Wire-Format

-

10.4.4.12 string

Specifications
Registered name

string

Properties
Control

input-control

Default configuration

-

User-Format

trim

Wire-Format

-

10.4.4.13 time

Specifications
Registered name

time

Properties
Base

string

Control

input-control

User-Format

time

Wire-Format

time

10.4.5 Controls

10.4.5.1 autocomplete-control

Data Structure

The JSON structure used for a autocomplete control looks as follows:

{"name":"value"}
Form Config Syntax
dataUri

The uri where data can be looked up

inputTemplate

A string template that defines how the values are represented in the html input element

listTemplate

A string template that defines how the values are represented in the list template.

initial

Initial value

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls

Example
"contact": {
    "base": "string",
    "label": "Select a contact",
    "control": {
        "base": "autocomplete-control",
        "dataUri": "/data/contact/",
        "inputTemplate": "{id} - {name}",
        "listTemplate": "{id} - {name} {email}"
    }
}

with html

  <div kauri-idref="contact">
   <label kauri-role="label" for="contact"/>
   <input id="contact" type="text" kauri-role="input"/>
  </div>

10.4.5.2 case-control

Data Structure

The JSON structure used for an input control looks as follows:

{"casecontrolname":{"case":"selectedcase","value":"casevalue"}}
Form Config Syntax
nullable

boolean field which defined whether or not this selection can contain a 'empty' (nothing selected) value

null-text

which text to display when nothing selected (use in combination with nullable : true)

initial

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls

Example

configuration via fconf:

"tn": {
    "base": "case",
    "selector": some-selector-fieldtype,
    "label": "Text or Number?",

    "control": {
      "base": "case-control",
      "nullable": true,
      "null-text": "--- please select ---"             
    },
    "cases": {
        "t" : {
            "base": "string",
            "label": "Text"
        },
        "n" : {
            "base": "decimal",
            "label": "Number"
        }
    }
}

10.4.5.3 collection-control

Data Structure

The JSON structure used for a collection control looks as follows:

[
  "hello",
  "world",
  ...
]
Form Config Syntax
base

collection-control

initial

see the syntax common for all controls

example

note that 'cols' and 'rows' does not overrule the css properties of the textarea

control: {
  'base': 'collection-control',
  'control': {
    'base': 'collection-control',
    'templates' : {
      'layout': "<div style='border-style: dashed; border-width: 1px; ;margin: 10px; padding: 10px;'><div ><span kauri-role='label'/><span kauri-role='control'/><span kauri-role='messages'/><span kauri-role='delete'/></div></div>",
      'control': "<div kauri-role='container' ></div>"
    }
  }
}
Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

Specific Validators

This section describes any specific existing validators (if any) are available to validate the values managed by this control.

HTML Bindings

see the syntax common for all controls

Events

This section lists and describes the specific events produced by this control.

10.4.5.4 common for all controls

All controls have some common properties that aren't control specific.

Form Config Syntax
initial

initial is an object that defines some initial properties for the control:

templates

for each control, templates can be defined. These specify what the generated control should look like.

HTML Bindings

You can bind HTML to the form configuration. Via the attribute 'kauri-idref' you specify which kauri field you are binding the HTML to. This idref can be absolute or relative. If a piece of HTML is bound to the form configuration via kauri-idref, you can add some additional properties.

  1. you can specify which fieldtype it is using via kauri-type
  2. you can specify which controltype it is using via kauri-control
  3. you can add some initial properties (value, type="hidden", disabled)

Without attaching it to a specific fconf field (i.e. without specifying kauri-idref) you can also assign a piece of html code to be the layout of a collection or composite with the kauri-layout attribute. If a layout contains more then one HTML element, you can group them in kauri-group. And even more, when assigning layouts you can also assign positions to copy each layout clone via kauri-cursor.

kauri-idref

makes the coupling between the HTML and the form configuration.

example

fconf:

var fconf = {
    members: {
        'firstname':  {'base' : 'string'},
        'lastname':   {'base': 'string'}
}};
new jQuery.org.kauriproject.forms.Form("myform", fconf);

html :

<form id="myform">
     <label kauri-role="label" kauri-idref="firstname"/>
     <input kauri-idref="firstname" kauri-role="input"/>
     <label kauri-role="label" kauri-idref="lastname"/>
     <input kauri-idref="lastname" kauri-role="input"/>
</form>
kauri-type

specifies which FieldType to use for this field

Example

fconf:

var fconf = {
    members: {
    }
};
new jQuery.org.kauriproject.forms.Form("myform", fconf);

html :

<form id="myform">
     <input kauri-idref="firstname" kauri-role="input" kauri-type="string"/>
     <input kauri-idref="lastname" kauri-role="input"  kauri-type="string"/>
</form>

remark that in this example, the control type for "firstname" and "lastname" will default to the default controltype for the field-type "string".

kauri-control

specifies the ControlType to use for this field. This one is optional, if left out, it will default to the default ControlType of the according FieldType.

example

fconf:

var fconf = {
    controlTypes: {
        sliderControl: {
            base: 'slider-control',
            min: 1,
            max: 1000,
            step: 1,
            isRange: false
        }
    }
};

html :

<form id="myform">
     <span kauri-idref="size" kauri-type="integer" kauri-control="sliderControl" kauri-role="control"/>
</form>
kauri-role

assigns a 'role' to a field. Possible values for kauri-role are:

example

Following will generate a datepicker input control for you:

<span kauri-idref="birthday"  kauri-role="control" kauri-type="date"/>

While this will assume you know what you are doing (using some datepicker yourself) and will not generate anything:

<span kauri-idref="birthday"  kauri-role="input" kauri-type="date"/>
kauri-child kauri-layout

specifies a layout for a composite or a collection. This piece of HTML code will be cloned and inserted into the DOM for each child element of the composite/collection. Value of the kauri-layout atributes references the absolute path of the parent collection/composite control.

example

Collection "countries" will be displayed in a table. Each country will be displayed in a table row. To accomplish this we set kauri-idref="countries" at table level and kauri-layout="/countries" at row level. Remark that the latter contains a absolute path.

<table kauri-idref="countries" kauri-type="collection" >
  <thead>
    <tr>
      <th>Name</th>
      <th>Capital</th>
      <th>Area (km*km)</th>
    </tr>
  </thead>
  <tbody kauri-role="container" >
    <tr kauri-layout="/countries">
      <td >
        <input kauri-idref="name" kauri-type="string" kauri-role="control"/>
      </td>
      <td>
        <input kauri-idref="capital" kauri-type="string" kauri-role="control"/>
      </td>
      <td>
        <input kauri-idref="area" kauri-type="integer" kauri-role="control"/>
      </td>
    </tr>
  </tbody>
</table>
kauri-group

to group more then one HTML element in groups, use this attribute. Without kauri-group the layout assumes just one group.

example

Take the above kauri-layout example. Assume we want 2 rows per collection child, we cannot accomplish that with just the kauri-layout attribute. Those 2 <tr> elements can then be grouped by using the kauri-group attribute.

<table kauri-idref="countries" kauri-type="collection" >
  <thead>
    <tr>
      <th>Name</th>
      <th>Capital</th>
      <th>Area (km*km)</th>
    </tr>
  </thead>
  <tbody kauri-role="container" >
    <tr kauri-layout="/countries" kauri-group="country">
      <td >
        <input kauri-idref="name" kauri-type="string" kauri-role="control"/>
      </td>
      <td>
        <input kauri-idref="capital" kauri-type="string" kauri-role="control"/>
      </td>
    </tr>
    <tr kauri-layout="/countries" kauri-group="country">
      <td>
        <input kauri-idref="area" kauri-type="integer" kauri-role="control"/>
      </td>
    </tr>
  </tbody>
</table>
kauri-cursor

With kauri-cursor you have the possibility where to insert the cloned layout per child of the composite or collection. If we don't do this, the clone will be inserted at

  1. the position of the layout element in HTML
  2. the end of the containment element (first of 2 available will be used)

First option is not available if we use automatic rendering of the collection or composite.
If a kauri-cursor is found, this one will be used to insert the clone.

example
<table kauri-idref="people" kauri-type="collection" >
  <tbody kauri-role="container">
    <tr kauri-cursor="/people/#" kauri-group="peoplegroup" />
    <tr kauri-layout="/people/#" kauri-role="container" kauri-group="peoplegroup" >
      <td >
        <span kauri-idref="firstname" kauri-role="control" kauri-type="string"/>
      </td>
      <td>
        <input kauri-idref="lastname" kauri-role="input" kauri-type="string"/>
      </td>
      <td kauri-idref="children" kauri-type="collection" kauri-layout="/people/#/children/#" kauri-child="string" >
        <input kauri-role="input" kauri-type="string" />
      </td>   
    </tr>
    <tr kauri-cursor="/people/#" kauri-group="other"/>
    <tr kauri-layout="/people/#" kauri-group="mylabel" >
      <td kauri-cursor="/people/#/communications"  kauri-group="mylabel" /><!--  expliciet -->
      <td kauri-idref="communications" kauri-type="collection" kauri-layout="/people/#/communications/#" kauri-group="comGroup">
        <input kauri-idref="type" kauri-role="control" kauri-type="string" kauri-control="output-control"/>
        <input kauri-idref="value" kauri-role="input" kauri-type="string"/>
      </td>              
    </tr>
  </tbody>
</table>
initial properties

some attributes in html can be used to specify the initial properties

value="somevalue"
type="hidden"
disabled
Events

10.4.5.5 composite-control

Data Structure

The JSON structure used for a composite control looks as follows:

{
  "integermember": 15
  "stringmember": "hello world"
  "compositemember": {
    ...
  }
  "collectionmember": [
    ...
  }
}
Form Config Syntax
base

composite-control

members

{ "member1": ..., "member2": ... }

initial

see the syntax common for all controls

example

note that 'cols' and 'rows' does not overrule the css properties of the textarea

control: {
  'base': 'composite-control',
  'members': {
    'firstName': { base: 'string' },
    'lastName': { base: 'string' }
  }
}
Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

Specific Validators

This section describes any specific existing validators (if any) are available to validate the values managed by this control.

HTML Bindings

see the syntax common for all controls

Events

This section lists and describes the specific events produced by this control.

10.4.5.6 date-range-control

Data Structure

The JSON structure used for a date-range control looks as follows:

{"name":"2010-12-31/2011-21-31"}
Form Config Syntax
base

date-range-control

forceOrder

"asc", "desc", "none" to indicate whether the members should be automatically ordered ascending or descending or not.

(Default: "asc")

initial

see the syntax common for all controls

example

note that 'cols' and 'rows' does not overrule the css properties of the textarea

control: {
  'base': 'date-range-control',
  'forceOrder': 'desc'
}
Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

Specific Validators

This section describes any specific existing validators (if any) are available to validate the values managed by this control.

HTML Bindings

see the syntax common for all controls

Events

This section lists and describes the specific events produced by this control.

10.4.5.7 datetime-control

TODO

10.4.5.8 dblselect-control

Data Structure

The JSON structure used for a selection control looks as follows:

{"name":[{object1},{object2}]}
Form Config Syntax
showAddAll

this boolean field defines whether or not to show a '>>' button which adds all options at once

showRemoveAll

this boolean field defines whether or not to show a '<<' button which removes all options at once

showAddOther

this boolean field defines whether or not to show an input field to add a custom option

data

the list of options, defined in a JSON array

initial

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls

Examples
simple selection list with 3 options
"colors": {
  "base": "string",
  "label": "Colors",
  "control": {
    "base": "dblselect-control",
    "options": {
      "data": ["red", "green", "blue", "white", "black", "yellow", "purple"]
    },
    "showRemoveAll": true,
    "showAddAll": true                      
   }
}

10.4.5.9 gmap-control

Data Structure

The JSON structure used for a gmap control looks as follows

"location":{"latitude":"51.00833734239019","longitude":"3.712741613126127","zoom":"16"}
Used in

location

Form Config Syntax
base

gmap-control

initial

see the syntax common for all controls

example
locationControl: {
    base: 'gmap-control'
}
Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

Specific Validators

This section describes any specific existing validators (if any) are available to validate the values managed by this control.

HTML Bindings

see the syntax common for all controls

Events

This section lists and describes the specific events produced by this control.

10.4.5.10 input-control

Data Structure

The JSON structure used for an input control looks as follows:

{"name":"value"}
Form Config Syntax
password

this boolean field defines whether or not this input field is op type "password"

initial

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls

Example

configuration via fconf

"controlTypes": {
    "passwordControl": { 
        'base': 'input-control',
        'password' : true,
        'initial' : {
            'enable': false,
            'show' : true,
            'value': 'test'
        }
    }
}

configuration via html

<input kauri-idref="name" kauri-type="string" kauri-control="input-control" kauri-role="input" disabled="disabled" type="hidden"/>

10.4.5.11 output-control

Data Structure

The JSON structure used for an output control looks as follows:

{"name":"value"}
Form Config Syntax
base

output-control

html

this boolean field defines whether or not the value of the control should be shown as html or not

initial

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls for how to set initial properties via html

Example
"controlTypes": {
    "htmlTextControl": { 
        'base': 'output-control',
        'html' : true
    }
}

or via HTML

<span kauri-idref="tip-of-the-day2" kauri-control="output-control" kauri-type="string"/>

10.4.5.12 radioselection-control

Data Structure

The JSON structure used for a radioselection control looks as follows:

{"name":"value"}
Form Config Syntax
cols

number of columns used to display the possibilities

data

the list of options, defined in a JSON array

initial

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls

Example
"radio": {
  "base": "string",
  "label": "Value set",
  "control": {
    "base": "radioselection-control",
    "options": {
      "data": ["yes", "no", "maybe"],
      "cols": 3
    }
  }
}

10.4.5.13 selection-control

Data Structure

The JSON structure used for a selection control looks as follows:

{"name":"value"}
Form Config Syntax
showRefresh

this boolean field defines whether or not to show a refresh button next to the selection control

depends

selection-controls can depend on the value of other controls

options

the list of options. This options can be retrieved via a data field or via an uri which gets the list.

data

the list of options, defined in a JSON array

uri

uri which gets the option list as a JSON array

valuetemplate

template to use to render the value

labeltemplate

template to use to render the label used in the options list

nullable

boolean field which defined whether or not this selection can contain a 'empty' (nothing selected) value

null-text

which text to display when nothing selected (use in combination with nullable : true)

initial

see the syntax common for all controls

Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

HTML Bindings

see the syntax common for all controls

Examples
simple selection list with 3 options
"control": {
    "base": "selection-control",
    "options": {
        "data": ["yes", "no", "maybe"]
    },
    "initial": {
        "value": "maybe"
     }
}
selection list which gets the data from an uri
"control": {
    "base": "selection-control",
    "options": {
        "uri": "${publicUri('service:/data/getoptionlist/')}",
        "valueTemplate": "{id}",
        "labelTemplate": "{name}"
    }
}

where the service returns a structure like this:

[{"id" : "1", "name": "option1"}, {"id" : "2", "name": "option2"}, {"id" : "3", "name": "option3"}]
a refreshable selection list
"control": {
    "base": "selection-control",
    "options": {
        "uri": "${publicUri('service:/data/optionlist/')}",
        "showRefresh": true,
        "valueTemplate": "{id}",
        "labelTemplate": "{name}",
        "nullable": true,
        "null-text": "--- please select ---"
    }
}
selection list that depends on value of another control

in the 'depends' field the path of the needed control is given a name which then can be used in the uri:

"control": {
    "base": "selection-control",
    "depends": {"needThisOne": "/othercontrol"},
    "options": {
        "uri": "${publicUri('service:/data/optionlist/{needThisOne}/options')}",
        "valueTemplate": "{name}",
        "labelTemplate": "{name}"
    }
}
Events
var myform = new $.org.kauriproject.form.Form("form", fconf);
myform.findControl("/myselection").options.update(function() {
  //... do something with the options
});

10.4.5.14 slider-control

Data Structure

The JSON structure used for an input control looks as follows for a range slider:

"slider-range":{"start":"10","end":"20"}

and for a non-range slider:

"slider":"10"
Registered name

slider-control

Form Config Syntax
base

slider-control

isRange

true for range sliders, false for non-ranges

min

the minimum value possible

max

the maximum value possible

step

which step to use to change the value of the slider

initial

see the syntax common for all controls

HTML Bindings

see the syntax common for all controls

Example
sliderControl: {
    base: 'slider-control',
    min: 1,
    max: 1000,
    step: 1,
    isRange: false
}

10.4.5.15 textarea-control

Data Structure

The JSON structure used for a textarea control looks as follows:

{"name":"value"}
Form Config Syntax
base

textarea-control

rows

number of rows in the text area

cols

number of columns in the text area

readonly

boolean true|false to specify whether this textarea should be readonly or not. default is false.

initial

see the syntax common for all controls

example

note that 'cols' and 'rows' does not overrule the css properties of the textarea

control: {
  'base': 'textarea-control',
  'cols': 40,
  'rows': 10,
  'readonly' : false
}
Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

Specific Validators

This section describes any specific existing validators (if any) are available to validate the values managed by this control.

HTML Bindings

see the syntax common for all controls

Events

This section lists and describes the specific events produced by this control.

10.4.5.16 upload-control

Data Structure

The JSON structure used for an input control looks as follows:

{"uploadfieldname":{
  "charset":"WINDOWS-1252",
  "mimetype":"application/pdf",
  "size":43000,
  "id":"tmpresourceid",
  "filename":"filename.pdf",
  "fieldname":"file"}
}

fieldname is not implemented yet, and will always be "file"

Used in

file, upload-control is thus the default control-type for a field of type 'file'.

Form Config Syntax
base

upload-control

initial

see the syntax common for all controls

example
"uploadControl" : {
   "base" : "upload-control"
}
Specific Formatters

This section describes any specific existing formatters (if any) are available to format the values managed by this control.

Specific Validators

This section describes any specific existing validators (if any) are available to validate the values managed by this control.

HTML Bindings

see the syntax common for all controls

Events

This section lists and describes the specific events produced by this control.

10.4.6 Formatters

10.4.6.1 numeric

Description

format from a Number to a String and parse to a Number

Specifications
Registered name

numeric

Properties Methods

10.4.6.2 numeric-range

Description

Formats a String of format

"Number1 - Number2"
 

to object:

{ start: Number,  end : number }

and vice versa.

Specifications
Registered name

numeric-range

Properties Methods

10.4.6.3 pattern

Description

use a pattern to format or parse

patterns:

Specifications
Registered name

pattern

Properties Methods
Example

Pattern for a Belgian bank account: ###-#######-##

var f = getFormatter("pattern", {
    pattern :"###-#######-##"
});

format of "737000003679" returns "737-0000036-79",
parse of "  737-0000036-79  " returns "737000003679" (remark the trimmed string).

10.4.6.4 pattern-date

Specifications
Registered name

pattern-date

Properties Methods

10.4.6.5 pattern-date-range

TODO

10.4.6.6 short-date

Description

short-date is a pattern-date with a preconfigured pattern. Formatter is based on jQuery formatDate patterns.

Specifications
Registered name

short-date

Base Formatter

wire-date

Properties Methods

10.4.6.7 short-date-range

TODO

10.4.6.8 time

Description

time is structure of format "hh:mm:ss"

Specifications
Registered name

time

Methods

10.4.6.9 true-false

Description

formatter to formats or parses a Boolean value

Specifications
Registered name

true-false

Methods

10.4.6.10 wire-date

Description

wire-date is a pattern-date with a preconfigured pattern.

Specifications
Registered name

wire-date

Properties Methods

10.4.6.11 wire-date-range

Description

wire-date-range parses date  separated by a specified separator to object {start: Date, end : Date}

Specifications
Registered name

wire-date-range

Properties Methods

10.4.6.12 wire-date-time

Description

wire-date-time parses date and time separated by a specified separator to objects {date: datePart, time : timePart} where datePart and timePart are just 2 Strings

Specifications
Registered name

wire-date-time

Properties Methods

10.4.7 Validators

10.4.7.1 dateRange

Specifications
Registered name

dateRange

Base

range

Properties
Methods

10.4.7.2 dateRangeOrder

Specifications
Registered name

dateRangeOrder

Base Properties Methods

10.4.7.3 dayOfWeek

Specifications
Registered name

dayOfWeek

Properties
Methods
Example
{
  "base" : "dayOfWeek"),
  "dayOfWeek" : 0
}
new Date(2008, 7, 31)

validates (is a sunday)

new Date(2006, 7, 30)

Does not validate (isn't a sunday)

10.4.7.4 fieldComparer

Specifications
Registered name

fieldComparer

Properties
Methods
Used in

composite

10.4.7.5 isDate

Specifications
Registered name

isDate

Properties
Methods
Used in

DateControl

10.4.7.6 isEmail

Specifications
Registered name

isEmail

Methods

10.4.7.7 isInt

Specifications
Registered name

isInt

Methods
Used in

integer , isIntRange

10.4.7.8 isIntRange

Specifications
Registered name

isIntRange

Base

isInt

Methods
Used in

integer-range

10.4.7.9 isOption

Specifications
Registered name

isOption

Methods

10.4.7.10 isUrl

Specifications
Registered name

isUrl

Methods

10.4.7.11 length

Specifications
Registered name

length

Properties
Methods

10.4.7.12 range

Specifications
Registered name

range

Properties
Methods

Only integer steps are implemented so far

Used in

dateRange

Example
{ 
  "base" : "range", 
  "min" :-10,
  "max" :10,
  "step" :3
};

-15 : does not validate
-14 : does not validate
-12 : does not validate
-11 : does not validate
-10 : does validate
-9  : does not validate
-8  : does not validate
-7  : does validate
7   : does validate
"some text" : does not validate

10.4.7.13 regex

Specifications
Registered name

regex

Properties
Methods
Example

Pattern for a Belgian national register number: xx.xx.xx-xxx.xx

"+validators" : {
    regex:{
        "regex":/\d{2}\.\d{2}\.\d{2}-\d{3}\.\d{2}/
    } 
}

10.4.7.14 remote

Specifications
Registered name

remote

Properties
Methods

10.4.7.15 required

Specifications
Registered name

required

Methods

11 Internationalization (i18n)

The internationalization (i18n) support of Kauri includes:

11.1 i18n first steps

11.1.1 wiring.xml

If you generated your project from a template, then this might already be set up for you.

In the wiring.xml, add the following modules as first modules.

  <modules>
    <artifact id="i18n" groupId="org.kauriproject" artifactId="kauri-i18n-impl">
      <mount name="i18n" path="/kauri/i18n"/>
    </artifact>

    <artifact id="locale-assignment" groupId="org.kauriproject" artifactId="kauri-locale-assignment"/>

The kauri-i18n-impl module provides all i18n functionality, most notably resource bundle loading.

The locale-assignment module installs a Restlet filter which will determine the locale to use. This is a small module, which you could replace with your own if you want to use custom logic for this.

11.1.2 pom.xml

This step is optional. It is only necessary if you plan on programmatically making use of i18n, thus to lookup a translation or format a number or date from Java code.

In the pom.xml of your module, add the following dependency:

    <dependency>
      <groupId>org.kauriproject</groupId>
      <artifactId>kauri-i18n-api</artifactId>
      <version>${version.kauri}</version>
    </dependency>

11.1.3 Defaults configuration

(optional)  Create a file conf/locale-assignment/defaults.xml

<i18n ignoreClientInfo="true">
  <defaultLocale language="en" country="" variant=""/>
  <defaultTimeZone>UTC</defaultTimeZone>
</i18n>

option

@ignoreClientInfo

If true, the browser's accepted variants will be ignored.  Default false

defaultLocale

Default java.util.Locale.getDefault()  @country and @variant can be omitted

defaultTimeZone

Default UTC (not java.util.TimeZone.getDefault() - currently under discussion)

11.1.4 Create a resource bundle

Resource bundles should be put in an i18n directory in src/main/kauri. The name of the resource bundle should not conflict with those of other modules (except if by intention), therefore its name is namespaced using Java-style dotted notation. A suffix is added to specify the locale, such as _en (to include the country, use e.g. _nl_BE). The file extension should be .xml. So for example, we could create the following files:

src/main/kauri/i18n/org.myproject.mymodule_en.xml
src/main/kauri/i18n/org.myproject.mymodule_fr.xml

In the _en file, we could put this:

<?xml version="1.0"?>
<messages>
  <message key="yes">yes</message>
  <message key="no">no</message>
</messages>

In the _fr file, we could put this:

<?xml version="1.0"?>
<messages>
  <message key="yes">oui</message>
  <message key="no">non</message>
</messages>

11.1.5 Create a template

Assuming you have set up the pages router, you can create a template file at:

src/main/kauri/pages/i18ntest.html.xml

with something like this in it:

<html>
  <body>
   The word yes in your language is: ${i18n('yes')}.
  </body>
</html>

If you request this page in your browser, you will most likely see the word "yes", except if your browser would be configured to prefer french, in which case you will see "oui". The language en is by default used as fallback in case no bundle for the user's language is available.

The kauri-i18n-sample includes a settings page to change your locale. You can easily reuse this settings page as it is not part of the i18n sample itself, but is a resuable snippet provided by the kauri-i18n-impl module.

For more details about how the user's locale is determined, and how to change this, see Locale settings.

11.2 Locale settings

11.2.1 Setting and retrieving active locale settings

TODO:
- explain kauri-locale-assignment module + how to write your own
- explain LocaleSettings object, request attribute

11.2.2 Reusable snippet

TODO:
- explain + refer to kauri-i18n-sample

11.3 Resource bundles

TODO:
- bundles are put in src/main/kauri/i18n
- bundle names are Java-style namespaced
- bundle manager reads bundles from all modules (conflicts: fallback, later modules override previous modules, except in case of duplicate module instances)
- bundle format: XML. What with mixed content.

11.4 Templates integration

11.4.1 i18n:bundle attribute

This attribute defines from what bundle i18n messages should be retrieved. This attribute can occur on any element in the template, and applies to all content contained within the element (lexical scoping).

The i18n namespace is http://kauriproject.org/i18n

Example:

<html xmlns:i18n="http://kauriproject.org/i18n"
      i18n:bundle="org.myproject">
  ...
</html>

11.4.2 i18n() function

This function takes one argument: the key to retrieve a message from a resource bundle.

Example:

${i18n('my_message')}

11.4.3 format() function

The format function takes a variable number of arguments:

11.4.3.1 Format string syntax

11.4.3.1.1 Basics

The format string contains placeholders using  {...} syntax. If you want to insert {...} literally, escape it using backslash: \{...}.

The placeholder contains the index of the parameter to insert, and optionally some formatting arguments.

A simple format string thus might look like:

The quick {0} fox jumps over the {1} dog.

Used with the format function in the template language:

${format('The quick {0} fox jumps over the {1} dog.', 'brown', 'lazy')}

If the first argument would be part of a resource bundle below the key 'quick_dog_phrase', the usage would be:

${format(i18n('quick_dog_phrase'), 'brown', 'lazy')}
11.4.3.1.2 Formatting arguments

Formatting arguments are useful when the value to insert is not a string, but a date or number.

The full format of the placeholders is:

{index,type,style_or_pattern}

The parts are:

Dates will be adjusted to the user's timezone when formatting.

The table below lists the available types and styles.

Object type

Type

Style / pattern

dates

(java.util.Date
or
org.joda.time.ReadableInstant)

date

none / S / M / L / F (short/medium/long/full)

time

none / S / M / L / F

datetime

none / two characters from S / M / L / F / -

dtpattern

A joda-time date/time formatting pattern.

numbers

(java.lang.Number)

int

none

nrpattern

A Java SimpleNumberFormat pattern.

11.4.3.1.3 Examples
Format a single date:
${format("{0,date}", someDateObject)}

Format a single date using a pattern:
${format("{0,dtpattern,dd/MM/yyyy}", someDateObject)}

Format a date-time using long date format and small time format:
${format("{0,datetime,LS}", someDateObject)}

11.5 Server API

TODO

I18n object

Note: the I18nManager is made available via a ThreadLocal variable. If you spawn your own threads, you will have to take this into account, e.g. by passing a reference to the I18nManager manually.

11.6 Client API

Since web pages are often constructed dynamically by downloaded Javascript code, features such as translation and number formatting need to be available client-side as well.

i18n REST-service

The kauri-i18n-impl bundle exposes an 'i18n' REST-service. The main purpose of this REST-service is to make resolved resource bundles available.

Getting a bundle

Motivation: due to locale fallback (e.g. from nl-BE to nl to en), looking up a key from a resource bundle might require reading multiple resources, which might or might not exist, and it would not be efficient to access all those resources from the browser. Therefore, the i18n REST-service provides a 'resolved' resource bundle, which is a merged view of the resource bundle and its fallback bundles.

Getting a bundle is done through this resource:

/bundles/{bundle}/{locale}

for example:

/bundles/org.myproject.mybundle/fr_CH

The locale can also be specified in full lower case, and using dash as separator, e.g. fr-ch

The resource bundle is returned as a JSON object, allowing easy use from Javascript.

[TODO: if values include mixed content, are these part of the json?]

Getting lists of locales and timezones

To help build GUIs to let users select their locale and timezone, the following resources are also available:

/info/locales/{locale}
/info/locales
/info/countries/{locale}
/info/countries
/info/languages/{locale}
/info/languages
/info/timezones/{locale}
/info/timezones

The optional {locale} specifies the locale in which the list should be returned. These resources are used by the locale settings page, which can be seen in action in the kauri-i18n-sample.

Javascript API

Building a message an displaying the text:

var kf = $.org.kauriproject.forms;
var msg = kf.Messsage.build(key, args[, type, source])
alert(msg.getText())

Setting a message bundle:

The example below does not work because kf.locale.loadMessages(path) is not implemented in Kauri 0.4 - See http://dev.outerthought.org/trac/outerthought_kauri/ticket/167
In Kauir 0.4 you should use kf.locale.setMessages(messages);

var kf = $.org.kauriproject.forms;
kf.locale.loadMessages("/bundles/org.myproject.mybundle/fr_CH");

Integration with Kauri forms

Validators and parsers (see  forms API)  have various methods that take messages and arguments - those are used to build messages as described above.

12 Security

12.1 Introduction

Kauri Security helps you with implementing authentication and authorization.

Kauri reuses Spring Security, a well-known Spring-based security framework. Some parts of Spring Security—those related to authentication methods—are dependent on the Servlet API. Kauri is based on the Restlet API instead of the Servlet API, and therefore we redesigned those parts specifically for Kauri/Restlet. All authorization features, and Servlet-independent parts of the authentication can however be leveraged as-is within Kauri.

Spring Security is quite extensive and can take some time to master. For basic usage, you don't need to learn much of Spring Security, but you can just follow our first steps tutorial.

Kauri Security is not a core Kauri feature, but as usual comes in the form of a module (kauri-security-impl) you can add to your application. Through configuration (auth.xml), you can define which paths of which REST-services should be protected. These protections can be grouped into realms, each potentially using different authentication methods, user databases, or access decision managers.

All the authentication-related services have to be defined as beans in a Spring container of one of your modules, and will be refered to from within the auth.xml configuration. This gives the flexibility to use any combination of implementations of these services.

The kauri-security-impl module will install filters before all REST-services, in order to check the authentication and authorization constraints before the services are accessed.

The information about the currently authenticated user, this is typically called the security context, is accessible from within your application (resource classes, beans, ...) in order to perform fine-grained authorization checks.

12.2 More security

We should also point out that application-level security is more than using authentication and authorization. Common vulnerabilities in web applications are Cross Site Scripting and Injection Flaws, see for example the owasp site for more information on these topics.

12.3 Security: first steps

We will shows the steps to add basic authentication to an existing Kauri application. It will use a simple in-memory user store.

For the purpose of this tutorial, we assume you have already a working Kauri project with at least one module.

12.3.1 Adding the kauri-security-impl module

Edit your conf/kauri/wiring.xml file, add add the following module as the last one:

<!-- This module should come after any modules that need protection. -->
<artifact id="security" groupId="org.kauriproject" artifactId="kauri-security-impl"/>

12.3.2 Create the beans providing the authentication and authorization implementation

In your Spring bean configuration (services.xml), you will need to define some beans that provide security related services: a bean implementing an authentication method, a bean for checking the user credentials, a bean for taking access decisions, a bean for loading user details.

You can either add these to an existing module, or create a module specifically for this purpose.

Here we will assume you add these to an existing module, for the purpose of this example module1.

In any case, this module should be loaded before the kauri-security-impl module, thus should be listed before that one in the wiring.xml.

12.3.2.1 Add a dependency on kauri-security-auth-methods

The kauri-security-auth-methods project contains the implementation of common authentication methods (basic, digest, form-based, ...). Through transitive dependencies, this will also make available Spring Security's classes.

Edit module1/pom.xml

    <dependency>
      <groupId>org.kauriproject</groupId>
      <artifactId>kauri-security-auth-methods</artifactId>
      <version>0.4-dev-SNAPSHOT</version>
    </dependency>

12.3.2.2 Update classloader-template.xml

Create (or edit) the file module1/src/main/kauri/classloader-template.xml, and put the following in it (in case it exists: just add the <artifact> entry):

<classloader>
  <classpath>
    <!-- We need to explicitly share it because:
         - it needs to be in the same classloader as spring-security-core
         - and the runtime is currently not aware of dependencies between the jars
         -->
    <artifact groupId="org.springframework" artifactId="spring-tx" share="required"/>
  </classpath>
</classloader>

12.3.2.3 Define the Spring beans

Edit module1/src/main/kauri/spring/services.xml, and add the following beans to it:

  <bean id="userDetailsService" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
    <property name="userProperties">
      <props>
        <prop key="alice">alicepw,ROLE_USER</prop>
        <prop key="bob">bobpw,ROLE_ADMIN</prop>
      </props>
    </property>
  </bean>

  <bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
    <property name="providers">
      <list>
        <bean class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
          <property name="userDetailsService" ref="userDetailsService"/>
        </bean>
        <bean class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
          <property name="preAuthenticatedUserDetailsService">
            <bean class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
              <property name="userDetailsService" ref="userDetailsService"/>
            </bean>
          </property>
        </bean>
      </list>
    </property>
  </bean>

  <bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
    <property name="decisionVoters">
      <list>
        <bean class="org.springframework.security.vote.RoleVoter"/>
        <bean class="org.springframework.security.vote.AuthenticatedVoter"/>
      </list>
    </property>
  </bean>

  <bean id="basicAuthMethod" class="org.kauriproject.security.providers.BasicAuthenticationMethod"/>

12.3.3 Create the security configuration: auth.xml

Now we will create the actual security configuration file, called auth.xml.

In this file we define realms, in which a user can authenticate using one or more authentication methods, and which define protect-rules that guard the access to REST-services.

In the example below, we assume your module1 has a REST-service called main of which all paths should belong to this realm.

Create the file conf/security/auth.xml within your existing conf directory, and put the following into it:

<?xml version="1.0"?>
<auth>
  <realms>

    <realm name="realm1">
      <authenticationMethods>
        <authenticationMethod moduleId="module1" beanId="basicAuthMethod"/>
      </authenticationMethods>
      <authenticationManager moduleId="module1" beanId="authenticationManager"/>
      <accessDecisionManager moduleId="module1" beanId="accessDecisionManager"/>
      <protect module="module1" restservice="main" path="**" access="ROLE_USER,ROLE_ADMIN"/>
    </realm>

  </realms>
</auth>

The various tags with moduleId and beanId attributes point to the beans we defined earlier on.

12.3.4 Trying it out

You will need to rebuild your project (mvn install) and restart Kauri.

If you then surf to a URL that is protected by the above configuration, you should be prompted for username and password.

See the userDetailsService configured in the Spring container for the available credentials, e.g. username "alice" and password "alicepw".

12.3.5 Next steps

12.4 Security configuration

12.4.1 Intro

Kauri Security is configured through a central configuration file called auth.xml, which contains references to Spring beans for delivering actual authentication and authorization logic.

While you can specify both authentication and authorization conditions in the auth.xml, one will often do more detailed authorization checks in e.g. resource classes, based on the established security context.

12.4.2 auth.xml syntax overview

The auth.xml file is typically located in conf/security/auth.xml. The name of the "security" directory should correspond to the id of the kauri-security-impl module in the wiring.xml.

<?xml version="1.0"?>
<auth>
  <realms>

    <realm name="...">

      <authenticationMethods>
        <!-- You can list multiple authentication methods -->
        <authenticationMethod moduleId="..." beanId="..." strength="..."/>
      </authenticationMethods>

      <authenticationManager moduleId="..." beanId="..."/>

      <accessDecisionManager moduleId="..." beanId="..."/>

      <!-- Either you specify one objectDefinitionSource or one or more
           protect elements (which internally are used to build a default
           ObjectDefinitionSource. -->
      <objectDefinitionSource moduleId="..." beanId="..."/>

      <protect module="..." restservice="..." path="..."
               type="ant|template|regex" method="..." access="..." strength="..."/>

    </realm>

  </realms>
</auth>

12.4.3 Determining the realm

Remember that Kauri Security will install a filter before each of your REST-services. When a request goes through such a security filter, it will check if the request is protected by any of the realms defined in the auth.xml.

The realms are checked in the order listed in the auth.xml, the first matching realm is used. A matching realm is one for which there is a protect-rule that matches the current module, restservice, request path and request method.

In Spring Security terminology, the protect-rules are used to configure an ObjectDefinitionSource, and instead of protect-rules you can also specify a custom ObjectDefinitionSource.

12.4.4 The protect rules

Here we discuss everything you need to know about the protect rules, defined by the <protect> elements.

12.4.4.1 Nesting of protect rules

You can have one or more of these <protect> elements. They can be nested, in case of nesting, only the leaf <protect> elements (= those without children) define actual protect rules. The parent <protect> elements are used to define common attributes, which will be inherited by the child protect elements.

Some examples will clarify this:

Example 1
---------
<protect module="moduleA" restservice="service1" path="/foo/*" access="ROLE_USER"/>
<protect module="moduleA" restservice="service1" path="/bar/*" access="ROLE_ADMIN"/>

can be rewritten as

<protect module="moduleA" restservice="service1">
  <protect path="/foo/*" access="ROLE_USER"/>
  <protect path="/bar/*" access="ROLE_ADMIN"/>
</protect>

Example 2
---------
<protect module="moduleA" restservice="service1" path="/foo/*" access="ROLE_USER"/>
<protect module="moduleA" restservice="service1" path="/bar/*" access="ROLE_ADMIN"/>
<protect module="moduleB" restservice="service1" path="**" access="ROLE_USER,ROLE_ADMIN"/>

can be rewritten as

<protect module="moduleA">
  <protect restservice="service1">
    <protect path="/foo/*" access="ROLE_USER"/>
    <protect path="/bar/*" access="ROLE_ADMIN"/>
  </protect>
</protect>
<protect module="moduleB">
  <protect restservice="service1" path="**" access="ROLE_USER,ROLE_ADMIN"/>
</protect>

While the examples above perform grouping by the logical hierarchy module > restservice > path, you could also group them by access or any other attribute.

12.4.4.2 Order of the protect rules

The order of the protect rules is important: the first matching rule will be used.

12.4.4.3 The path and type attributes

The path attribute is an expression matching the request path, and the type attribute specifies the type of expression.

The type can be:

The path that should be matched is the path handled by the particular REST-service, thus already stripped from the prefix on which the REST-service is mounted in the wiring.xml. The query string is not part of the path either. The path is decoded, so all escaped sequences (%HH) will be replaced by the actual characters.

12.4.4.4 The method attribute

Can contain an HTTP method name such as GET, PUT, POST or DELETE. The rule will only apply for a request if the method of the request is the same as the value of this method attribute.

12.4.4.5 The access attribute

The access attribute is a comma separated list of values. These values are typically role names, but for completeness we should mention that in Spring Security these are called configuration attributes, and they might represent other things.

For advanced usage: the configuration attributes don't need to be strings, though this configuration only allows for string-based configuration attributes. In case you want something else than strings, you can use a custom ObjectDefinitionSource using the <objectDefinitionSource> element.

12.4.5 The authentication methods

For each realm, you can list multiple authentication methods. The actual authentication method implementations should be defined as beans in a Spring container of a module, and you use the moduleId and beanId attributes to refer to them. There are various implementations available.

Each authentication method can optionally specify a strength (default is 0), this strength corresponds to the strength attribute on the <protect> elements (default also 0).

When a request is matched to a certain realm, the authentication methods of that realm will each be asked to find authentication information (e.g. username and password) on the request. The authentication information from the first highest-strength authentication method will be used.

If none of the authentication methods returns authentication information, the client will be challenged. The authentication method that will produce the challenge is the first one listed, that has a high enough strength: the strength attribute on the <authenticationMethod> element is >= the strength attribute on the <protect> element.

If the authentication information is returned by an authentication method which does not have high enough strength, then the client will also be challenged.

12.4.6 AuthenticationManager and AccessDecisionManager

Each realm needs a reference to an AuthenticationManager and an AccessDecisionManager. These are concepts from Spring Security.

Both of these should be defined as beans in a Spring container of a module, and are refered to using the moduleId and beanId attributes.

The AuthenticationManager is responsible for validating the authentication information returned by the authentication method (e.g. username-password) and returning fully populated authentication information (e.g. with the granted authorities, mostly the roles, of the user added).

The AccessDecisionManager is responsible for taking authorization decisions.

Both can be extensively customized through the Spring bean configuration. We refer to the Spring Security documentation for more information.

12.5 Authentication methods

Kauri ships with a variety of authentication methods, and you can write your own ones as well.

To use Kauri's authentication methods, add kauri-security-auth-methods as a dependency to your project, and instantiate the beans as described in their reference documentation.

12.5.1 Basic authentication

12.5.1.1 About

See wikipedia.

12.5.1.2 Usage

The BasicAuthenticationMethod has no dependencies. The same instance can be reused in multiple realms.

<bean id="basicAuthMethod"
      class="org.kauriproject.security.providers.BasicAuthenticationMethod"/>

12.5.2 Digest authentication

12.5.2.1 About

See wikipedia.

12.5.2.2 Usage

<bean id="digestAuthMethod"
      class="org.kauriproject.security.providers.DigestAuthenticationMethod">
  <property name="userDetailsService" ref="userDetailsService"/>
</bean>

12.5.3 Form-based authentication

12.5.3.1 About

Form-based authentication is likely the most widely used authentication method on the human-accessible Web.

Despite this, it is not really RESTful as it relies on the server to keep some state, and it doesn't play well with the typical challenge-scenario of HTTP.

It does however provide some important advantages:

12.5.3.2 Usage

The form-based authentication process consists of a combination of three components:

If you want to use form-based authentication for multiple realms, you will need to make multiple instances of the LoginRestlet (as it needs the realm name) and the formAuthMethod (as it links to a specific LoginRestlet).

<bean id="formAuthMethod"
      class="org.kauriproject.security.providers.FormAuthenticationMethod">
  <constructor-arg ref="module"/>
  <property name="preAuthTokenStore" ref="preAuthTokenStore"/>
  <property name="loginFormUrl" value="service:/loginRestlet"/>
</bean>

<bean id="preAuthTokenStore"
      class="org.kauriproject.security.providers.InMemoryPreAuthTokenStore">
</bean>

<bean id="loginRestlet" class="org.kauriproject.security.providers.LoginRestlet">
  <constructor-arg ref="restletContext"/>
  <constructor-arg ref="module"/>
  <property name="realm" value="realm3"/>
  <property name="preAuthTokenStore" ref="preAuthTokenStore"/>
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="representationName" value="loginform"/>
  <property name="defaultTargetUrl" value="/"/>
</bean>

<kauri:export-restservice name="loginRestlet" ref="loginRestlet"/>

You will need to mount the loginRestlet on some path, using the wiring.xml.

Your AuthenticationManager will need to be able to handle so-called "PreAuthenticatedAuthenticationToken" tokens, therefore add a PreAuthenticatedAuthenticationProvider to it, like this:

  <bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
    <property name="providers">
      <list>

        [... add here any other (especially non-pre-auth) providers you use ...]

        <bean class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
          <property name="preAuthenticatedUserDetailsService">
            <bean class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
              <property name="userDetailsService" ref="userDetailsService"/>
            </bean>
          </property>
        </bean>
      </list>
    </property>
  </bean>

To handle logout, a LogoutRestlet is available. Logout is an optional feature, it is not necessary for the form based authentication to work.

<bean id="logoutRestlet" class="org.kauriproject.security.providers.LogoutRestlet">
  <constructor-arg ref="restletContext"/>
  <constructor-arg ref="module"/>
  <property name="realm" value="realm3"/>
  <property name="preAuthTokenStore" ref="preAuthTokenStore"/>
  <property name="defaultTargetUrl" value="/"/>
</bean>

<kauri:export-restservice ref="logoutRestlet"/>

12.5.3.3 Technical background

Kauri handles the form-based login somewhat differently than Spring.

In Spring, the HttpSessionContextIntegrationFilter is responsible for putting the SecurityContext in the session.

In Kauri (and Restlet), sessions do not exist. Therefore the form-based authentication method itself is responsible for keeping the cookie-to-credentials mapping.

Another difference is that Kauri does not store the SecurityContext, but rather a PreAuthenticatedAuthenticationToken. The authentication itself (thus the loading of the SecurityContext) is done fresh on each request. While this moves the responsibility for caching (for performance, if needed) from the session to a lower layer, it should be easier to manage.

In contrast with session-based alternatives, Kauri's form based authentication supports multiple realms.

12.5.4 Belgian eID authentication

12.5.4.1 About

Belgium's identity card, called the eID, is a smart card that can be used for authentication.

In a Web-environment, we can do the authentication in two ways:

  1. client-side, using a Java applet.
  2. using https with client authentication

Kauri's BelgianEidAuthenticationMethod uses the second way, which is also the way used by most government sites.

From the point of view of Kauri, most work is done by the SSL protocol and the client-side eID-supporting software.

The kauri-security-sample contains a sample of Belgian eID. The sample includes a keystore containing the Belgium Root CA(2), and has a HTTPS connector running, so if you have an eID and a smart card reader, you can easily try it out.

12.5.4.2 How it works

Essentially, the eID authentication method works by redirecting to a https URI for which client authentication is enabled.

Configuring HTTPS and enabling client authentication is a matter of Web server configuration.

Kauri relies on the client certificates to be available in the request atribute org.restlet.https.clientCertificates. This will be the case if you enable the HTTPS connector of Restlet

Right now it likely won't work if you handle the SSL on a reverse proxy, for example an Apache in front of Kauri, though as it is possible to forward the certificates via a request header, it should be possible to make this work.

Upon successful https authentication, the client certificate will need to be mapped to a certain user in your system. This can be done using the serial number stored in the certificate's subject.

12.5.4.3 Usage

12.5.4.3.1 Setting up HTTPS

You need to create a keystore, containing:

  1. The certificate and private key for the own server.

  2. The Belgium Root CA certificates. This is because in case of client authentication, the server needs to tell the client what certification authorities it accepts.

Information on the first step can be found in the Jetty documentation.

For the second step, see the section further on.

To add the HTTPS connector, create a conf/kauri/ connectors.xml file and configure it e.g. as follows:

<connectors>
  <serverConnector protocols="HTTP" port="8888">
  </serverConnector>

  <!-- If you change the port for https, adjust it also in the services.xml -->
  <serverConnector protocols="HTTPS" port="8443">
    <!-- The following assumes the keystore file can be found in the working directory. -->
    <parameter name="keystorePath">keystore</parameter>
    <parameter name="keystorePassword">foobar</parameter>
    <parameter name="keyPassword">foobar</parameter>
    <parameter name="needClientAuthentication">true</parameter>
  </serverConnector>

  <clientConnector protocols="HTTP"/>
  <clientConnector protocols="FILE"/>
  <clientConnector protocols="CLAP"/>
</connectors>
12.5.4.3.2 Spring
<bean id="beidAuthMethod" class="org.kauriproject.security.providers.BelgianEidAuthenticationMethod">
  <property name="principalExtractor" ref="beidPrincipalExtractor"/>
  <property name="httpsPort" value="8443"/> <!-- See also the port number in connectors.xml -->
  <property name="challengePage" value="service:/main/belgian_eid_infopage.html"/>
  <property name="restletContext" ref="restletContext"/>
</bean>

<bean id="beidPrincipalExtractor" class="org.kauriproject.samples.security.SampleBelgianEidPrincipalExtractor">
  <property name="userDetailsService" ref="userDetailsService"/>
</bean>

The challengePage property is optional. Its purpose is to show the user a page telling that he should insert the eID card into the card reader before continuing. When not used, the user is immediatelly redirected to the https URL.

The BelgianEidPrincipalExtractor maps the certificate to a username. You will have to create your own implementation of this.

12.5.4.4 Limitations

See also this GSoC idea page for more information.

12.5.4.5 Adding the Belgium Root CA certificates to your keystore

Just for convenience, we show here how to add the root certificates to your key store.

First create the following files.

belgianroot.pem

-----BEGIN CERTIFICATE-----
MIIDlDCCAnygAwIBAgIQWAsFbFMk27JQVxhf+eWmUDANBgkqhkiG9w0BAQUFADAn
MQswCQYDVQQGEwJCRTEYMBYGA1UEAxMPQmVsZ2l1bSBSb290IENBMB4XDTAzMDEy
NjIzMDAwMFoXDTE0MDEyNjIzMDAwMFowJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMT
D0JlbGdpdW0gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMihcekcRkJ5eHFvna6pqKsot03HIOswkVp19eLSz8hMFJhCWK3HEcVAQGpa+XQS
J4fpnOVxTiIs0RIYqjBeoiG52bv/9nTrMQHnO35YD5EWTXaJqAFPrSJmcPpLHZXB
MFjqvNll2Jq0iOtJRlLf0lMVdssUXRlJsW9q09P9vMIt7EU/CT9YvvzU7wCMgTVy
v/cY6pZifSsofxVsY9LKyn0FrMhtB20yvmi4BUCuVJhWPmbxMOjvxKuTXgfeMo8S
dKpbNCNUwOpszv42kqgJF+qhLc9s44Qd3ocuMws8dOIhUDiVLlzg5cYx+dtA+mqh
pIqTm6chBocdJ9PEoclMsG8CAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYD
VR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4AQEBMC4wLAYIKwYBBQUHAgEW
IGh0dHA6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQ8AxW
m2HqVzq2NZdtn925FI7b5jARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAU
EPAMVpth6lc6tjWXbZ/duRSO2+YwDQYJKoZIhvcNAQEFBQADggEBAMhtIlGKYfgP
lm7VILKB+MbcoxYA2s1q52sq+llIp0xJN9dzoWoBZV4yveeX09AuPHPTjHuD79ZC
wT+oqV0PN7p20kC9zC0/00RBSZz9Wyn0AiMiW3Ebv1jZKE4tRfTa57VjRUQRDSp/
M382SbTObqkCMa5c/ciJv0J71/Fg8teH9lcuen5qE4Ad3OPQYx49cTGxYNSeCMqr
8JTHSHVUgfMbrXec6LKP24OsjzRr6L/D2fVDw2RV6xq9NoY2uiGMlxoh1OotO6y6
7Kcdq765Sps1LxxcHVGnH1TtEpf/8m6HfUbJdNbv6z195lluBpQE5KJVhzgoaiJe
4r50ErAEQyo=
-----END CERTIFICATE-----

globalsignroot.pem

-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
-----END CERTIFICATE-----

belgianroot2.pem

-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE
BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw
WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1
bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S
/3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61
IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU
+40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr
XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y
HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL
TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6
Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD
lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7
vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc
UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK
JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW
nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8
KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F
sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO
hXY=
-----END CERTIFICATE-----

And then load them into your keystore like this:

keytool -keystore keystore -import -alias belgianroot -file belgianroot.pem -trustcacerts
keytool -keystore keystore -import -alias belgianroot2 -file belgianroot2.pem -trustcacerts
keytool -keystore keystore -import -alias globalsignroot -file globalsignroot.pem -trustcacerts

12.5.5 Creating your own authentication method

To make available a new authentication method in Kauri, you only need to implement one interface:

org.kauriproject.security.AuthenticationMethod

The implementation then needs to be instantiated as a bean in a Spring container of a module, and referred to from within the auth.xml.

The existing implementations in the Kauri source code might provide some inspiration.

12.6 Security context

12.6.1 Intro

After successful authentication, some security context is initialized to make the authenticated user available to the rest of the application, for authorization purposes.

12.6.2 The Spring SecurityContext

The primary source of security context is Spring's Authentication token in the SecurityContext. This context is maintained as a thread-local variable via the SecurityContextHolder class.

import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.Authentication;
import org.springframework.security.userdetails.UserDetails;

Authentication existingAuthToken = SecurityContextHolder.getContext().getAuthentication();
String username = ((UserDetails)existingAuthToken.getPrincipal()).getUsername();

12.6.3 Restlet Security Context

Kauri propagates some of security context toward Restlet's Request.clientInfo.subject object, by adding org.restlet.security.RolePrincipal and UserPrincipal objects into it. This makes the ClientInfo.isInRole() method work.

12.6.4 Request attribute "principal"

The principal object (Authentication.principal) is made available as a request attribute called "principal". This allows for easy access from e.g. templates.

12.6.5 Security in resource classes

12.6.5.1 Restlets, Restlet resources and filters

You can either use Spring's SecurityContext directly, or use Restlet's security context.

Here is an example of using the Restlet API:

// Suppose getRequest() and getApplication() return the corresponding Restlet objects
ClientInfo clientInfo = getRequest().getClientInfo();
Role userRole = getApplication().findRole("ROLE_USER");

if (clientInfo.isInRole(userRole)) {
   // do something
}

12.6.5.2 JAX-RS

JAX-RS has its own API that allows to check if users have certain roles. This is done by injecting a SecurityContext in your resource class.

Here is some sample code:

package org.kauriproject.samples.security;

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.Context;

@Path("roleSensitiveJaxRsResource")
public class RoleSensitiveJaxRsResource {
    // The SecurityContext will be injected by the JAX-RS system.
    @Context
    SecurityContext securityContext;

    @GET
    @Produces("text/plain")
    public String get() {
        if (securityContext.isUserInRole("ROLE_ADMIN")) {
            return "Hello from a JAX-RS resource class, person in ROLE_ADMIN role!";
        } else if (securityContext.isUserInRole("ROLE_USER")) {
            return "Hello from a JAX-RS resource class, person in ROLE_USER role!";
        } else {
            return "Hello from a JAX-RS resource class, you are not in ROLE_ADMIN or ROLE_USER.";
        }
    }
}

12.6.6 Security in templates

12.6.6.1 t:protect

The template language features a t:protect element to conditionally show content.

<t:protect access="...">
  [protected content here]
</t:protect>

This protect element is quite similar to the one in the auth.xml. The access attribute contains a comma-separated list of "configuration attributes" (this is Spring Security terminology). Often these are role names.

The way in which these are used to determine your access depends on the AccessDecisionManager of the current realm. For example, supposing you list some role names, the user might either need to have only one of those roles, or might need to have them all.

12.6.6.2 Showing the name of the current user

${request.attributes.principal.username}

12.7 Technical overview

12.7.1 Spring Security

If you wish to go beyond the superfical level, you will have to study Spring Security. There is extensive documentation available.

Spring Security comes with is own set of concepts, such as Authentication, SecurityContext, GrantedAuthority, ConfigAttribute, ConfigAttributeDefinition, ObjectDefinitionSource, AccessDecisionManager, etc.

12.7.2 Relation between Kauri Security and Spring Security

Kauri reuses Spring Security, with the exception of the Servlet-specific parts. More specifically, this means the concept of the "filter chain" from Spring Security, with its various ProcessingFilters and its matching AuthenticationEntryPoints, is not used within Kauri. We have not modified Spring Security, we reuse the binary release as-is, we just don't use some of its classes.

The Servlet-specific parts in Spring Security have to do with authentication and web-level authorization. Since authentication is split in different stages, even there we can reuse most of Spring Security as-is. The follow table summarizes these stages, and as you can see, it is only the first stage which we had to change for Kauri.

Authentication stage

Spring Security or Kauri Security object responsible

reading authentication information from request or challenging the user.

org.kauriproject.security.AuthenticationMethod (orchestrated by the security filter)

validating the authentication information and returning a populated Authentication token

org.springframework.security.AuthenticationManager

loading user information

org.springframework.security.userdetails.UserDetailsService

making security information available

org.springframework.security.context.SecurityContext(Holder)

The object-level (AOP) authorization features of Spring Security do their work based on the SecurityContext, and hence all work as expected.

For Web-level security, you can directly access the SecurityContext, or do it through Restlet or JAX-RS APIs, as explained in Security context.

12.7.3 Relation between Kauri Security and Restlet security

Kauri does not make use of Restlet's security features, though we do populate Restlet's security context (Request.clientInfo.subject), which should make its authorization filters work.

12.7.4 Internal requests

Since internal requests operate within the same executing thread as the launching thread, they re-use the same SecurityContext. No re-authentication happens.

In case an internal request is performed from a daemon thread, outside of the scope of another request, the usual authentication challenging will performed.

13 Runtime

The Kauri Runtime is the platform on which Kauri applications run.

It provides the basic infrastructure for:

The documentation is still mostly todo, but we have already availabe:

13.1 wiring.xml reference

13.1.1 Index

<?xml version="1.0"?>
<wiring>
  <virtualHosts default="">
    <virtualHost name="" hostPort="" hostDomain="" hostScheme="" canonicalUri=""/>
  </virtualHosts>

  <modules>

    <file id="" path="">
      <mount name="" path="" virtualHost="" canonical=""/>
      <inject-restservice name="" ref="module:service"/>
      <inject-javaservice name="" service="" ref=""/>
    </file>

    <artifact id="" groupId="" artifactId="" classifier="" version="">
      <mount name="" path="" virtualHost="" canonical=""/>
      <inject-restservice name="" ref="module:service"/>
      <inject-javaservice name="" of service="" ref=""/>
    </artifact>

    <directory id="" path=""/>

  </modules>
</wiring>

13.1.2 Element description

13.1.2.1 wiring

The root element.

13.1.2.2 virtualHosts

This element is optional.

This element is used in case you want your application to handle requests for different virtual hosts.

Remember that one Kauri Runtime instance usually corresponds to one application. If you have multiple applications that you want to associate with different virtual hosts, you would rather launch these as separate Kauri instances, and use other techniques such as putting an Apache httpd instance in front to distribute the requests to the different Kauri instances.

Attributes:

13.1.2.3 virtualHost

Attributes:

We demonstrate the use of virtual hosts and the purpose of the canonicalUri's using an example.

<runtime>
  <virtualHosts default="web">
    <virtualHost name="static" hostDomain="static.kauriproject.org" canonicalUri="http://static.kauriproject.org"/>
    <virtualHost name="web" hostDomain="www.kauriproject.org" canonicalUri="http://www.kauriproject.org"/>
  </virtualHosts>

  <modules>
    <artifact id="webmodule" ...>
      <inject-restservice name="static" ref="staticmodule:files"/>
      <mount name="myservice" path="/foo" virtualHost="web"/>
    </artifact>

    <artifact id="staticmodule" ...>
      <mount name="files" path="" virtualHost="static"/>
    </artifact>

  </modules>

</runtime>

Suppose the webmodule generates a page with a template that creates a link as follows:

<a href="${publicUri('service:/static/downloads/bar.zip')}">bar.zip</a>

The purpose of the publicUri() function is to translate the service-URI in the argument to a public URI. The "static" service of the webmodule is provided by the "files" service of the staticmodule, which is mounted on the path "" on the virtualHost static. Since the virtual host is different from the request to the webmodule, the publicUri() function will generate an absoute URI: http://static.kauriproject.org/downloads/bar.zip.

13.1.2.4 modules

The modules element is the most important part of the runtime configuration: it specifies which modules to launch, and the wiring of the services between them.

Modules can be specified in three ways: using file references, using artifact references, or by specifying a directory containing module jars.

Each module is identified by a unique id. Within the wiring.xml, this is used for describing the wiring between the modules. At runtime, it may be used for informational or error messages.

The order in which the modules are defined is important. It is in this order that the modules will be started. The wiring between the modules needs to be such that there are no forward references to modules which are not yet launched. To put it in another way, the Kauri Runtime is currently not smart enough to figure out the startup order itself.

13.1.2.5 file

Specifies a module using a file reference.

Might be useful sometimes, but in general we recommend to refer to modules as artifacts.

Attributes:

13.1.2.6 artifact

Specifies a module using a Maven repository reference.

Attributes:

13.1.2.7 directory

Using directory, you can tell the runtime to launch all the modules jars in the specified directory (non-jar files will be ignored).

The modules will be loaded in alphabetical order according to their file name.

When using directory, explicit wiring between modules and mounting of restservices is not possible.

Attributes:

13.1.2.8 mount

Mounts a REST-service exported by a module on certain path of a certain virtual host, to make it available for access from outside the application.

Attributes:

13.1.2.9 inject-restservice

This is used to wire a REST-service dependency of a module.

If a module's Spring config contains kauri:import-restservice elements, then you use inject-restservice to connect the restservice.

REST-service dependencies can be connected to REST-services that are exported by other modules, or to arbitrary URIs.

Attributes:

Example:

Suppose we have two modules called module A and module B.

Module A exports (= provides) a REST-service in its Spring config:

<kauri:export-restservice name="foo" ref="beanId1"/>

Module B imports (= depends on) two REST-services in its Spring config:

<kauri:import-restservice name="bar1" ref="beanId1"/>
<kauri:import-restservice name="bar2" ref="beanId2"/>

Now, let us connect the "bar1" dependency of module B to the "foo" service provided by module A. The "bar2" dependency will be connected to an arbitrary URL.

<runtime>
  <modules>
    <artifact id="moduleA" groupId="mygroup" artifactId="artifactA" version="1.0"/>

    <artifact id="moduleB" groupId="mygroup" artifactId="artifactB" version="1.0">
      <inject-restservice name="bar1" ref="moduleA:foo"/>
      <inject-restservice name="bar2" ref="url(http://myservice.org/something/)"/>
    </artifact>
  </modules>
</runtime>

Note that the order of the modules is important: in the ref attribute you can only refer to modules that come before the current one.

13.1.2.9.1 About REST-service types

It is possible to declare a type attribute on the kauri:import-restservice and kauri:export-restservice elements. This is optional, but if it is declared on both the import and export of two wired services, then these types need to be equal or an error will be given. The REST-service type is just a free-form string.

13.1.2.10 inject-javaservice

This is used to wire a Java-service dependency of a module.

Note that wiring Java services is optional. Since Java services are typed, the Runtime can auto-wire dependencies on a certain type of Java service as long as there is only one provided service for that type.

Attributes:

When performing the wiring for a particular dependency, the Runtime will first see if there is an inject for this particular dependency, identified by name. If that is not the case, it will look if there is an inject for the type of service. If that is not the case, the Runtime will auto-wire the dependency by looking in the global Java service registry for a service of that type. If there would be more than one available, or none, an error will be thrown.

13.2 connectors.xml reference

13.2.1 Index

<connectors>
  <serverConnector protocols="" address="" port="">
    <parameter name="">value</parameter>
  </serverConnector>
  <clientConnector protocols="">
    <parameter name="">value</parameter>
  </clientConnector>
</connectors>

13.2.2 Element description

13.2.2.1 connectors

This element is used to define the Restlet server and client connectors. From the Restlet docs:

A connector in the REST architecture style is a software element that manages network communication for a component, typically by implementing a network protocol (e.g. HTTP).

Example configuration:

  <connectors>
    <serverConnector protocols="HTTP" port="8888"/>

    <clientConnector protocols="HTTP"/>
    <clientConnector protocols="FILE"/>
  </connectors>

When deploying your application as a Servlet webapp, the server connectors are ignored.

13.2.2.2 serverConnector

Defines a Restlet server connector. From the Restlet docs:

A server connector listens for connections (from clients of any kind), transmits the request to the component that performs the request processing, creates the response and sends it to the client.

Attributes:

Using nested <parameter> elements you can specify implementation-specific configuration options.

The server connector implementation that will be used depends on what Restlet finds on the classpath. Kauri includes Jetty by default, so that is what will be used. More information on the available protocols and parameters for this connector can be found in the Restlet documentation.

For an example configuration, see connectors.

13.2.2.3 clientConnector

Defines a Restlet client connector. From the Restlet docs:

A client connector initiates communication with a server (of any kind) by creating a request.

Attributes:

In Kauri you can always make use of the service protocol and the module protocol. These are available without specifying client connectors.

For an example configuration, see connectors.

13.3 classloading.xml reference

<classLoading>
  <required on-conflict="highest"/><!-- (default)highest|error -->
  <allowed on-conflict="default"/><!-- (default)dontshare|highest|error -->
</classLoading>

required/@on-conflict: What to do when a share-required classloader entry occurs with different versions in different modules.

allowed/@on-conflict: What to do when a share-allowed classloader entry occurs with different versions in different modules.

These properties allow to solve a common source of classloading annoyance: you have a dependency on artifact X, which the runtime decides to put in the shared classloader. But X has a dependency on Y, and some other project also has a dependency on Y, but another version of it. Hence, the runtime decides to put Y not in the shared classloader. Consequence: X does not have access to the classes of Y. The solution before was to add, in the pom(s), an exclusion for one of the versions of Y. This works, but takes effort and is hard to maintain.

To decide what is the highest (most recent) version, we need to know how to compare version numbers. The comparison logic assumes version follow the following format:

major.minor.revision-suffix

in which the minor, revision, and -suffix parts are optional. A missing minor or revision number is the same as it having the value 0.

Concerning the suffix: if the two version numbers are equal, and the one has a suffix and the other not, then the one without suffix is considered to be the most recent. This is because the suffix is usually used to indicate some 'in preparation' release: -alpha, -beta, -r22342, -20101023, ...

If both versions have a suffix, than currently the only supported comparison is if they have the form '-r{number}', which is the format we usually use for Subversion revision-numbered snapshots.

13.4 Spring config reference

13.4.1 Introduction

13.4.1.1 Purpose

The Kauri Runtime provides some extension elements to use in the Spring configuration. The purpose of these elements is to:

13.4.1.2 Namespace

The extension elements are in the following namespace:

http://kauriproject.org/runtime/1.0#springext

The typical declarations to include in your Spring config are:

              xmlns:kauri = "http://kauriproject.org/runtime/1.0#springext"
                xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation = "http://kauriproject.org/runtime/1.0#springext
                             http://www.kauriproject.org/schemas/runtime/springext.xsd">

In case you wonder: the springext.xsd file is not available at the URL specified in the xsi:schemaLocation attribute, and will hence not be downloaded from the network. The URL is only used as an identifier, the schema file is included within the Runtime jars.

13.4.2 Element description

13.4.2.1 kauri:module

Makes available certain module context as beans within the Spring bean container.

Syntax:

<kauri:module restletContext="restletContext" classLoader="classLoader" handle="module" conf="confRegistry"/>

All the attributes are optional. The values of the attributes are the bean names under which to make the beans available, and can be freely chosen.

The following attributes are available:

13.4.2.2 kauri:import-service

Imports a Java service (= declares a dependency on a Java service).

Syntax:

<kauri:import-service service="..." name="..." id="..."/>

Attributes:

13.4.2.3 kauri:export-service

Exports (= provides) a Java service.

Syntax:

<kauri:export-service service="..." name="..." ref="..."/>

Attributes:

13.4.2.4 kauri:import-restservice

Imports a REST-service (= declares a dependency on a REST-service).

Syntax:

<kauri:import-restservice name="..." type="..."/>

Attributes:

The type of the bean that will be made available is org.restlet.Restlet.

13.4.2.5 kauri:export-restservice

Exports (= provides) a REST-service.

Syntax:

<kauri:export-restservice ref="..." name="..." type="..."/>

Attributes:

14 Configuration

14.1 Introduction

An application often has a number of configurable items: connection settings for a database or SMTP server, the path to the company logo, connection limits, port numbers, date formatting patterns, passwords for external services (e.g. Google maps API key), and so on.

Configurability is useful both for company-internal usage (e.g. different configurations for different deployments) and standard applications installed by many users.

As applications become bigger and are composed of lots of modules, each of the modules might have its configuration requirements.

Rather than letting developers invent a configuration technique on the spot (property files, system properties, ...), Kauri offers a default solution, bringing both homogeneity and a larger feature set. Some of its features include:

14.2 Configuration: first steps

TODO

14.3 Defining configuration

Here we describe the structure of the configuration data.

We explain this by how the configuration is defined on the filesystem. Internally, Kauri does not really care the configuration data is stored on the filesystem, other implementations are possible.

14.3.1 The configuration directory

14.3.1.1 Basics, important terminology

All configuration is grouped in a so-called configuration directory. This configuration directory can contain:

So an example configuration directory might look like:

conf
|-- kauri
|   |-- wiring.xml
|   `-- connectors.xml
|-- moduleA
|   |-- foo.xml
|   |-- bar.xml
|   `-- foo
|       `-- xyz.xml

While on the filesystem we talk of directories and configuration files, the logical configuration model of Kauri uses the terms paths and configurations:

When starting Kauri, it uses as configuration directory by default the directory named conf in the current directory. You can specify another location through the -c option.

14.3.1.2 Configuration inheritance

You might want to create multiple configuration directories for multiple purposes: one for development, one for test, and one for deployment. A lot of the configuration of these three cases might be the same. To avoid duplication, you can create a base configuration directory containing everything that is the same, and put in the specific configuration directories only what needs to be different.

When starting Kauri, you supply the configuration directories in the order that they should be read by Kauri:

[Linux] (using colon as path separator]
kauri -c confs/common_conf:confs/dev_conf

[Windows] (using semicolon as path separator]
kauri -c confs/common_conf;confs/dev/conf

Besides this, a module might also have default built-in configuration. Rather than having these defaults in code, it might be useful to have them as configuration files in the module jar. This provides a nice example of what and how to configure.

The figure below illustrates the configuration inheritance.

14.3.2 The configuration files

The configuration files themselves are XML files. They should have the extension .xml, other files are ignored.

The XML files have some limitations:

Other than this, the XML files are form-free, there is no schema to follow. You can invent elements and attributes as needed.

14.3.3 Inheritance (merging) between configuration files

When using fallback between multiple configuration directories, or fallback to the module built-in configuration, a configuration file in a higher-prioriy location will hide the corresponding configuration file from the fallback location(s).

Rather than replacing the file completely, it is possible to have inheritance within the configuration files.

Let 's use the terminology base config file and child config file.

By default inheritance is disabled. Inheritance is enabled for an element by means of the following attributes:

Let's illustrate this with an example.

Base config file:

<?xml version="1.0"?>
<conf>
  <properties>
     <property key="key1">value1</property>
     <property key="key2">value2</property>
  </properties>
  <param1>value1</param1>
</conf>

Child config file:

<?xml version="1.0"?>
<conf xmlns:conf="http://kauriproject.org/configuration"
      conf:inherit="deep">
  <properties conf:inheritKey="@key">
     <property key="key2">value2 - altered</property>
     <property key="key3">value3</property>
  </properties>
</conf>

The child config file contains a conf:inherit attribute on its root element, enabling the inheritance.

The root element does not have a conf:inheritKey attribute, so the uniqueness is determined by element name: the <properties> element in the child config corresponds to the <properties> element in the base config. The <param1> child is missing in the child config, so it will be inherited from the base config.

Since it is a deep inheritance, the inheritance will also be applied to the child elements of the <conf> element: in this case only <properties>. The children of the properties element can not be uniquely identified by name, since they are all called <property>. Rather, their uniqueness is defined by the value of the key attribute, thus we specify the attribute conf:inheritKey="@key".

If you want to copy all child elements from the base config to the child config, thus without considering the uniqueness, you can specify an empty expression: conf:inheritKey="".

Inheritance also works for attributes, which are of course always uniquely identified by name (XML does not allow two attributes with the same name).

So the resulting config after inheritance looks like:

<?xml version="1.0"?>
<conf>
  <properties>
     <property key="key1">value1</property>
     <property key="key2">value2 - altered</property>
     <property key="key3">value3</property>
  </properties>
  <param1>value1</param1>
</conf

14.4 Accessing config from Java and Spring

14.4.1 Basics

The following Java interfaces play a role:

All these interfaces are part of the kauri-runtime-rapi artifact.

You can get access to the ConfRegistry or directly to a specific Conf object by injecting it into beans via the Spring container.

14.4.2 Getting access to the ConfRegistry

You can make the ConfRegistry available as a bean in your Spring container via the conf attribute of the kauri:module tag:

<kauri:module restletContext="restletContext" classLoader="moduleClassLoader" conf="confRegistry"/>

You can then inject the confRegistry into your beans.

The ConfRegistry is useful if you want to load configuration data at runtime, and register ConfListeners.

14.4.3 Getting access to a specific configuration

If you want to supply a bean with a specific configuration (a Conf object), and you don't need the ConfRegistry, you can directly retrieve it using the kauri:conf tag:

  <bean id="myBean" class="com.mycompany.MyClass">
    <constructor-arg><kauri:conf path="foo"/></constructor-arg>
  </bean>

Suppose your module has the id "example" (in the wiring.xml), then this would inject the Conf object corresponding to the following configuration file:

conf/example/foo.xml

14.4.4 Getting access to a specific configuration value

If you want to inject simple values into beans, rather than complete configurations in the form of Conf objects, you have two options.

14.4.4.1 ConfPlaceholderConfigurer

Spring has the concept of PropertyPlaceholderConfigurer's which are used to resolve ${...} expressions in the Spring config.

Kauri provides an implementation which works on top of its configuration system. Example:

  <kauri:module restletContext="restletContext" classLoader="moduleClassLoader" conf="confRegistry"/>

  <bean class="org.kauriproject.runtime.rapi.ConfPlaceholderConfigurer">
    <constructor-arg ref="confRegistry"/>
  </bean>

  <bean id="myBean" class="java.lang.String">
    <constructor-arg value="${foo:email}"/>
  </bean>

The content of the ${...} expression is as follows:

${configuration-path:jxpath-expression}

The jxpath-expression is just like an XPath expression but works on top of the Conf objects. You can use an expression like "@myAttribute" to get the value of an attribute, or "foo/bar" to get the value of the element bar nested within the element foo. The root element of the configuration has no name and is not addressable. In the configuration XML file, the name of the root element thus has little importance.

For the above example, supposing your module has the id "example", you would need the file conf/example/foo.xml containing:

<?xml version="1.0"?>
<conf>
  <email>billg@microsoft.com</email>
</conf>

14.4.4.2 kauri:conf

The kauri:conf tag discussed above can also be used to retrieve individual values by specifying a JXPath expression in the select attribute on kauri:conf:

<kauri:conf path="configuration-path" select="jxpath-expression"/>

You might as well use the ConfPlaceholderConfigurer, but this syntax opens the future possibility of returning lists of things too.

14.5 Accessing config from templates

You can directly retrieve configuration values within templates, without having to pass them on via a resource class.

This is done by means of a conf() function, which takes two or three arguments:

conf(path, jxpath-expression)

conf(path, jxpath-expression, default)

In case you specify no default and the config is not available, the string CONF_UNDEFINED is returned.

The conf function can be used within EL expressions, so in a template it will look like this:

<html>
  <body>Hi ${conf('helloworld', 'greeting-target')}</body>
</html>

Suppose the module is called 'example', then you would need the following configuration file:

conf/example/helloworld.xml

Containing:

<?xml version="1.0"?>
<conf>
  <greeting-target>world</greeting-target>
</conf>

14.6 Accessing config from router.groovy

You can get access to the configuration from within the router.groovy by means of an available variable named 'confRegistry' which refers to the ConfRegistry associated to the module.

Inside the router.groovy one can read configuration settings from that by calling the java API of this ConfRegistry interface and the Conf instances it returns.

TODO: synopsis of the most essential methods of those, or refer to javadoc (when published)

String message = confRegistry.getConfiguration("helloworld", false).getChild("greeting-target", false).getValue();

This value can then be used in the groovy builder in any way you'ld want to.  It could be defining parts of paths to match, the name of a kauri-representation to return, a specific version number of a service to call, etc etc

14.7 Configuration of the configuration system

The configuration system can be configured by means of itself.

Currently the only parameter is how often the filesystem should be checked for changes to configuration files.

The configuration should be made available at the path kauri/configuration, thus typically in the following file:

conf/kauri/configuration.xml

Example configuration:

<?xml version="1.0"?>
<conf>
  <!-- Interval is in milliseconds -->
  <reloading enabled="true|false" interval="5000"/>
</conf>

15 Temporary Resources

Introduction

Getting into REST frameworks a lot of experienced web developers are faced with the daunting hurdle of "having no session management" available.
Indeed.  The 'statelessness constraint' (ie. Making sure every request can be handled in total isolation of any previous ones) is forced upon these developers by depriving them from their beloved "Session" object.

Future Plans

15.1 Usage

The temporary resources module exposes a Java service and a REST service which allow you to store temporary files, but the Java API and implementation classes can equally be used to create other services (e.g. a service for implementing HTTP-Session-like features or for writing binary blobs to your own backends).

This file upload services can be used to create HTML forms with multipart data, as demonstrated by the Kauri Forms upload-control.

Configuration

The tmp dir where the files will be written can be specified via the wiring.xml

<?xml version="1.0" encoding="UTF-8"?>
<wiring>

  <modules>
    <artifact id="routing" groupId="org.kauriproject"  artifactId="kauri-routing-impl"/>

    <artifact id="template" groupId="org.kauriproject" artifactId="kauri-template-service-impl"/>

    <artifact id="tmprsrc" groupId="org.kauriproject"  artifactId="kauri-tmprsrc">
      <mount name="upload" path=""/>
      <!--  important convention: no trailing slashes since we want to leave them for the child routers -->

      <inject-restservice name="store" ref="url(file:///tmp/kauri-temp-upload)" />
    </artifact>
  </modules>

</wiring>

By default, each temporary resource is kept for 5 minutes. Each time you access the resource (read or write) the resource, the lease timeout is reset to 5 minutes. Yan change the duration by creating a file called conf/tmprsrc/upload.xml, where tmprsrc is the id used in the wiring.xml file.

<?xml version="1.0" ?>
<conf>
  <lease-refresh-time>300000</lease-refresh-time><!-- time in milliseconds -->
</conf>

15.2 API and Services

There is a Java API and a Rest API for working with temporary resources

Java API

See the apidocs for org.kauriproject.upload.FileUploadStore

To see how the Java service can be used, have a look at the sources for FileUploadRestService.

The 'persistData' method is of notable interest: by calling this method the uploaded file will no longer be subject to automatic cleanup.

Rest API

These are the various calls that you can make on the rest service.

GET /

A very basic upload form for posting files to /

POST /

Creates a temporary resource and returns a JSON structure.

[{
  "charset":"UTF-8"
  "mimetype":"application/pdf"
  "size":176607
  "id":"231f5c60254d0f1f44697a6d4c53596543451d13"
  "filename":"example.pdf"
  "fieldname":"file"
}]

GET /{key}/info.json

Returns the same info returned by a POST to /

GET /{key}/lease.json

Returns a JSON structure containing the lease information:

{
  "refreshTime":300000,
  "expiryTime":1288360200000
}

GET /{key}/data/{filename}
GET /{key}/data
GET /{key}

Returns the actual data.

PUT /{key}/data/{filename}
PUT /{key}/data
PUT /{key}

Updates the data

DELETE /{key}/data/{filename}
DELETE /{key}/data
DELETE /{key}

Deletes the data (the lease is removed)

16 Error handling

16.1 Different ways of handling error situations

When a resource class encounters an error situation (bad client request, error from backend, ...), there are different ways to deal with it:

  1. Produce the complete error response: set the appropriate status code and a response body.

  2. Throw an exception. Catching the exception and creating the appropriate response becomes the responsibility of a downstream filter.

  3. Set only the response status, but not the response body. The Restlet API allows the status to include a custom description and a Throwable object. Creating the response body becomes the responsibility of a downstream filter.

16.1.1 Case 1: resource class produces complete error response

This is interesting if you want to provide very specific error responses. This will especially be useful in Webservice (REST-API) style resources, and less for user-facing web applications.

If a resource class formats all errors it might produce itself, it is completely self-contained without relying on any downstream filters to do further work for them.

16.1.2 Case 2: throw an exception

When a resource class talks to back-end classes, these classes will often produce all kinds of exceptions. For example a CMS might produce something like a DocumentNotFoundException or a DocumentAccessDeniedException. Rather than handling such exceptions everywhere in all resource classes, it might be easier to let the resource classes simply ignore this exception, and let it be handled by a downstream filter. This filter can translate the exception to appropriate response status (e.g. "404 Not Found" for the DocumentNotFoundException) and generate a response body.

The exception (or more generally: the Throwable) will have to be catched and translated to an HTTP response body and status code. There are multiple ways to do this:

16.1.3 Case 3: set response status, but no body

Restlet has a Status object which can contain more information than just the status code (the number). It can also contain a custom description and a Throwable object.

Response.setStatus(new Status(Status status, String description, Throwable throwable));

or the shortcut:

Response.setStatus(Status status, String description, Throwable throwable);

Since you can specify a custom description and the cause-throwable, this is in many ways similar to throwing an exception, though you don't have the advantage of the flow control provided by exceptions, you will have to make sure yourself you stop further processing and return from the resource class.

The formatting of the response body can be done by:

16.2 Throwing an exception versus setting response status

When an error condition occurs in a resource class, and you don't want to be concerned with formatting the response body, you have the choice of either throwing an exception or setting the response status.

For such error conditions, you will often have an opinion on the response status code: e.g. it might be a “400 Bad Request”.

Throwing an exception might however provide for easier flow control than setting the response status. But you will often not want to define a custom exception class and corresponding configuration of the downstream filter, but still you want to be able to set the status code, provide a description and possibly a cause-throwable.

For this case, you can use:

17 Caching of static resources

17.1 Introduction

The term static resources is used to describe the static/invariable elements of web pages, such as images.

In modern web sites and applications, web pages often consist of a large amount of resources: images, javascript and css files, ... When these resources can be identified as "static", the addition of "caching directives" can give hints to browsers, proxies and other actors on the Web to allow for optimal caching of the resources. This can dramatically improve loading time of such heavy pages.

17.2 Best practices

17.2.1 Convention

Gather your module's static resources in a folder static under src/main/kauri .

There you will probably want to create also the following subfolders:

static
   |> image   :: static images
   |> script  :: static javascript files
   |> style   :: static css files

17.2.2 Use "static" names for static resources

Identifying static resources is one thing, but then you still have to be careful about naming them. Imagine a web application FooBar, with a nice logo with a green background. Naturally the logo image is a static resource, but what about the name ? A logical choice would be e.g. foobar_logo.png , but you can see this means trouble when you restyle your app and want to use a logo with blue background and the same "logical" name. Such problems can easily be avoided by choosing a more "unique" name.

This is even more important in case of javascript files. When using a javascript utility (e.g. some fancy jquery plugin), you have to ensure that the name unambiguously identifies the utility and the version of it. If not, caching can cause situations in which the same page is working fine for user A but giving headaches to user B who is working with some old cached version. It is useful to also indicate if the javascript file is regular, "packed" or "minified".

Some examples:

17.2.3 Semi-static resources: module resources which can (only) vary per build

Some resources in your module might have a static nature, but can vary per build. Consider, for example, a stylesheet layout.css containing the global layout of your application. You don't want too aggresive caching of this resource, because you might want to change the layout in a future release of your application. Although it's good practice to add the versions to the names of your utitlity resources (see above), doing so for your own mutable code causes too much overhead.

Luckily, Kauri provides a feature for this use case. If enabled, a unique build key is generated during every build, which can also be used in resource paths. Caching will then also consider the build key (as it is a part of the resource URI), which eliminates the danger of lingering old resources when deploying a newly built release.

By convention, we place those resources in the folder static-{build}.key (literally) under src/main/kauri .

17.3 Add Caching to kauri module

17.3.1 Add caching headers via router.groovy

import java.util.List;
import org.restlet.data.CacheDirective;

builder.router {
  
  def localInSourceMode = inSourceMode;
  
  filter(
      uri: "/static",
      after : { request, response ->
        if (!localInSourceMode && response.getStatus().isSuccess()) {
          List<CacheDirective> cacheDirectives = response.getCacheDirectives();
          cacheDirectives.clear();
          cacheDirectives.add(CacheDirective.maxAge(157680000)); //cache for 5 years (expressed in seconds)
          cacheDirectives.add(CacheDirective.publicInfo());
        }
      }) {   
        // various static resources cached by the filter:
        router() {         
          // static resources
          directory(
              uri: "",
              root: "module:/static"
              )
        }
      }
  
  ...
  
}

17.3.2 Enable usage of semi-static resources

In the configuration below, we will only activate the caching of semi-static resources when kauri is not started in source mode (-s module-source-locations.xml), because during development it's most likely more convenient to be able to modify and test these resources without restarting let alone rebuilding the module.

17.3.2.1 i) router.groovy

Extend the above configuration:

// various static resources cached by the filter:
router() {
    
  String buildKey = localInSourceMode ? "nocaching" : confRegistry.getConfiguration("build", false).getChild("build", false).getChild("key",false).getValue();
  
  // semi-static resources
  directory(
      uri: "-" + buildKey + ".key/", 
      root: "module:/static-{build}.key"
      )
  
  // static resources
  directory(
      uri: "",
      root: "module:/static"
      )
}

17.3.2.2 ii) placeholder conf/build.xml

Create a folder conf under src/main/kauri, in which you create a placeholder file build.xml :

<!--
   | This placeholder file is replaced (generated) during the build process.
   |
   | This placeholder file is required when running this module from source.
   -->
<conf/>

17.3.2.3 iii) pom.xml

Add/configure the maven antrun plugin in your pom to generate the build key during the build process.

<!--  kauri module building :: producing a conf/build.xml -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>

      <id>KauriStaticResources</id>
      <phase>generate-resources</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <tasks>
          <mkdir dir="${project.build.directory}/classes/KAURI-INF/conf"/>
          <tstamp>
            <format property="build.time" timezone="GMT + 0" pattern="yyyyMMdd'T'HHmmss'Z'"/>
          </tstamp>
          <condition property="key" value="${project.version}-${build.time}" else="${project.version}">
            <contains string="${project.version}" substring="-SNAPSHOT" />
          </condition>
          <echo file="${basedir}/target/classes/KAURI-INF/conf/build.xml" encoding="utf8"><![CDATA[<?xml version="1.0"?>
<!-- generated by the module build process -->
<conf>
  <build>
    <id>${project.id}</id>
    <by>${user.name}</by>
    <time>${build.time}</time>
    <version>${project.version}</version>
    <key>${key}</key>
    <java>
      <vendor>${java.vendor}</vendor>
      <version>${java.version}</version>
    </java>    
  </build>
</conf>]]></echo>
        </tasks>
      </configuration>
    </execution>
  </executions>
</plugin>

17.3.2.4 iv) Usage in templates

It is convenient to keep the build key of your module in a template variable. You can do this by adding the following in e.g. your base template:

<t:init>
  <t:variable name="fooKey" value="${inSourceMode() ? 'nocaching' : conf('build','build/key')}" />
</t:init>

You can then access the semi-static resources as in the following example:

<script type="text/javascript" src="${publicUri('service:/fooRouter')}/static-${fooKey}.key/foo.util/bar.js"/>

Naturally this example requires that you place the resource bar.js in the folder src/main/kauri/static-{build}.key/foo.util .

18 Packaging Kauri applications

While developing a Kauri application, you will typically launch Kauri from the command line. Kauri will by default use the conf directory in the current directory, and retrieve all needed artifacts from your local Maven repository. Because of this, no special packaging is needed to run an application during development, reducing the build-run cycle.

However, at some point, you will have to package your application to distribute it to the users or to put it on some server for deployment.

A packaged Kauri application consists minimally of:

Besides that, it can also include logging configuration, application configuration, Java service wrapper configuration, documentation, and any other resources needed by your application.

There are basically two approaches:

18.1 Packaged Kauri application

18.1.1 What it is

A packaged Kauri application consists of a directory containing everything to run your application, except for Kauri itself.

It has no new concepts or features of its own, it is just a standard method for packaging a Kauri application.

[todo: still needs work: The directory can also contain documentation, installation scripts, and any other resources needed by your application]

A packaged Kauri application can be created by means of the Maven plugin kauri-package-plugin.

18.1.2 Usage

18.1.2.1 Add kauri-package-plugin configuration

If you have generated your application using the archetype, then this will already be present. Otherwise, add the following plugin to your (root) pom.xml:

<project>
  [...]
  <build>
    [..]
    <plugins>


      <plugin>
        <groupId>org.kauriproject</groupId>
        <artifactId>kauri-package-plugin</artifactId>
        <version>${version.kauri}</version>
        <inherited>false</inherited>
        <configuration>
          <confDirectory>${basedir}/conf</confDirectory>
        </configuration>
      </plugin>


    </plugins>
  </build>
</project>

Adjust the path to the configuration directory (containing the kauri/wiring.xml file) if necessary.

It doesn't really matter to which pom.xml you add the kauri-package-plugin, since the plugin does not look at the project it is embedded in. It does its work based on the specified wiring.xml file.

18.1.2.2 Creating the package

Execute the following command (in the directory containing the pom.xml):

mvn kauripackage:package

This will create the package in

target/kauri-package

18.1.3 Configuration properties

Name

Description

confDirectory

Location of the conf directory, containing the kauri/wiring.xml file.

packageDirectory

Path where the package should be created, default ${project.build.directory}/kauri-package

includeServiceWrapper

true/false, to indicate whether the service wrapper scripts should be included

includeRunInstructions

true/false, to indicate whether the HOW_TO_RUN.txt file should be included

logConfig

Path to log configuration, to be included instead of the default log configuration

18.1.4 Executing the plugin as part of build lifecycle

If you want to execute the plugin as part of the build lifecycle, use the "attached-package" goal.

warning: when adding this in the root pom, be aware that this will run first, as part of the root pom, not after all the modules have been built. Define a separate project with approriate dependencies to force correct execution order. I think this is the only solution, though have not looked too deep into it yet. (what does assembly:attached do?). Anyway, I'd recommend calling it manually for now.

      <plugin>
        <groupId>org.kauriproject</groupId>
        <artifactId>kauri-package-plugin</artifactId>
        <version>${version.kauri}</version>
        <inherited>false</inherited>        
        <configuration>
          <confDirectory>${basedir}/conf</confDirectory>
        </configuration>
        <executions>
          <execution>
            <phase>install</phase>
            <goals>
              <goal>attached-package</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

18.2 Packaging as a servlet webapp

18.2.1 What it is

Using the Maven plugin kauri-package-plugin, you can produce a stand-alone war for running a Kauri application.

18.2.2 Usage

18.2.2.1 Add kauri-package-plugin configuration

If you have generated your application using the archetype, then this will already be present. Otherwise, add the following plugin to your (root) pom.xml:

<project>
  [...]
  <build>
    [..]
    <plugins>


      <plugin>
        <groupId>org.kauriproject</groupId>
        <artifactId>kauri-package-plugin</artifactId>
        <version>${version.kauri}</version>
        <inherited>false</inherited>
        <configuration>
          <confDirectory>${basedir}/conf</confDirectory>
        </configuration>
      </plugin>


    </plugins>
  </build>
</project>

Adjust the path to the configuration directory (containing the kauri/wiring.xml file) if necessary.

It doesn't really matter to which pom.xml you add the kauri-package-plugin, since the plugin does not look at the project it is embedded in. It does its work based on the specified wiring.xml file.

18.2.2.2 Creating the webapp

Execute the following command (in the directory containing the pom.xml):

mvn kauripackage:webapp

This will create the webapp in

target/webapp

You should be able to deploy this in most Servlet containers like Tomcat, Jetty, and others.

You could create a war of this for easy distribution, but for running the webapp, only "extracted wars" are supported.

18.2.3 Plugin configuration properties

Property

Description

confDirectory

Location of the conf directory, containing the kauri/wiring.xml file.

kauriVersion

Version of Kauri to include in the webapp, by default the same version as this plugin.

webappDirectory

Where the webapp directory should be created, default ${project.build.directory}/webapp

webXmlLocation

Allows to specify a custom web.xml to be included instead of the default one.

18.2.4 Executing the plugin as part of build lifecycle

If you want to execute the plugin as part of the build lifecycle, use the "attached-webapp" goal.

warning: when adding this in the root pom, be aware that this will run first, as part of the root pom, not after all the modules have been built. Define a separate project with approriate dependencies to force correct execution order. I think this is the only solution, though have not looked to deep into it yet. (what does assembly:attached do?). Anyway, I'd recommend calling it manually for now.

      <plugin>
        <groupId>org.kauriproject</groupId>
        <artifactId>kauri-package-plugin</artifactId>
        <version>${version.kauri}</version>
        <inherited>false</inherited>        
        <configuration>
          <confDirectory>${basedir}/conf</confDirectory>
        </configuration>
        <executions>
          <execution>
            <phase>install</phase>
            <goals>
              <goal>attached-webapp</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

18.2.5 Limitations

18.2.6 Background

While this tool is created in the form of a Maven plugin, it does not look at the Maven project it is used in, but does its work based on the specified wiring.xml file.

Everything necessary to launch Kauri and the Kauri-based application is embedded within the webapp. So if you provide someone with this webapp, they have enough to run your application. A Maven-style repository with all needed artifacts is embedded within the webapp.

Technically, the solution consists of two parts:

Since the HTTP server is provided by the servlet container, any server connectors defined in the connectors.xml will be disabled.

18.2.7 Layout of the webapp

WEB-INF
  + lib              contains the kauri-runtime-servlet jar and all its dependencies
  |                  (= mainly comes down to the Kauri Runtime and all its dependencies)
  |
  + repository       Maven-style repository, contains the jars of the modules listed in
  |                  the wiring.xml, and their dependencies
  |
  + confs
     + 1             Configuration directory.
  + kauri-auth.xml   (optional)
  + web.xml

19 Service wrapper

19.1 Introduction

In order to easily start and stop Kauri on deployment systems (often as part of the server boot process), Kauri includes the Tanuki Java Service Wrapper. This provides solutions for both Unix and Windows.

The service wrapper configuration we provide is intended for use with binary Kauri distributions and packaged Kauri applications.

19.2 Usage

19.2.1 Package your application

Packaging your application is described in detail here. In summary, assuming the kauri-package-plugin is configured in your pom.xml, it is a matter of executing:

mvn kauripackage:package

This will create the packaged application in the directory target/kauri-package.

The packaged application contains configuration files and scripts for the service wrapper. The actual wrapper binaries are part of the binary Kauri release.

19.2.2 Modify service-wrapper.conf

In the service directory of the packaged application, you will find a service-wrapper.conf file. Edit this file and adjust the two variables shown below:

# Environment variables
set.default.KAURI_HOME=/home/me/kauri/
set.default.KAURI_APPLICATION_HOME=/home/me/my-packaged-kauri-application

On Windows, use forward slashes in the paths, for example c:/kauri

Use absolute paths in both cases.

The KAURI_HOME variable should point to your binary Kauri installation, for example c:/kauri-{version}

The KAURI_APPLICATION_HOME variable should point to your packaged application, thus the parent directory of the service directory.

19.2.3 Try it

First set the KAURI_HOME environment variable:

Linux
export KAURI_HOME=/home/me/kauri

Windows
set KAURI_HOME=c:\kauri

Then launch kauri using:

Linux
kauri-service console

Windows
kauri-service

The console argument for Linux will cause the wrapper to run in the current shell, displaying any output on your shell. This is convenient in case there would be start up problems. On Windows, it is automatically in console mode.

19.2.4 Troubleshooting

When the wrapper is not run in console mode, you can find its output in the file:

{packaged application directory}/logs/kauri-wrapper.log

19.2.5 Installing the service on Windows

On Windows, you can install and uninstall Kauri as a service using the scripts install-kauri-service and uninstall-kauri-service, which you also find in the service directory.

19.2.6 Customizing the wrapper configuration

You can modify the wrapper configuration through the service-wrapper.conf file. This can be useful to change things like memory settings.

Most of the config is imported from a common configuration file that is part of the binary Kauri distribution. It is strongly recommended not to modify that common file, but instead make changes in the service-wrapper.conf file.

20 TODO - WRITE UP AND ORGANIZE

20.1 Kauri Project/Application Structure

20.1.1 The overall structure

A typical Kauri-projects will follow a recognizable structure.  Part of this structure is inherited from the Maven approach, adding onto that a number of web-dev specific parts.   The reasoning behind it boils around logical observations:

In other words: Even while most of this is optional and configurable, you don't want to needlessly stress out your colleagues by introducing wickedly deviant layouts.

Here is how it looks like.

-- my-application

 |-- pom.xml  // the root pom

 |-- conf
      |-- kauri
           |-- connectors.xml
           |-- wiring.xml
      |-- // further per-module-instance configuration           

 |-- module-source-locations.properties 

 |-- main-module
       |-- pom.xml     // the module pom
       |-- src
            |-- main
                 |-- java
                      |-- // Java packages and classes
                 |-- kauri
                      |-- mockdata 
                           |-- // mockup data structured in JSON files
                      |-- pages 
                           |-- // pages
                      |-- spring 
                           |-- // spring configuration
                      |-- static
                           |-- // static resources
                      |-- templates 
                           |-- layout
                           |-- macro
                           |-- snippet
                 |-- resources
                      |-- // stuff that goes into the jars

 |-- (optional) other-modules

The various pom.xml (project descriptor) files and their usage should be clear and comfortable to those using the Maven build-system in so called multi-project (or multi-module) setup.

For convenience this structure (pre-filled with some sample files) can be easily generated using the provided maven archetype.

The specific parts for kauri projects are described below, grouped as follows:

Before getting into that though: some typical questions:

20.1.1.1 What is a project, what are modules?

As the above listing suggests a kauri-project is mainly a group of modules being developed, tested, released (and distributed) together. 
These get started out of the need to create and eventually deploy a new web-service or web-site (ie. hosted on one associated domain-name).  In those cases these projects will at least have (at least) one module that will service as the main entry point and dispatcher: typically called the 'main-module'.

The modules however are re-usable components that are designed to be reusable across many projects. In other words: not all modules used in the application under development need to be an actual part of that very project. (They typically can be created inside some other project)

Because of this, eventually projects surface that still group a number of modules, but are not targeted at any specific web-site or -service (and thus don't have a 'main-module').  The grouping of the modules is then practically motivated by some common release cycle, feature-set, or shared ownership.

20.1.1.2 When do I need a new project, and new modules?

As in most modular or component architectures the 'size' (or 'scope') of what makes up a single module is an exercise left to the application developer.  What goes together, what should be split needs your careful consideration, but can't really be outsourced to any body else (let alone a framework).

Development teams typically will take into consideration fundamental questions as completeness and atomicity of feature-sets (the thing, the whole thing and nothing but the thing) but are equally often guided by more practically comparing maintenance and development costs versus perceived opportunity gains in reuse.  These might shift over time.

The two classic reality-check observations to make in this respect are:

The observation is that by seeking to add much wanted 'generic' properties to a single module, people tend to make up possible future use-cases for it that in reality will never occur.  Making it apt for reuse typically adds layers of configuration complexity that bloats the thing and thus makes it a very unappealing candidate for future reuse.  Aptness to reuse is a property of the overall architecture and design, more then it is of the one specific module.  When generalization is able to declare clean-cut interfaces (Separation of Concerns) then a countable higher degree of reuse is achieved: by replacing one module you get to reuse all the others (N+1 >> 1)

20.1.2 Various parts of the structure

20.1.2.1 The Project Declaration (root pom.xml)

Maven organizes all build and dependency-management aspects of your project at build time in the pom.xml. 
In the typical multi-module approach Kauri proposes this is called the 'root-pom'.  It will hold:

20.1.2.2 The Various modules and their contents

Each module being produced in a project requires its own subdirectory (holding its proper pom.xml)  This matches the maven approach to let each pom.xml be responsible to produce one artifact.  In the case of kauri-modules these artifacts are classic java jar files with an optional KAURI-INF map in them.

The typical maven approach is to let

{module-dir}/src/main/java

Hold the java classes, organized in packages that will be compiled to {module-dir}/target/classes and included in the root of the jar.

{module-dir}/src/main/resources

Hold additional 'resources' to be mixed in with the classes mentioned above.

{module-dir}src/main/test

Hold the junit test classes for build-time tests. (Not to be included in the jar)

To that Kauri adds:

{module-dir}/src/main/kauri

A place-holder for all kauri-specific stuff that gets folded into the jar under the mentioned KAURI-INF folder.

In that folder the following the following elements/positions have a specific function:

Next to these, you'll typically find also

20.1.2.3 Test and Deploy settings (conf, module-source-location.properties,...)

Lastly the project-folder will hold a number of runtime oriented files that allow for easily running and testing the combined modules in their project setting.

20.1.3 Using the archetype

TODO: write up

Things to explain here:

  1. cli script windows/lunux to generate project
  2. alternative when building from source
  3. explanation of the project structure (possibly in other doc)
mvn archetype:generate -DarchetypeGroupId=org.kauriproject -DarchetypeArtifactId=kauri-archetype-prototyping -DarchetypeVersion={version}-dev-SNAPSHOT

20.2 CLI reference

still in progress, just a dump from the scripts
(note by mpo) we shouldn't forget to list other scripts in [kauri-home]/bin  next to kauri.sh (runtime) there is also kauri-deploy-repo.sh (install dependencies in m2-repo) and kauri-project-template.sh (run the archetypes)

Kauri run/debug actions

run             Run the Kauri Runtime (default)
debug           Run the Kauri Runtime, listed to debugger on port 5005
debug-suspend   Run the Kauri Runtime, suspend for debugger on port 5005

Customize startup

You can use the following environment variables to customize the startup

KAURI_CLI_CLASSPATH
additional entries to be added to the classpath
KAURI_JAVA_ARGS
additional options to be passed to the java executable
KAURI_DEBUG_ARGS
 can be used to define alternative Java debug arguments
KAURI_DEBUG_SUSPEND_ARGS
can be used to define alternative Java debug arguments for suspended mode

21 Kauri hackers

21.1 Kauri source code

21.1.1 Getting the source

To get the source you have a few different options

21.1.2 Building the source

Install the basics:

It is a known problem that Kauri does not build on Java 1.6.0_03, due to problems with this Java version which are fixed in later versions.

Then execute:

mvn install

To speed up the build, you can skip the testcases by using the fast profile:

mvn -P fast install

21.1.3 Running Kauri build from source

After building the source, you have two options for running Kauri:

  1. Build a binary distribution and run it the same as any downloaded binary Kauri distribution.
  2. More likely, run Kauri directly. Kauri will load its jars from your local Maven repository, allowing fast build-test cycles when developing on Kauri itself.

Here is an example of how to run Kauri directly after building, using the template sample application:

cd samples
cd kauri-template-sample

[Windows]
..\..\kauri

[Unix]
../../kauri.sh

In this case, not only Kauri will be loaded from the local Maven repository, but the application modules (in this case the template sample module) and its dependencies will also be loaded from the local Maven repository.

21.1.4 Using the archetypes

For your convenience, here are the commands to generate projects using the archetypes (adjust version numbers as appropriate):

Basic archetype:

mvn archetype:generate -DarchetypeGroupId=org.kauriproject
-DarchetypeArtifactId=kauri-archetype-basic -DarchetypeVersion=0.4-dev-SNAPSHOT 

Prototyping archetype:

mvn archetype:generate -DarchetypeGroupId=org.kauriproject
-DarchetypeArtifactId=kauri-archetype-prototyping
-DarchetypeVersion=0.4-dev-SNAPSHOT

And add this option to specify location of the archetype repository:

-DarchetypeRepository=<your-repository>

21.1.5 Test hints

When running tests based on AbstractRuntimeTest, all warning-and-up log messages are logged to the console. If you want to see more logging output when running a testcase, you can easily enable this by passing some system properties, for example:

mvn install -Dconsole-logging=debug -Dconsole-log-category=org.kauriproject.i18n

The property console-logging sets the log level.

The property console-log-category sets the log category for which to enable this level of logging. It is optional to specify this property, if not specified, the log level will apply to the root log category.

21.2 Coding style

Without getting religious about coding style guidelines, it is pleasant and productive if all code follows more or less the same style. Basically, just do the same as the current sources, and follow the standard Java conventions (ClassNamesLikeThis, static finals in uppercase, etc). Opening braces are on the same line. Use some whitespace, e.g. write x = 5 + 3, not x=5+3.

One special point that requires attention: use spaces for indentation, do not use tabs. For Java sources, we use 4 spaces, for XML 2 spaces.

For your convenience we provide a formatter-profile with the kauri conventions for java sources which you can import in your IDE (if supported).

For Javascript, please follow the Dojo style guide .

For CSS, use these coding conventions

Please use the following license header:

/*
 * Copyright 2008 Outerthought bvba and Schaubroeck nv
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

21.2.1 js guide

21.2.1.1 Intro

Getting started with Javascript we recommend O'Reilly's book with the Rhino on the cover

For people coming from Java, this blogpost might get some common misconceptions out of the way fast. Same is true for this (sit back and relax) "Youtube video of the Google Techtalk "Javascript the good parts"

In Javascript land there are a number of techniques that enable to achieve the same thing. This page lists the ones we opt for in the coding of the needed Kauri libraries.

21.2.1.2 jQuery.com

We have chosen to use the jQuery library as a base for the Javascript development. The parts we'll be using most have been combined in our jQuery crash-course which is mainly a list of direct pointers in to the well-done jQuery documentation.

21.2.1.3 Coding techniques

21.2.1.3.1 Cloning a js object

jQuery provides a built-in member copy strategy in its 'extend' function. It can be used to make shallow object clones easily by extending a new created object:

    var clone = jquery.extend({}, original);
21.2.1.3.2 OOP like inheritance
21.2.1.3.2.1 Prototype definitions

A more design-time (and better performing) way to let all object instances of a certain 'type' behave in the same way and share the same properties is achieved by creating actual 'classes' and subclasses.  The 'classes' are created through Javascript prototype definitions:

  function  Base() {
    ...
  }

  Base.prototype.methodX = function(...) {
    ...
  }

The usage of prototype is standard Javascript practice.

21.2.1.3.2.2 Subclassing

Creating a subclass that inherits from the above is then done like this:

  Sub.prototype = new Base();
  Sub.prototype.constructor = Sub;
  Sub.prototype['<super>'] = Base.prototype;
  function Sub() {
    ...
  }
  
  Sub.prototype.methodX() {
    ...
  }

The first two lines are standard Javascript way of working the '<super>' property we introduce so we can call upon super implementations from the subclasses.

This last feature is offered through two additional methods:

The '<super>' property and these last two methods are automatically added to any subclass object created through our own $.inherit() function that takes two constructor-functions as argument, the subclass-function, resp. the superclass-constructor.

With this in place we get constructs like this:

  $.inherit(Sub, Base);

  function Sub() {
    this['<super.init>'](...);
  }

  Sub.prototype.methodX() {
    ...
    this.['<super.call>']("methodX", [...]);
    ...
  }
21.2.1.3.3 Namespacing

Javascript libraries have to watch out claiming names when being loaded.  Since any declared function (like for class-constructors) can conflict on the global scope we recommend:

The pattern looks like this:

  (function($){
    $.my = $.my || {};

    function Base() {
       ...
    }

    $.my.Base = Base;
  })(jQuery);

In this way there could be a $.my.Base which is kept completely distinct from say $.yourown.Base.

Kauri introduces in this way the variable: $.org.kauriproject.forms

21.2.1.3.4 Type checking

Javascript provides two techniques for type-of checking:

  1. typeof variableName == 'lowercase-string-name-of-object-type'
    Recommended use for built in Javascript object structures: Array, Number, String, Date, Object
  2. variableName.constructor == namespace.constructorFunctionName
    Recommended for own defined classnames.

21.2.1.4 Documenting js

We use jsdoctoolkit.

The generation is triggered in the maven site building by

  1. configuration in the pom
    <reporting>
        <plugins>
          <plugin>
            <groupId>org.codehaus.mojo.javascript</groupId>
            <artifactId>javascript-report-maven-plugin</artifactId>
            <version>1.0-alpha-1-SNAPSHOT</version>
            <configuration>
              <sourceDirectory>${basedir}/src/main/resources/KAURI-INF/js/</sourceDirectory>
            </configuration>
            <reportSets>
              <reportSet>
                <reports>
                  <!-- include the desired reports -->
                  <!-- <report>jslint</report>-->
                  <report>jsdoc</report>
                </reports>
              </reportSet>
            </reportSets>
          </plugin>
        </plugins>
      </reporting>
  2. calling maven:
    mvn site

A reference of supported tags can be found here.

21.2.1.5 File name convention

We choose to keep the js file names all in lower case.

21.2.1.6 Testing

Debug code

The javascript-maven-plugin can be configured to filter out all lines starting with specified character string.

<configuration>
	<!-- .. -->
        <strip>/* _DEV_ */</strip>
	<!-- .. -->
</configuration>

With the current configuration, all lines starting with /* _DEV_ */ will be deleted at build time. This is handy for inserting debug code when using the unassembled code files.

jQuery Test Suite

Explained in this document.

Crosscheck

Chrosscheck is able to run js-tests without starting a browser, it's pure java.

The next example shows how to load the jQuery and Kauri-form libraries and run a simple test.

crosscheck.onSetup(function() {
    //loads the JavaScript library from the file
    //paths relative to modules/kauri-forms/kauri-forms-framework
    crosscheck.addPath('target/scripts/KAURI-INF/public');
    crosscheck.addPath('../kauri-forms-jquery/src/main/resources/KAURI-INF/js/');
    crosscheck.load('jquery-1.2.3.js');
    crosscheck.load('kauri-forms.js');
});


crosscheck.addSuite({
  test_jquery: function() {
    //any variables, objects or properties defined in 'jquery-1.2.3.js' will be accessible here.
    
    crosscheck.print("Test loaded libraries");
    assertNotNull($, "jQuery not loaded.");
    assertNotNull($.org, "namespace 'org' not registered.");
    assertNotNull($.org.kauriproject, "namespace 'org.kauriproject' not registered.");
    assertNotNull($.org.kauriproject.forms, "namespace 'org.kauriproject.forms' not registered.");
    
    crosscheck.print("Test ValidationResult");
    var errmsg = new $.org.kauriproject.forms.ValidationResult("{0} - {1}", "i18nkey", ["a", "b"]);
    assertTrue(errmsg.getMessage() == "a - b");
 
    crosscheck.print("Test jQuery extend");
    var newObj = {};
    assertNull(newObj.a);
    $.extend(newObj, {a: 5, b: 10});
    assertTrue(newObj.a == 5, 'object not extended.')
  }
});

To run:

java -jar crosscheck.jar [options] [test-file | test-directory]*

Options:

21.3 Subversion configuration

21.3.1 Subversion configuration

Edit the file ~/.subversion/config

Make sure the following line is not commented out:

enable-auto-props = yes

In the section [auto-props], add the following entries:

*.js = svn:eol-style=native
*.xml = svn:eol-style=native
*.html = svn:eol-style=native
*.java = svn:eol-style=native
*.txt = svn:eol-style=native
*.xconf = svn:eol-style=native
*.xweb = svn:eol-style=native
*.xmap = svn:eol-style=native
*.properties = svn:eol-style=native
*.css = svn:eol-style=native
*.xsl = svn:eol-style=native
*.xsd = svn:eol-style=native
*.dtd = svn:eol-style=native
*.ent = svn:eol-style=native
*.nsh = svn:eol-style=native
*.nsi = svn:eol-style=native
*.ini = svn:eol-style=native
*.conf = svn:eol-style=native
*.pom = svn:eol-style=native

Additionally one might want to automatically ignore some common IDE project files, by including the line:

global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store .classpath .project .settings *.iws *.ipr *.iml

In your IDE you just have to import this config file in the section "SVN properties configuration - automatic properties" if available.

21.4 Building restlet-snapshot

Given the dependency Kauri has on the Restlet project (http://www.restlet.org/) one will every now and then want to check if the Restlet trunk either contains fixes for or else introduces incompatibilities with certain solutions in the Kauri trunk.

To check this, one can follow the steps below to add a snapshot-version of the Reslet jars to the local maven repository:

The steps below have been bundled up into a shell script available in the kauri-svn at ./tools/restlet-dependency/make_restlet4kauri.sh

  1. checkout restlet
    svn checkout http://restlet.tigris.org/svn/restlet/trunk restlet-trunk --username {guest or tigris user name}

    When this finishes, you'll see a message like "Exported revision XXXX." Remember this revision number, you need it in the next step.

  2. customize build
yourname soft nofile 4096
yourname hard nofile 10240
  1. build Restlet and the maven artefacts
    cd restlet-trunk/build
    ant rebuild
  2. copy those to your local repository
    cp -R dist/maven2/restlet-{version}snapshot/* ~/.m2/repository/

After this you should change the version number of the Restlet dependencies in the root pom before making a clean Kauri build: Look in Kauri's root pom.xml for the value of the version.restlet property. Do a find-and-replace over the whole source tree of this version to the new version, svnYYYY to svnXXXX.

21.5 Running modules from source in your IDE

21.5.1 Running From Source-Directory

The Kauri Runtime allows to work on 'source-directory' layouts of your modules, which avoids building and installing them into full blown module jars in the maven repository just so you can test them.

Here is what you can do in your IDE:

  1. Hook up at least the Kauri Runtime project, and configure a java-application-runner to launch the main-class
    org.kauriproject.runtime.cli.KauriRuntimeCli
    with the arguments:
    -c ${project_loc}/conf
    -s ${project_loc}/module-source-locations.properties
    -r ${system_property:user.home}/.m2/repository
    -z  
    

    in the context (classpath) of this 'kauri-runtime' project.

    Note that eclipse will have the ${project_loc} property pointing to the location of the project holding the actual file/resource that is active in the IDE when starting the run.
    In other words: the actual location of the files will be relative to your module-project-directory

  2. So, obviously you should provide a module-source-locations.properties file in your module-project-directory. This file allows to list actual source-locations to use for distinct modules. The file follows the Java property syntax. Keys should be references to the module (group and artefactID, separated by a '!'), while the value holds the source-directory to run from:
    groupid!artifactid=/path/to-the-module/

    This source-directory your module is expected to stick to the maven2 directory layout. More specifically, it expects:

    + src/main/kauri
            classloader.xml
            spring/*.xml 
    + target/classes/

    Note that the source-location paths in the property file can contain

    1. Relative paths: they are considered relative with respect to the module-source-locations.properties

    2. All Java System properties like ${user.home}

21.5.2 JUnit "Module" Tests

TODO: the same approach could be used to run module-tests vis-a-vis a kauri-runtime launched with references to source-directories.
This calls for some test-convenience base-class.

21.6 Maven Dependency plugin

We included the Maven Dependency Plugin in Kauri, by adding the following in the parent pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <version>2.0</version>
</plugin>

This makes it possible to do some analysis of all the dependencies - including the transitive dependencies - of each (sub)project. You can invoke any of the dependency-goals on the root level, or in a single (sub)project: mvn <goal>

The most interesting goals for this purpose are:

goal

description

dependency:analyze

Very useful ! Analyzes the dependencies of this project and determines which are: used and declared; used and undeclared; unused and declared.

dependency:tree

Very useful ! Displays the dependency tree for this project.

dependency:list

Displays the list of dependencies for this project.

Some other plugins do similar analysis, but they don't always seem as accurate as this dependency plugin.

Maybe we could use this plugin to generate the classloader.xml files we need in our modules. Maybe dependency:copy-dependencies can be of some help, or otherwise the dependency:list with post-processing ? TODO: Take a look at how they do it @Schaubroeck.

21.7 Release Building

These are the steps to perform an official Kauri release.

All command-line example instructions are for Unix, though should be easily translatable to equivalent operations on other systems.

21.7.1 Requirements

To do the complete release process, you should have:

21.7.2 Checks

21.7.2.1 Check 'dist' dependencies

The included 'dist' project lists all modules that need to be included in the distribution.  

21.7.2.1.1 Samples inclusion

Special care should be taken to verify if all  the samples to be shipped in the distro are effectively listed in the ./dist/pom.xml
One should compare with the list of

find ./samples -name pom.xml
21.7.2.1.1.1 Verify a clean Maven build works

This is to verify a "real clean build" scenario would work, thus that the pom's don't reference something which is only available in your local repository.

Depending on how much you value your local Maven repository, you can either just throw away your local repository or temporarily use another location as the local repository:

EM2R=/tmp/EMPTY_MAVEN2_REPO; rm -rf ${EM2R}; mkdir -p ${EM2R}
mvn install -Dmaven.repo.local=${EM2R}
21.7.2.1.2 Archetype consistency

The archetype dependencies (versions!) need to be in sync with those actually shipped in the release.
Best to check a simple build of an archetype-generated project against a clean maven repo.

Specially check the restlet-dependency:

$ find -name pom.xml |grep -v -P -e "target|\.svn" |xargs grep --colour "version.restlet>svn"

21.7.3 Configure Maven settings for Kauri repository access

This is important so that the permissions of the deployed files are correct, otherwise you'll have to fix them manually afterward (or most likely, you won't notice it, and the next person trying to deploy might have problems).

In the following file (create it if it does not exist):

~/.m2/settings.xml

make sure the following server entries are included:

<settings>
  <servers>
    <server>
      <id>kauriproject-website</id>
      <filePermissions>664</filePermissions>
      <directoryPermissions>775</directoryPermissions>
    </server>

    <server>
      <id>org.kauriproject.maven-deploy</id>
      <directoryPermissions>775</directoryPermissions>
      <filePermissions>664</filePermissions>
    </server>

    <server>
      <id>org.kauriproject.maven-snapshot</id>
      <directoryPermissions>775</directoryPermissions>
      <filePermissions>664</filePermissions>
    </server>
  </servers>
</settings>

You might want to add directives for your credentials on these servers, through more elements nested in the <server> tag:

      <privateKey>/path/to/your/private-key</privateKey>
      <password>yourPasswordHere</password> <!-- avoid this by publishing your pubkey to the server -->

21.7.4 Test if you have sufficient karma and correct settings to actually deploy

To avoid entering your password many times during the deployment of the artifacts to the public repository, you should add your public key to the ~/.ssh/authorized_keys2 file on kauriproject.org. If you are unfamiliar with this, stop reading here and find out how to do this. It will take you less time than entering your password a gazillion times.

windows users should add the path to the private key (and when using keygenerator: export the private key instead of saving it, I have no idea why but saving does not work in this setting):

<privateKey>c:\pathtoprivatekey\mykey.ppk</privateKey>

You can verify it works by deploying to snapshot repository:

mvn deploy

21.7.5 Run Maven release:prepare

you should build and install /tools/kauri-genclassloader-plugin separately

in windows after preparing release: find -name pom.xml |xargs unix2dos

Maven release:prepare performs the steps documented here, most importantly:

This does not yet deploy anything.

It is strongly recommended (read: official releases: obliged) to do this on a fresh SVN checkout to avoid non-clean situations:

rm -rf kauri-all
svn co https://dev.outerthought.org/svn/outerthought_kauri/trunk/ kauri-all
cd kauri-all

Then first do a dry run of release:prepare:

mvn release:prepare -DautoVersionSubmodules=true -DpreparationGoals="clean install" -DdryRun=true

As long as the effective mvn release:prepare has not been performed, you can back out with mvn release:clean

Why we need the preparationGoals parameter: by default the release plugin only executes the 'verify' phase, not install, but Kauri requires the artifacts to be installed in the local repository for Kauri Runtime based test cases to run.

Maven will interactively ask for:

21.7.5.1 Optional: (recommended for official release) test the distro

Before actually releasing, assemble a binary release and test that the following work on a clean system:

Note: one way to do that is to clone your current directory and replace all the prepared pom's and then perform a distro build. (Don't use that changed setup for actual release building though.

$ cd ..; cp -r kauri-all kauri-distro-test; cd kauri-distro-test
$ find -name pom.xml.tag -execdir cp pom.xml.tag pom.xml  \;
$ mvn install; cd dist; mvn assembly:assembly

Then install the build distro somewhere and play around with it.  Things to check:

21.7.6 Actual release building

If this finished successfully, you can proceed for real:

mvn release:prepare -DautoVersionSubmodules=true -DpreparationGoals="clean install"

If the above would fail with a build failure like "The svn tag command failed. ... File ... already exists." then do an "svn up" and run the above command again. Apparently this is a problem starting from subversion 1.5.1.

To deploy the artifacts to the repository, execute:

mvn release:perform

to clean up:

cd ..
rm -rf kauri-all

21.7.7 Building the distribution

Binary distribution building should be performed once on a Unix-like system and once on a Windows-like system. This is to have files with proper line-endings for both systems. The knowledge about file endings is stored in Subversion, hence starting from a platform-specific SVN-download of the sources gives the best guarantees for appropriate line endings (nonetheless, either release should work on either platform, it is just a matter of polishing).

For the Windows part: don't use Cygwin, but plain Windows. The subversion embedded in cygwin is known to produce *nix line-endings for eol-style:native even when the Cygwin config is set to use DOS line endings. You can keep working from Cygwin, but you should install the windows copy of subversion yourself from http://subversion.tigris.org/project_packages.html

21.7.7.1 Source distribution

Download the tagged sources and zip them:

[Windows]
set version="0.1"
set vtag="RELEASE_0_1"
svn export https://dev.outerthought.org/svn/outerthought_kauri/tags/%vtag% kauri-src-%version%
zip -r kauri-src-%version%.zip kauri-src-%version%

[Linux]
version="0.1"; vtag="RELEASE_0_1"
svn export https://dev.outerthought.org/svn/outerthought_kauri/tags/$vtag kauri-src-${version}
tar zcvf kauri-src-${version}.tar.gz kauri-src-${version}

See instructions further on, after building the binary release, on how to upload these archives to Sourceforge.

21.7.7.2 Binary distribution

Starting from the exports you created for the source distributions, you can build the binary distributions:

[Windows/Linux]
mvn install
cd dist
mvn assembly:assembly

The resulting distribution files can be found in the dist/target folder

Do check the tar.gz contents for 'strange' permissions (Reported on 0.4-RC were rwsrwsrwt on the /*.txt files, but only when extracting with file-roller in gnome).  In general it is best to build zip on windows, and surely tar.gz on linux.

21.7.7.3 Uploading the distributions to sf.net

In total, there are four files to upload: source archive as .zip and as .tar.gz, and binary archive as .zip and .tar.gz.

To upload, login to sourceforge.net and go to 'The Kauriproject'. Select the last tab 'project admin' => 'file manager' where all folders and uploaded files are listed.

Create a new directory for the release by clicking the icon next to the kauriproject folder and upload then the files in this new directory by selecting  'upload' on the folder icon.

21.7.8 Post release work

21.7.8.1 Announce

Don't forget to update possible 'current release' references on the own website kauriproject.org 

21.7.8.2 Apidocs

21.7.8.3 These are generated with maven site plugin 

$ mvn site-deploy

should make you happy. Published site should be in http://kauriproject.org/maven-site

21.7.8.4 Docs

21.7.8.5 Update release on daily-builds

These are provided through Hudson running at ci.outerthought.org

Select the job KAURI_DAILY_RELEASE, choose configure, and change the version number to whatever the new upcoming version number is (matching the one in the pom)

21.8 Javascript Maven Plugin

Javascript Maven plugins

javascript-maven-tools

We choose the javascript-maven-tools plugin for its rich featureset and active development.

Storage

Js-files are packed in a jar file and stored in the repository.

Dependency

Dependencies between javascript artefacts can be forced. The javascript plugin must therefore be declared as an extension in the POM for these artefacts.

..
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>maven-javascript-plugin</artifactId>
  <extensions>true</extensions>
</plugin>
..

Other js artefacts can than force the dependency as for java artefacts, but with the type set to 'javascript':

..
<dependency>
  <groupId>..</groupId>
  <artifactId>..</artifactId>
  <version>..</version>
  <type>javascript</type>
</dependency>
..
Assembly

It's possible to combine different js-files in one big file during the build cycle. This prevents the designer to have to include a bunch of javascript files, and still keeps de code easy to maintain.
An assembler XML-file describes which files to combine, and in what order.

<?xml version="1.0"?>
<assembler>
  <scripts>
    <script>
      <fileName>combined.js</fileName>
      <includes>
        <include>file1.js</include>
        <include>file2.js</include>
      </includes>
    </script>
  </scripts>
</assembler>

The descriptor-tag in the configuration of the plugin points to this file.

<configuration>
  ..
  <descriptor>${basedir}/src/assembler/myAsm.xml</descriptor>
  ..
</configuration>
Strip debugging code

The pluging provides a goal that strips lines starting with a special token from the code. This is usefull for removing debug code. The token can be set in the plugin configuration with the strip-tag.

Compression

There are three compressors included: Dojo Shrinksafe, YUI compressor and JSMin. JSMin is de deafult one used, this can be changed in the plugin configuration by the compressor-tag. The possible values are: 'shrinksafe', 'yahooui' and 'jsmin'.

Configuration

Compression:

Tag

Default

Description

optimizationLevel

9

Optimization level, from 0 to 9

languageVersion

130

JS Language version (130 for JS 1.3)

compressor

jsmin

The compressor to used. Either "shrinksafe", "yahooui" or "jsmin" for default compressor, or a custom one provided as an artifact in repo org.codehaus.mojo.javascript:<xxx>-compressor.

skipStats

false

Don't display compression stats

compressedDirectory

${project.build.directory}/compressed

The output directory of the compressed javascript files.

buildDirectory

${project.build.directory}

The output directory of the compressed javascript archive.

finalName

${project.build.finalName}

The filename of the compressed js file.

classifier

compressed

Classifier for the compressed artefact

scriptClassifier

Optional extension for the compressed artifact. Example "compressed"

scriptsDirectory

${project.build.outputDirectory}

The intput directory for the source javascript files.

Strip debugging code:

Tag

Default

Description

strip

A special token to recognize lines to be removed from scripts (debugging code).

Assembler:

Tag

Default

Description

sourceDirectory

${basedir}/src/main/javascript

Location of the source files.

outputDirectory

${project.build.outputDirectory}

The output directory of the assembled js file.

descriptor

src/assembler/${project.artifactId}.xml

Descriptor for the strategy to assemble individual scripts sources into destination.

descriptorFormat

default

Descriptor file format ("default" or "jsbuilder").

Custom Kauri build

Since there's no official build available for this plugin, and because no other version than SNAPSHOT exists, a custom build was made with the build date included. No noticeable updates were made to the source since then.

21.9 Kauri Forms Source Code Guide

TODO

list of source files and their responsibility

javascript extension and inherit system

build system (aggregation)

22 Glossary of Terms

22.1 Terms in use

22.1.1 archetype

A template for generating new Kauri projects. It frees you from the work of having to create the basic directory structure, build files, etc. See also Creating a Kauri project.

22.1.2 authentication method

A way for verifying the identity of a user. According to Wikipedia, it is the act of establishing or confirming something (or someone) as authentic. Some typical authentication methods are basic, digest, form-based and client certificate authentication. Sometimes also referred to as an authentication scheme or authentication mechanism.

22.1.3 element (XML)

An element in XML is most common kind of markup in an XML document. An element can contain content, typically text or other elements. There are two syntactical forms:

22.1.4 JAX-RS

JAX-RS is the Java API for RESTful Web Services. It is mainly about how to implement resources using Java objects, and defines a set of Java annotations for this purpose. The specification (which is quite compact and readable) can be found at java.net.

22.1.5 module

A module is the unit of modularization within the Kauri Runtime. A live Kauri Runtime instance consists of a number of modules, wired together to use each other's services, some of which are also exposed externally (over HTTP). Physically, a module is a self-contained archive containing code, resources and configuration (classpath, bean container). A module is less than a Servlet war, as a typical application consists of the combination of multiple modules. A module is similar to a bundle in OSGi.

22.1.6 module protocol

The module protocol (or URI scheme) is used by a module to access resources contained in the module. When a module is packaged as a jar, then the URI "module:/test.txt" will resolve to the file KAURI-INF/test.txt contained in the module jar.

22.1.7 resource class

A resource class is a Java class which implements a corresponding Web resource. A Web resource is the intended conceptual target of a hypertext reference (Fielding). From a developer point of view, a resource class contains the code which is executed in response to a Web request. In Kauri, resource classes are either implemented using the standard JAX-RS API or using the Restlet-specific org.restlet.resource.Resource API.

22.1.8 RESTful Web Services book

See here.

22.1.9 Restlet

Depending on the context, the term Restlet can refer to:

22.1.10 REST-service or restservice

A module can provide (or export) REST-services to expose its functionality, and depend on (or import) REST-services to use external functionality. A REST-service is a service through which you communicate using the REST uniform interface. On a Java-technical level, a REST-service is an org.restlet.Restlet. Next to REST-services, a module can also use Java-services to expose or use functionality.

22.1.11 service protocol

The service protocol (or URI scheme) is used by a module to address its REST-services. These can be any of the imported or exported REST-services. The syntax is service:/restservice-name/path. The service protocol can be used in various locations: the routing, the templates, ... Technically, they can be resolved through org.restlet.Context.getClientDispatcher().

22.1.12 source mode

A shortcut to refer to a Kauri Runtime started with the option (-s) to load modules directly from your (Maven-style) source directory layout. In this mode, changes to non-Java classes are automatically picked up without need to restart Kauri, and even without need to run Maven, since resource files are directly read from the 'src' directory, rather than the 'target' directory. See docs.

22.1.13 URI template

A URI template is used for constructing or matching URIs. In general a URI template is a string containing variables between { and }, for example /users/{id}. The term URI template is re-used by different technologies, which always use the basic {variable} notation, but each have their own specific features:

22.1.14 wiring.xml

The wiring.xml is Kauri's most important configuration file: it describes what modules to load and how to wire them. The wiring.xml is necessary to start Kauri, without it, Kauri does not know what modules to load, and thus would have nothing to do. See also the wiring.xml reference.

23 Upgrading from 0.3

[TODO: kauri.xml to wiring.xml and connectors.xml, see http://groups.google.com/group/kauri-discuss/browse_thread/thread/b2060b94c45bfce5]

[TODO: change the version properties in your pom's for Kauri, Spring, ...]

[TODO: 0.3.0 to 0.3.1: {x:**} syntax from representationbuilder config changed]

[TODO: incompatible changes in Restlet: Move of representation classes from org.restlet.resource to org.restlet.representation: ajdust your imports]

Forms

Control event listeners should now be registered directly on the control instead of on getElement(). Mail.

Representation builder

For exception formatting, there is no kauri_throwable_chain available anymore in the view data. This is not needed anymore as the template language now supports recursive macro calling.

Templates

A variable (parameter) "request" containing the Restlet request object is now automatically made available. If you previously set this yourself, you don't need to do this anymore. If there is an existing parameter named "request", it will be overwritten.

DBResources

classpath:org/kauriproject/dbresources/jpa/jparesources-beans.xml

has been renamed to

classpath:org/kauriproject/dbresources/jpa/services.xml
1.The first extension is the public one, the second extension serves for associating with appropriate editors on your system.