STEP BY STEP: KAURI PROTOTYPING AND APPLICATION BUILDING

Introduction

The main purpose of this document is to guide you through a first Kauri experience. This is however not a reference guide or extended tutorial. Is also recommended to take a look at the Kauri samples which are distributed in the builds.

Setting up the environment

General Kauri/Maven setup

For building an application with Kauri, you'll at least need a JDK, Maven for building purposes and Kauri. For detailed information about the setup read the getting started document.

Making your project structure

Creating a new project

In this document you see how to create a new project with one module. A Kauri project contains one kauri.xml with the description of the Kauri application, but one project can contain more than one module.

What are modules?

A module is a unit inside the Kauri Runtime. Different modules 'live' together in this runtime environment and these are glued together so they can use each other's services.

Kauri provides some standard modules -like routing, templating, forms, ...- which you can use in your project. Your application is then build-up in a modular way, customized to your needs.

What needs a separate module

Now how do you decide when to create a separate module instead of keeping everything in one module? Generally you can ask the question if the module on itself should be re-usable.
If we would create a planning application in which we keep and organize contacts, tasks and projects; we can imagine that the logic to create, edit and organize persons and contacts can be reused in another application. So in in this example application we could create separate modules for contacts, tasks and projects.

None if this is required, so it's no problem to keep everything in one module in prototyping phase.

How to wire modules

Since modules can use each others public services, we need some wiring to expose and use these services. Typically, you will need to perform 2 steps to enable services from a module:

  1. you will have to include the needed module in the kauri.xml
  2. you will have to import the needed services in the Spring configuration of your project

You do this only once per project, so there is no need to do this on each module level.

Examples will follow  for the DBmock module and can be found in the documentation of the module you need.

Project structure

As you can see in the project structure below:

  • One project contains one kauri.xml
  • Each module had its own pom.xml and spring configuration
  • Each module has its own sources, dbmock entities (if in prototyping mode), static resources, templates and configuration (router, spring, representation)
.
|-- kauri.xml
|-- module-source-locations.properties
|-- contact-module
|   |-- pom.xml
|   `-- src
|       `-- main
|           |-- java
|           |   `-- com
|           |       `-- mycompany
|           |           `-- contact
|           |               `-- ContactResource.java
|           `-- kauri
|               |-- dbmock
|                   `-- contacts
|                       |-- 1.json
|                       |-- 2.json
|                       |-- 3.json
|                   `-- events
|                       |-- 1.json
|                       |-- 12.json
|                       |-- 13.json
|               |-- static
|               |   |-- img.jpg
|               |-- representations.groovy
|               |-- router.groovy
|               |-- spring
|               |   `-- contact-module-beans.xml
|               |-- pages
|               |   |-- contacts.html.xml
|               |   |-- index.html.xml
|               |   |-- tasks.html.xml
|               |   |-- contacts
|               |       |-- {id}.html.xml
|               |        `-- {id}-edit.html.xml
|               `-- templates
|                   `-- layout.xml
|-- task-module
|   |-- pom.xml
|   `-- src 
|       `-- ...
`-- pom.xml

Now let's look at the contact module in detail, and the pages directory in particular:  you can see some strange file names there which need some explanation.

First of all: the double extension is just because we want a different extension in the URI space (html) then on the filesystem (xml) - because we want to associate the pages with the correct application/editor. In the URI space this will map to contacts.html, index.html and so on.

Second: what's up with the {id} in the filename? To understand this just consider what we'd like to accomplish in the URI space:

  • /contacts.html  for overview of all contact persons in our application
  • /contact/1.html for a detailled overview of contact person with ID 1
  • /contact/1-edit.html for a page to edit the details of contact person with ID 1
  • /contact/new-edit.html for a page to create a new person

We can accomplish all of this by adding one entry in our router:

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

where the root entry specifies the directory where you want to put your templates, in our case 'pages'.

The pages component will build a router based on this file structure, the file paths are actually directly usable as URI templates. And because they are templates, we can make strange filenames like {id}.html.xml.

This means that in our example if we access the page /contacts/1-edit.html, a request parameter id with value 1 is added. So in this page we can access the parameters by refering the key: ${request.attributes.id}.

Details about this pages entry in the router, you can find in this section.

Start to prototype your application

This section is meant for those who want to build a prototype of their application, by which we mean a mocked-up application with sample data. A prototype can later be migrated to a real-data application. Prototypes can in a first stage only be the page templates with static data, but in a Kauri project structure. A next phase could be mocking up the application with data provided in JSON files. This process should make the flow from designing a prototype to building the real application more easy. In this context, the DB mocked prototype is in fact a first model of the application. 

Using DB mock

Purpose

The purpose of using a DB mock is to provide an easy way to make a prototype of an application. By this we mean an application that can be used as a demonstration model: it acts as a real application but it works only using test data inside simple text files. We can create and edit entities, for example we can create a new contact and we will see this contact on a contact overview page. But what is then the difference with the real application if this creates a 'working' application? This mockup uses plain text files, and not a database. So only basic actions and structures are possible, and you can not expect this to work as a real database system.

What do we call an entity in this context? Everything you want to act as a unit of data is an entity. A contact, a project, a task, a status and a company can all act as an entity. In this DB mock we will create a plain text file per entity. If we want to use 5 test-persons in our application, then we'll have to create 5 files in the directory /persons. More about this will follow.

Setup

To enable the dbresources in your kauri project:

  1. create a dependency on the module in the pom.xml:

<dependency>
   <groupId>org.kauriproject</groupId>
   <artifactId>kauri-dbresources-impl</artifactId>
   <version>${version.kauri}</version>
</dependency>  
  1. import the spring beans in the spring configuration of your module:

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

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

After these steps you can access the structure of JSON files on your file system.

JSON files: where to put in your project

You add your JSON entities to your project in directory /entities similar to the layout of our contact project below. For correct usage, you must add the directories in the 'entities' directory of the Kauri source dir.

.
|-- contact-module
|   `-- src
|       `-- main
|           `-- kauri
|               |-- dbmock
|                   `-- contacts
|                       `-- 1.json
|                       `-- 2.json
|                       `-- 3.json
|                   `-- tasks
|                       `-- 1.json
|                       `-- 12.json
|                       `-- 13.json
|                   `-- projects
|                       `-- 1.json
|                       `-- 2.json
|                       `-- 3.json

At runtime when you start your project, this entities directory will be copied by default to a temporary directory of your working environment (e.g. /tmp under Unix). You can change this temporary location by adding the location to as third argument in the spring configuration of your project if you  really want to:

  <bean id="data" class="org.kauriproject.dbmock.DbMockFinder">
    <constructor-arg ref="restletContext"/>
    <constructor-arg ref="module"/>
    <constructor-arg value="D:\\tmp\\dbmock\\contactmodule"/>
  </bean>

This third argument is optional, if you don't add it the temporary directory will be the default.

Structure of JSON files

If you're new to JSON, please check out some sites online:

Each .json file contains a valid JSON structure, as below is the one for a contact:

{
   "id": "1",
   "name": "John Doe",
   "type": "employee",
   "parameters":    [
            {
         "name": "address1",
         "value": "Kauri Street 1"
      },
            {
         "name": "city",
         "value": "Universe"
      },
            {
         "name": "postal_code",
         "value": "921932321"
      }
   ],
   "comment": "No comments so far for this employee",
   "color": "#ff00ff",
   "picture": "face1.jpg"
}

In this JSON you define the structure of your entity: what properties does a person have?

Now, imagine that we created have a set of tasks 1.json, 2.json, 3.json and in our application model each project consists of a set of subtasks. It would be redundant to repeat all these task JSON structures in each project file. To avoid this, it is possible to make references to other entities in files: the key $ref is used to obtain this.

{
    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: "/task/2"},
        {$ref: "/task/3"}
    ]
}

If you don't want to create the JSON structure yourself on disk, just start your prototype by making your 'new entity' page via Kauri forms and DB mock. This will create the JSON files on disk for you.

How to use it in your templates, how to display one entity or list of entities

Now you can use these DB mocks in your templates really easy via the Kauri template language. See this section for further details about templating.
If you want to use the entity in file /contact/1.json as a variable in your page you define this:

<t:variable name="contact" src="service:/data/contacts/1"/>

But remember, we used a template URI with that {id}, so we want to use this request parameter instead of just contact 1 so then just first get that request parameter and use that one:

    <t:variable name="id" value="${request.attributes.id}"/>
    <t:variable name="contact" src="service:/data/contacts/${id}"/>

And some finishing touch: since we want to use the same page for editing a person and creating a new person, just check if the id is different from 'new' (or whatever you want to use in your URI):

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

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

Once defined your can use this contact like a variable:

<tbody>
        <tr>
          <td>Name</td>
          <td>${contact.name}</td>
        </tr>
        <tr>
          <td>Type</td>
          <td>${contact.type}</td>
        </tr>
</tbody>

You also can iterate lists in JSON files:

<t:forEach var="parameter" in="${contact.parameters}">
 <tr>
   <td>${parameter.name}</td>
   <td>${parameter.value}</td>
 </tr>
</t:forEach>

Most likely you'll want to use this contact we read from the DB mock to fill the form field. If the members of your form map the properties of your entity, you can use this to wire your form:

var editForm = new jQuery.org.kauriproject.forms.Form("edit-form", fconf);
editForm.setWireValue(${contact});

And last of all: since a Kauri form has a property to define whether or not we want to create a new entity (if not, we are updating) we can use our {id} to define what  to do:

var editForm = new jQuery.org.kauriproject.forms.Form("edit-form", fconf);
editForm.setCreateMode(${id == 'new'});

<t:if test="${id != 'new'}">
 editForm.setWireValue(${contact});
</t:if>

Building and running your project

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

Now to run your project do as follows:

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

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

And then surf to:

http://localhost:8888/

Using snippets and templates

In a typical webapplication you'll have parts in pages that are used by all pages: a menu with links, a search bar, a login box, ... It would be really unhandy to keep repeating these items on each page. There are some Kauri template features that keep us from doing this.

Using blocks/master templates

Consider we want a template to use for all our pages. Some blocks will be the same for alle pages, let's say a header with the page title and a sidebar with navigation. The content will be different on each page.

We can use the block feature of Kauri templating language to accomplish this. Remark in that the project structure  we had a layout.xml file:

.
|-- contact-module
|   `-- src
|       `-- main
|           `-- kauri
|               |-- pages
|               |   |-- contacts.html.xml
|               |   |-- index.html.xml
|               |   |-- tasks.html.xml
|               |   |-- contacts
|               |       |-- {id}.html.xml
|               |        `-- {id}-edit.html.xml
|               `-- templates
|                   `-- layout.xml


This layout template will serve as a master template file with blocks we can inherit or override:

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

  <t:init/>

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

    Here some CSS, javascript, ..
    
    <t:block name="extraHeadContent"/>
  </head>

  <body>
    <div class="container">
      <div class="span-24">
        <h1>
          <t:block name="pageTitle"/>
        </h1>
      </div>

      <div class="span-4">
          Here some common things needed for all pages...
      </div>

      <div class="span-16">
        <t:block name="content">[ content ]</t:block>
      </div>
    </div>
  </body>
</html>

So you can use your pages just to define the content on each page, just specify which template you want to inherit from:

<?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="contact" src="service:/data/contacts/${id}"/>
    </t:if>

    <t:variable name="title">
      <t:choose>
        <t:when test="${id == 'new'}">
          New contact
        </t:when>
        <t:otherwise>
          Edit contact
        </t:otherwise>
      </t:choose>
    </t:variable>
  </t:init>


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

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

  <t:block name="extraHeadContent">
    <script type="text/javascript">
      jQuery(document).ready(function() {
          var fconf = {
                 ....
          };
          var editForm = new jQuery.org.kauriproject.forms.Form("edit-form", fconf);
          editForm.submitSuccess = function (data, success) {
              window.location = "${publicUri('service:/router/contacts.html')}";
          };
          editForm.setCreateMode(${id == 'new'});
          <t:if test="${id != 'new'}">
            editForm.setWireValue(${contact});
          </t:if>
      });
    </script>
  </t:block>

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

</html>

This prevents you from repeating the same code on each page. For more information about this Kauri template feature see the template reference.

Include

To include a snippet:

<t:include src="module:/router/templates/navigation.xml" />

Creating forms

Enabling Kauri forms in your project

To enable Kauri forms in your project, your have to do 2 things:

  1.  import the Kauri forms and jquery services in the spring configuration of your project:
  <kauri:import-restservice name="jquery"/>
  <kauri:import-restservice name="forms"/>
  1. configure the kauri.xml of your project so that the jquery and forms restservices are injected in your module
    <artifact id="jqueryModule" groupId="org.kauriproject" artifactId="kauri-jquery">
      <mount name="main" path="/_kauri/jquery" />
    </artifact>

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

    <artifact id="main" groupId="org.kauriproject" artifactId="kauri-tupper-main" version="1.0-SNAPSHOT">
      <inject-restservice name="jquery"        ref="jqueryModule:main" />
      <inject-restservice name="forms"         ref="formsModule:main" />
      <mount name="data" path="/data"/>
      <mount name="router" path="" />
    </artifact>

Setting the right includes

Kauri forms provides you functionality over standard html forms: you can easily add validations and there is a wide set of controls available.

Now let's create a form to edit contact details, so we edit the {id}-edit.html.xml page. We can create this form in Javascript code.

First step is to include the jquery and kauri-forms js-files:

        <t:include src="service:/jquery/templates/snippet/headerlinks-ui.xml"/>
        <script type="text/javascript" src="${publicUri('service:/forms/js/kauri-forms.js')}"></script> 

Once this is done, we can create the form itself.  What is needed to create a (Kauri) form?

  • members of the form
  • the URI to post the data to: we want to post to our DB mock backend
  • create a new resource or update existing one
     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?'
                },
                'mondaysok': {
                    base: 'boolean',
                    label: 'Do you like mondays?'
                },
                'description': {
                    base: 'string',
                    control: 'textarea-control',
                    label: 'Describe yourself in 10 words'
                }
            
            }
    }};
      jQuery(document).ready(function() {
          var basicForm = new jQuery.org.kauriproject.forms.Form("basic-form", fconf);
          basicForm.setCreateMode(true);
          basicForm.submitSuccess = function (data, success) {
              window.location = "grid.html";
          };
      });

Now we've created this editForm, how do we display it?

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

This way, you have defined the form in javascript and done nothing in html, and Kauri will create the form for you.

For more extensive examples, consult the kauri-forms-sample that shows multiple ways of defining a form.

Setting the wired value of a form/pre-filling the form

On your Kauri form you have the option to set the wired value so you can pre fill the form. Via the JSON mockup mechanism and Kauri template tags this can be done really easily.
Say we are editing a contact on URI /contacts/1-edit.html, this maps to the the template /pages/contacts/{id}-edit.html.xml. In this template, 1 is set as request attribute 'id'. This said, you can use the contact entity with the specified id:

  <t:variable name="contact" src="${publicUri('service:/data/contact/${request.attributes.id}')}/"/>

This makes the entity available as a variable. To wire this contact in your form just use the newly introduces variable as argument:

 editForm.setWireValue(${contact});