The mapper
overlay
mediates and relays requests from a host space
to a wrapped space.
As with all
overlays
the wrapped space is accessible only through the mapper overlay.
The mapper overlay is opaque - the only
endpoints surfaced in the
host space are those explicitly defined in its configuration.
This overlay functions as a mapper because configured
logical endpoints are mapped to logical endpoints
in the wrapped space.
The processing steps are illustrated in this diagram:
- 1. A request is received by the mapper overlay
- 1a. The configuration determines how the request is mapped to a constructed sub-request destined for the wrapped space.
- 2. The constructed request is issued into the wrapped space.
- 3. The response arrives at the mapper overlay.
- 4. The mapper overlay relays response (3) as its response to the initial request (1).
A mapper overlay is declared with the mapper element which
must have a config child element and must have a
space child element.
The config element contains the logical endpoint mappings between
the host and the wrapped spaces.
The space element contains the definition of the wrapped space.
<mapper>
<config />
<space />
</mapper>
The wrapped space must be defined within the space element.
The configuration may be defined within the config element or it
may be a reference to a configuration resource
(which may be a static or dynamically generated resource).
<config>res:/resources/mapperconfig.xml</config>
The configuration resource must have a root element
named config and may include
import elements and endpoint declarations.
<config>
<endpoint />
<endpoint />
<endpoint />
...
<import>res:/resources/additionalConfiguration.xml</import>
</config>
Endpoint
In the config element one or more child endpoint elements each
declare a logical endpoint which is surfaced in the host space
and which defines the mapping to a
standard declarative request
issued into the wrapped space.
An endpoint element must have a
request
and usually must have a
grammar:
<endpoint>
<grammar />
<request />
</endpoint>
An endpoint may have any of the following child elements:
| Element | Description |
| id | Logical endpoint identifier for the surfaced endpoint |
| name | Human readable name displayed for this endpoint in system tools. |
| description | Human readable description displayed for this endpoint in system tools. |
| doc | Resource identifier for Wiki text documentation for this endpoint which is displayed in system tools. |
| icon | Resource identifier used as the icon for this endpoint in system tools. |
| header | Sets a response header on the returned response |
| verbs | A comma separated list of verbs that are resolved to this logical endpoint |
| private | Visibility constraint. |
| protected | Visibility constraint. |
|
verb
Note: The verb element of the
standard declarative request
used in the mapper is ignored.
Instead, the verb of the resolved request is used for the request issued into
the wrapped space.
tolerant missing arguments
When mapping grammars with optional arguments you can place arguments onto the
constructed request and these will gracefully fail if those arguments are not specified on the incoming request.
Mapping
The mapper overlay provides the context for one or more
logical endpoint to declarative request mappings.
This simple relationship is surprisingly powerful.
The following examples illustrate a sample of
the capabilities.
RESTful Path Parsing
A mapping between a RESTful path and an active service request
can be created in a logical endpoint declaration.
In the following example, an endpoint grammar parses and names
the final part of the RESTful identifier and then uses this as
the value for the argument named id in the
sub-request.
Note that the reference arg:customer-id in the request
refers to the parsed part named "customer-id" in the grammar.
<mapper>
<config>
<endpoint>
<grammar>res:/customer/
<group name="customer-id">
<regex type="alphanum" />
</group>
</grammar>
<request>
<identifier>active:customer</identifier>
<argument name="id">arg:customer-id</argument>
</request>
</endpoint>
</config>
<space>
...
</space>
</mapper>
RESTful Path to RESTful Path Translation
One aspect of the mapping is between identifiers.
The set of identifiers defined by the endpoint grammar
map to the set of identifiers that can be used in the
declarative request.
Aiding this mapping is the arg: scheme mapping.
As described
elsewhere,
a grammar parses a request identifier into constituent (named)
parts
and these named parts can then be referenced in the
standard declarative request
using the arg: scheme.
For example, this logical endpoint definition reorders the parts
of a RESTful identifier and uses the new form for the issued request:
<endpoint>
<grammar>res:/customer/id/
<group name="customer-id">
<regex type="alphanum" />
</group>/order/
<group name="order-id">
<regex type="alphanum" />
</group>
</grammar>
<request>
<identifier>res:/order/[[arg:order-id]]/customer/[[arg:customer-id]]</identifier>
</request>
</endpoint>
Interface / Implementation Separation
A benefit of NetKernel's dynamic environment is that
real service implementations can be substituted for
the stub implementations in a 24*7 operational system
with no downtime.
It is frequently beneficial to separate the interface of a resource
from its implementation.
During system development one team can develop software
that uses a resource or service while another team
develops the implementation if a temporary
stub can be
provided.
This can be achieved with the mapper overlay as illustrated
in the following example.
The first mapper overlay shows an interface defined for a
list of books, res:/booklist/, and the
initial static representation provided by an XML file:
<mapper>
<config>
<endpoint>
<grammar>
<group>res:/booklist/</group>
</grammar>
<request>
<identifier>res:/resources/statics/booklist.xml</identifier>
</request>
</endpoint>
</config>
<space>
<fileset>
<regex>res:/resources/statics/.*</regex>
</fileset>
</space>
</mapper>
The second mapper overlay shows the same interface mapped to a
dynamic implementation.
This second mapper definition can be used once the team developing
the implementation has tested and released their service.
<mapper>
<config>
<endpoint>
<grammar>
<group>res:/booklist/</group>
</grammar>
<request>
<identifier>active:groovy</identifier>
<argument name="operator">res:/org/netkernel/doc/bookList.gy</argument>
</request>
</endpoint>
</config>
<space>
<fileset>
<regex>res:/org/netkernel/doc/.*</regex>
</fileset>
<import>
<uri>urn:org:netkernel:lang:groovy</uri>
</import>
</space>
</mapper>
Filter
Because the mapper overlay is opaque, each endpoint in the wrapped
space that is to be surfaced in the host space must have an
endpoint declared in the configuration.
If all that is required is a pass-through and not a mapping of
the inner endpoint then configured endpoint need only refer
to logical endpoint identifier of the inner endpoint.
In this example a mapper is used to surface two of four
internal logical endpoints (essentially filtering the endpoint):
<mapper>
<config>
<endpoint>
<request>
<identifier>meta:one</identifier>
</request>
</endpoint>
<endpoint>
<request>
<identifier>meta:two</identifier>
</request>
</endpoint>
</config>
<space>
<accessor>
<id>meta:one</id>
...
</accessor>
<accessor>
<id>meta:two</id>
...
</accessor>
<accessor>
<id>meta:three</id>
...
</accessor>
<accessor>
<id>meta:four</id>
...
</accessor>
</space>
</mapper>
Other Mappings
These example show only a sample of the capabilities of the mapper overlay.
To illustrate even more richness, examine the following
endpoint:
<endpoint>
<grammar>res:/configuration/
<group name="resource">
<regex type="nmtoken" />
</group>
</grammar>
<request>
<identifier>active:configuration</identifier>
<argument name="resource">arg:resource</argument>
<argument name="host">active:hostname</argument>
</request>
</endpoint>
This mapping is used by a large company
to allow a single set of NetKernel modules
provide configurations unique to their
production, test, staging and development platforms.
Notice that the request includes a reference to a service
active:hostname,
which presumably returns the host name of the current computer.
This information is then used by the
active:configuration
service to provide different configuration resources for a standard
resource request depending on the machine running the application.
All of the information and all of the services within the
request context are available for the mapping.
This implies that architectural designs that in
pure physical system would require extensive code
can be created declaratively with NetKernel's
ROC platform.
Optional Elements
id
The id element specifies the logical endpoint identifier for the
logical endpoint declared in the mapper configuration.
If the inner logical endpoint has a logical endpoint identifier, the
id declaration overrides the value of the inner logical endpoint.
name, doc, icon, description
The name, description, icon and doc
elements can be placed within an endpoint declaration
to override any defaults which may be generated or inherited from the delegated endpoint.
The endpoint declaration supports the standard endpoint metadata
standard endpoint metadata declarations
A header element sets a response header name-value pair.
The header must have a name attribute which specifies the
header key and must have either a text value or a nested
literal tag that is used to specify the header value.
An endpoint may have any number of header elements.
For example, to set the MIME type of a response use the following
header element:
<header name="mime">text/html</header>
or
<header name="mime">
<literal type="string">text/html</literal>
</header>
Setting a response to not cache:
<header name="no-cache">
<literal type="boolean">true</literal>
</header>
verbs
The verb element can contain a comma separate list of verbs that constrain
the verbs that are resolved to the endpoint.
For example:
<verbs>SOURCE,SINK</verbs>
constrains request resolution to those request using either SOURCE
or SINK and no others.
The supported verbs are SOURCE, SINK, NEW, DELETE and EXISTS.
public / private / protected
Logical endpoint declared in the mapper overlay are always
visible in the wrapped space.
In addition, their visibility beyond the wrapped space may be controlled.
By default, logical endpoints are public;
they can be referenced within the wrapped space,
the host space and spaces that import the host space.
If the protected element is added to an endpoint declaration then that
endpoint will be visible in the wrapped space, and the host space but not
in spaces that import the host space.
If the private element is added to an endpoint declaration then that
endpoint will be visible in the wrapped space only.
It will not be visible in the host space nor in spaces that import
the host space.
Configuration Import
The mapper overlay configuration may be import in whole or in parts.
To import in whole, the config element contains a reference
for a resource containing the configuration information:
<config>res:/resources/mapperConfig.xml</config>
In addition a configuration resource may contain import elements
which refer to a portion of the configuration information:
<config>
<endpoint />
<import>res:/resources/moreConfig.xml</import>
</config>
There is no limit to the depth to which imports may be made.