Composing Applications
In this tutorial you have seen how to use XRL to map address spaces,
create simple template defined resource widgets, and compose resource widgets to
build new resources.
In this section we will examine resource widget composition in more detail
and show how NetKernel supports a clean and clear separation
of layers, widgets, resources, and services that enables
developers to quickly compose application solutions.
XRL Resource Widgets, continued...
Dynamic Template Pull
In the previous examples, we saw how template content
could be located dynamically at runtime.
In this example we will see how to specify the template at runtime.
In the following XRL resource widget template, the
content is static and the framing template, service-box-table
,
is located dynamically at runtime.
The content is a static XML documentation fragment that
describes three sets of three coloured boxes.
<div xmlns:xrl="http://1060.org/xrl" style="background-color: silver; padding:10px;">
<div>Part 6 Content</div>
<xrl:include href="xrl:service-box-table">
<data>
<set>
<box>red</box>
<box>green</box>
<box>blue</box>
</set>
<set>
<box>blue</box>
<box>red</box>
<box>green</box>
</set>
<set>
<box>green</box>
<box>blue</box>
<box>red</box>
</set>
</data>
</xrl:include>
</div>
At this level of abstraction details of the service-box-table
implementation are hidden in a lower level.
However, at this level we are concerned with delegation to the framing template,
so let's examine how an xrl:include
tag can provide a parameter
argument in a service call.
In the links document that maps the XRL name service-box-table
to an internal active URI,
note that there is a args
tag with the value
param
.
The result of this entry is that the DPML runtime executes a DPML script to dynamically generate
a HTML table with box entries...
<links>
<link>
<name>service-box-table</name>
<int>active:dpml+operand@ffcpl:/xrldemo/services/box-table.idoc</int>
<args>param</args>
</link>
</links>
When the xrl runtime resolves the xrl:include
tag,
it locates the internal URI specified by the link name.
It also passes the static XML inline document fragment
as the 'param' argument to the DPML program because the service link has
an <args>
tag.
This indicates to the XRL runtime that if an argument named 'param' is available
then it should be passed as an argument on the internal service request.
First try the example...
http://localhost:8080/workbench/xrldemo/part6/index
.
You will note that the static XML content defining various coloured boxes has been translated into
a visual representation.
If you examine services/box-table.idoc you will see that the implementation
calls a XSL stylesheet that translates the inline data.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xrl="http://1060.org/xrl" version="1.0">
<xsl:output method="xml" />
<xsl:template match="/data">
<table>
<xsl:apply-templates />
</table>
</xsl:template>
<xsl:template match="set">
<tr>
<xsl:apply-templates />
</tr>
</xsl:template>
<xsl:template match="box">
<td>
<xrl:include href="xrl:{.}-box" />
</td>
</xsl:template>
</xsl:stylesheet>
If you inspect the XSL code carefully, you will notice that
the resulting table contains another set
of dynamically generated xrl:includes
tags, each of which references a coloured box resource.
The resulting HTML table is as follows:
<table xmlns:xrl="http://1060.org/xrl">
<tr>
<td>
<xrl:include href="xrl:red-box" />
</td>
<td>
<xrl:include href="xrl:green-box" />
</td>
<td>
<xrl:include href="xrl:blue-box" />
</td>
</tr>
<tr>
<td>
<xrl:include href="xrl:blue-box" />
</td>
<td>
<xrl:include href="xrl:red-box" />
</td>
<td>
<xrl:include href="xrl:green-box" />
</td>
</tr>
<tr>
<td>
<xrl:include href="xrl:green-box" />
</td>
<td>
<xrl:include href="xrl:blue-box" />
</td>
<td>
<xrl:include href="xrl:red-box" />
</td>
</tr>
</table>
The dynamically generated XRL references in this HTML fragment are also
recursively resolved by the XRL runtime.
Dynamic Template and Dynamic Content
In this section we will extend the previous example to include
dynamic content.
The user will be presented a form that accepts a number specifying how many
coloured boxes to generate.
When executed, the program will generate an N by N grid of boxes and randomly select the
colour for each box.
http://localhost:8080/workbench/xrldemo/part7/index
.
We'll let you dissect the source in detail.
What you'll discover is a set of linearly independent services which are
marshalled and coordinated
by the XRL recursion.
The important point with this application is that the form data is
being passed down from the browser submission all the way through to
the implementing services.
Note that the input form itself is actually dynamically generated so
that is displays the current grid size.
This is the named link "part7-form" and is implemented by a DPML script with an
active:dpml request...
<links>
<link>
<name>index7</name>
<ext>/part7/index</ext>
<int>active:xrl-html+template@xrl:part7-template+content@xrl:part7-content</int>
<args>param,links</args>
</link>
<link>
<name>part7-template</name>
<int>ffcpl:/xrldemo/part7/template.xml</int>
</link>
<link>
<name>part7-content</name>
<int>ffcpl:/xrldemo/part7/content.xml</int>
</link>
<link>
<name>part7-form</name>
<int>active:dpml+operand@ffcpl:/xrldemo/part7/form.idoc</int>
<args>param</args>
</link>
</links>
So, how did this form-script get its parameter?
Parameter Relaying
When your web-browser submits the form, the form post data is
received by NetKernel's HTTP transport.
The HTTP transport initiates an internal request for
the resource, this request is mapped by the front-end fulcrum to the the http-bridge accessor.
This accessor extracts the posted form data and initiates an
active URI request for ffcpl:/workbench/xrldemo/part7/index and
passes the form-post data as the 'param' argument on this active URI request.
As we have seen previously, requests for ffcpl:/workbench/xrldemo
enter the workbench module and are directed to the mapper accessor,
however this mapping also captures and relays to the mapper all of the
active URI arguments on the external request, including the 'param' argument containing
the post data.
In general we don't think about these external stages - they are performed
transparently by the infrastructure above us.
The important thing, and the thing to focus on, is that we have initiated a
request on the mapper and the externally generated post data has arrived as
an argument named 'param'...
As in earlier examples, the mapper resolves the operand
argument to the part7-index link.
If we examine this link closely we see that it has a tag <args>
.
The args tag indicates to the mapper and the xrl runtimes the names of the
arguments which should be relayed on with the internal
active URI request which is specified in the int tag - in this case 'param'.
So the 'param' argument which the mapper received, is relayed on as an argument
to the active:xrl call.
During the xrl recursion the xrl runtime resolves an include request for "xrl:part7-form".
It locates the appropriate link in the links document, which, as we discussed above,
is a request to the DPML scripting runtime.
However this link also has an <args>
tag containing 'param'.
The xrl runtime is therefore instructed to relay on the 'param' argument which it
received on the active URI request to
the DPML engine.
Finally the DPML script executes and uses the param to dynamically generate
the form widget.
In a very similar way the main grid of coloured boxes is generated.
Examine the source code and look at how the 'param' argument is passed to another,
independent DPML script to generate the table.
Other Points of Interest
The source for the example has a few other points of interest...
The random-box service is implemented as a simple wrapper over a
secondary call to the mapper and links...
import java.util.*;
main()
{ r=new Random();
c=r.nextInt(3);
color=null;
switch(c)
{ case 0:
color="red";
break;
case 1:
color="green";
break;
case 2:
color="blue";
break;
}
//ReUse the mapper to source the box widgets
req=context.createSubRequest();
req.setURI("active:mapper");
req.addArgument("operator", "ffcpl:/xrldemo/links.xml");
req.addArgument("operand", "ffcpl:/workbench/xrldemo/widgets/"+color+"-box");
result=context.issueSubRequest(req);
context.createResponseFrom(result);
}
A DPML script to filter the default-parameter is used by two
services (part7-form and dynamic-box-table).
If no external parameter is provided, which is the case
when the page is first requested, then a default size of 3 will be used...
<idoc>
<seq>
<instr>
<type>copy</type>
<operand>this:param:param</operand>
<target>this:response</target>
</instr>
<exception>
<comment>If there is no parameter then default to 3x3</comment>
<instr>
<type>copy</type>
<operand>
<nvp>
<size>3</size>
</nvp>
</operand>
<target>this:response</target>
</instr>
</exception>
</seq>
</idoc>