Database-backed Application pt2
Using NetKernel with a DB to create an Address book application
Release Notes
REST Service
Batch Processing
Intray PDF Distiller
Database-backed Application pt1
Database-backed Application pt2
Database-backed Application pt3
Active URIs
License
Change History
NetKernel History
Acknowledgements

Database-backed Application

Part 2 - Creating the application

Summary

In part 1 we built and configured a module to connect to a database and setup the database and JDBC connection. The application framework is complete we now need to write the application code which is now pretty straightforward.

Specification part2

We will create two pages for the application. A master page will provide an alphabetically browsable view of the address book. The master page will also provide an embedded search form. The search results will be rendered back into the master page. It will also have a link to a new entry form - this will be a new page containing an XForm.

Using the mapper and xrl accessor we will modularize the design into components and use a template document in which the page components are combined.

Building the App

Master Template

The master template will be an XHTML document containing some static content common to all pages. It includes an <xrl:include/> element which is an xrl statement to include any dynamic content supplied from the mapper. Here it is

<html xmlns:xrl="http://1060.org/xrl">
  <body>
    <h1>AddressBook</h1>
    <xrl:include href="xrl:content" />
    <div style="font-size: 10px">(C) 2004, 1060 Research Ltd</div>
  </body>
</html>

Copy this into a file called mastertemplate.xml in the resources/ directory. Add the following link to the links.xml document.

<link>
  <name>main</name>
  <ext>/</ext>
  <int>active:xrl-html+operator@ffcpl:/links.xml+template@ffcpl:/resources/mastertemplate.xml</int>
  <args>param,session</args>
</link>

The link maps a request for the external root path to an internal execution of the xrl accessor with the mastertemplate.xml as template - since this is just testing we are not providing a content argument, also we are using the xrl-html varient of the xrl accessor, this simply tells xrl to return the XML with a mimetype of text/html. We've also specified <args>param,session</args> this tells the mapper to pass through the param and session arguments to any included content (more on this later).

We can now test the contentless template http://localhost:8080/addressbook/.

Adding the alphabet browser bar

We require an alphabetized browser bar with each letter a link to a page which renders all entries beginning with that letter. We have said that the main page will provide the browser view. So it's REST interface will look like /addressbook/?letter=a.

Here is an idoc which uses an XQuery to generate the browser bar - save it in the resources/ directory as alphabetmenu.idoc.

<idoc>
  <seq>
    <instr>
      <type>xquery</type>
      <operator>
        <xquery> (: Create an alphabet link table :) &lt;table&gt; &lt;tr&gt; { for $letter in ("a","b","c","d","e","f","g","h","i","j","k","l","m", "n","o","p","q","r","s","t","u","v","w","x","y","z") return &lt;td&gt; &lt;a href="/addressbook/?letter={$letter}"&gt;{$letter}&lt;/a&gt; &lt;/td&gt; } &lt;/tr&gt; &lt;/table&gt; </xquery>
      </operator>
      <target>this:response</target>
    </instr>
    <instr>
      <type>copy</type>
      <operand>this:response#xpointer(/result:sequence/result:element/table)</operand>
      <target>this:response</target>
    </instr>
  </seq>
</idoc>

We want to include the browser bar in the mastertemplate. First we add a new named link to the links.xml file.

<link>
  <name>alphamenu</name>
  <int>active:dpml+operand@ffcpl:/resources/alphabetmenu.idoc</int>
  <args>links,param,session</args>
</link>

This link has no external part since it is purely an internal component. It's internal URI is an active:dpml which executes the alphabetmenu.idoc in the DPML runtime. Therefore any XRL Include of this link will execute the the DPML process to generate the browser bar.

Edit the mastertemplate to xrl:include the alphamenu link like this...

<html xmlns:xrl="http://1060.org/xrl">
  <body>
    <h1>AddressBook</h1>
    <xrl:include href="xrl:alphamenu" />
    <xrl:include href="xrl:content" />
    <div style="font-size: 10px">(C) 2004, 1060 Research Ltd</div>
  </body>
</html>

Try the master template again http://localhost:8080/addressbook/.

Entering data with an XForm

So far our application is static - we can't add any data and all we're doing is looking at the dynamically generated template but with no content.

Add the following two links to the links.xml document.

<links> ...
  <link>
    <name>xform_page</name>
    <ext>/newentry</ext>
    <int>active:xrl-html+operator@ffcpl:/links.xml+template@ffcpl:/resources/mastertemplate.xml+content@xrl:xform</int>
    <args>links,param,session</args>
  </link>
  <link>
    <name>xform</name>
    <int>active:dpml+operand@ffcpl:/resources/xform_execute.idoc</int>
    <args>links,param,session</args>
  </link>
</links>

The first link maps the external path /newentry to an execution of the XRL runtime. As for the "main" root link it uses our mastertemplate.xml but it also declares a content resource xrl:xform. This is a reference to the second link, an internal link, which executes an idoc xform_execute.idoc. The result is that a request for /newentry will start a cascade of XRL includes, first for the mastertemplate which will then include the content of the execution of the xform idoc.

XRL is a pull runtime it recusively pulls URI referenced resources defined by xrl:include declarations - it uses the the named links as the primary resource identifier, the resources can be static or as in the case above dynamically generated (here by DPML).

Below is the xform_execute.idoc and below that is xform.xml, the XForm it will process. Add these files to the resources/ directory.

<idoc>
  <seq>
    <instr>
      <type>copy</type>
      <operand>this:param</operand>
      <target>var:param</target>
    </instr>
    <exception>
      <instr>
        <type>copy</type>
        <operand>
          <nvp />
        </operand>
        <target>var:param</target>
      </instr>
    </exception>
    <instr>
      <type>XForm</type>
      <xform>xform.xml</xform>
      <xslt>xform_style.xsl</xslt>
      <param>var:param</param>
      <session>this:param:session</session>
      <target>this:response</target>
    </instr>
    <exception>
      <instr>
        <type>log</type>
        <operand>this:exception</operand>
      </instr>
      <instr>
        <type>copy</type>
        <operand>
          <div />
        </operand>
        <target>this:response</target>
      </instr>
    </exception>
  </seq>
</idoc>

This is the XForm for a new entry - although it has many fields it is not very complicated! It contains a single constraint - the Form is not valid unless a lastname is given.

<html xmlns:chiba="http://chiba.sourceforge.net/2003/08/xforms" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xrl="http://1060.org/xrl" xml:base="http://localhost:8080/chiba-0.9.2/">
  <head>
    <xforms:model>
      <xforms:submission id="submit" xforms:action="active:dpml+operand@ffcpl:/resources/xform_process.idoc" xforms:method="post" xforms:replace="all" />
      <xforms:instance>
        <nvp>
          <firstname />
          <lastname />
          <add1 />
          <add2 />
          <add3 />
          <add4 />
          <region />
          <country />
          <zip />
          <phone1 />
          <phone2 />
          <phone3 />
          <fax />
          <email1 />
          <email2 />
          <email3 />
          <web1 />
          <web2 />
          <notes />
        </nvp>
      </xforms:instance>
      <xforms:bind id="lastname" xforms:constraint="string-length(.) &gt; 0" xforms:nodeset="/nvp/lastname" xforms:required="true()" xforms:type="string" />
    </xforms:model>
  </head>
  <form>
    <xforms:group>
      <xforms:input xforms:ref="/nvp/firstname">
        <xforms:label>First Name</xforms:label>
        <xforms:hint>First name</xforms:hint>
      </xforms:input>
      <xforms:input xforms:bind="lastname">
        <xforms:label>Last Name</xforms:label>
        <xforms:hint>Last name</xforms:hint>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/add1">
        <xforms:label>Address1</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/add2">
        <xforms:label>Address2</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/add3">
        <xforms:label>Address3</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/add4">
        <xforms:label>Address4</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/region">
        <xforms:label>Region</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/country">
        <xforms:label>Country</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/zip">
        <xforms:label>Zip</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/phone1">
        <xforms:label>Phone1</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/phone2">
        <xforms:label>Phone2</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/phone3">
        <xforms:label>Phone3</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/fax">
        <xforms:label>Fax</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/email1">
        <xforms:label>email1</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/email2">
        <xforms:label>email2</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/email3">
        <xforms:label>email3</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/web1">
        <xforms:label>web1</xforms:label>
      </xforms:input>
      <xforms:input xforms:ref="/nvp/web2">
        <xforms:label>web2</xforms:label>
      </xforms:input>
      <xforms:textarea xforms:ref="/nvp/notes">
        <xforms:label>notes</xforms:label>
      </xforms:textarea>
      <xforms:trigger>
        <xforms:label>Submit</xforms:label>
        <xforms:hint>Submit new address</xforms:hint>
        <xforms:action>
          <xforms:send xforms:submission="submit" />
        </xforms:action>
      </xforms:trigger>
    </xforms:group>
  </form>
</html>

XForms

XForms are the W3C's next generation web form - since browsers do not yet support client-side XForms we are using a server-side XForm module based on the Chiba XForm engine. You can read in detail about using XForms on NetKernel here.

In brief the xform_exec.idoc is both the source of the form and the target of submission of the form. It renders the form using an XSLT stylesheet (see below, make sure you copy this to a file called xform_style.xsl in the resources/ directory). The form's state is held in the session (hence the reason we used the sessionmapper and pass the session through in the mapper arguments). The xform will not complete until all its constraints have been met. In this case a lastname must be provided. Once valid the xform's instance data is submitted to the target process defined in the submission definition - in this case the idoc xform_process.idoc, which receives the instance data as it's parameter.

<xsl:stylesheet xmlns:chiba="http://chiba.sourceforge.net/2003/08/xforms" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xrl="http://1060.org/xrl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="chiba xforms xlink xsl" version="1.0">
  <xsl:include href="ffcpl:/org/chiba/xslt/form-standard.xsl" />
  <xsl:output encoding="UTF-8" method="xml" />
  <xsl:template match="/">
    <div>
      <xsl:apply-templates select="/descendant::form" />
    </div>
  </xsl:template>
  <xsl:template match="form">
    <div>
      <xsl:call-template name="build-form">
        <xsl:with-param name="action-uri" select="'newentry'" />
      </xsl:call-template>
    </div>
  </xsl:template>
</xsl:stylesheet>

You should have put these three files (named as described above) in your resources/ directory. In the mastertemplate.xml add an href link <a href="newentry">Add new entry</a> - this links to the XForm page we've just created. Give it a try directly...http://localhost:8080/addressbook/newentry.

The XForm executes but we've not created the xform_process.idoc yet so it will break if you submit any data. In the final part we will show how the xform_process.idoc creates a new RDBMS entry from the form data and finish the browser.

[Part 3]

1060® NetKernelTM Documentation
(C) 2003-2004 1060 Research Limited

Send Feedback

© 2003,2004, 1060® Research Limited
1060 registered trademark, NetKernel trademark of 1060 Research Limited