Address Resolution
The first step NetKernel takes to process a resource request is address resolution.
The purpose of this step is to locate the endpoint accessor that will be
given the request for processing.
When a resource address is resolved the logical and the physical levels
are bound for the duration of the request processing.
Once the request has been processed and the resource representation
returned the binding no longer exists.
In resource oriented computing the binding between the logical and
the physical levels occurs anew for each request.
This late and renewed binding results in tremendous flexibility.
Because binding occurs for each request, NetKernel is able to
change the bindings of a system as it is running without disrupting
the integrity of a system.
For example, a library module for an application can be updated in
an operational system.
Since all requests are intermediated by the microkernel NetKernel can
guarantee that modules are introduced to the system in an orderly
manner and that requests will go to the original library module
up until the moment that the new library module version has been
commissioned and is ready to accept requests.
Address resolution has negligible performance overhead and
in practice NetKernel applications run faster than
Java J2EE applications even though NetKernel is constantly renewing the dynamic
linking of the software system. The performance gains stem from the ability to
perform optimizations below the logical level, such as automatic and transparent caching
of computations, resolution caching and dynamic compilation of resources.
Once you understand the address resolution process, specific examples
of resolution with existing modules can be examined with the Resource Request Trace Tool
located on the
Developer Tools
panel.
Transports, Modules and Address Resolution
Resource request processing starts when a transport detects an event.
In the following diagram an Actor (a concept from Use Case Analysis)
initiates processing by requesting a resource.
The actor will request a resource with an identifier that has
meaning in its context.
For example, if the transport is the HTTP transport the actor may request
the resource http://myco.com/forum/topic/281
.
The transport detects this request as an event and acts as an adapter,
interpreting the external request and creating an internal resource
request.
For example, the above HTTP request could be translated into a
resource request for the resource identified by the address
ffcpl:/forum/topic/281
along with HTTP parameter
or header information supplied in the resource request as request parameters.
Transports inject root requests into their hosting fulcrum module.
Generally fulcrum modules do not provide any resources or services
and instead import one or more modules that constitute the supported
application(s).
As you will see in detail in the section on
modules, modules
export a portion of their address space and when imported
these exported address spaces become a part of the importing
module's private address space.
This is a critical point which we will illustrate with an example.
In the diagram above the fulcrum is importing two modules.
In our example, one module exports the address space
ffcpl:/accounting/.*
and the second exports the address space
ffcpl:/shipping/.*
.
These exported address spaces define two portions of the fulcrum's private
address space making it capable of resolving resource
requests for resources with an address that starts with
either ffcpl:/shipping/
or ffcpl:/accounting/
.
From the transport's perspective, it does not know whether this address
space is provided by the fulcrum or imported modules, it only sees
that root requests for resources in these address spaces are accepted
and processed.
To resolve an address NetKernel uses a "first match wins" approach.
As soon as it discovers a mapping from an logical URI address to
an endpoint, the resolution step completes.
The search order is well defined; imported modules are examined for
an address space match in the order they are listed in the importing
module's module.xml file.
Imported address spaces may overlap. For example if the fulcrum imports
a module that exports ffcpl:/accounting/.*
and then
imports a module that exports ffcpl:/account.*/.*
there
is an overlap.
Because the fulcrum imports in the stated order all requests for
resources in the ffcpl:/accounting/.*
address space
will be resolved (or not) in the first module; the second module
will never be searched.
This is an important point - if a resource for example for
ffcpl:/accounting/readme
is not resolved in the
first module then the resolution step fails, NetKernel will not
attempt to locate the resource in the second module.
Because the address resolution step involves a search that proceeds
along a well defined path, an alternate way of viewing this
is message routing.
It can be seen that a resource request is routed to various modules
for processing.
You will see and hear the term "request routing" frequently as an
alternate way to describe what happens in the address resolution
step of request processing.
When the search for an address enters a module it passes through
a series of re-write rules and then the local mappings to
endpoints as well as that module's import statements.
(There is no limit to the depth of module imports and since each
level can model an architectural layer in a system, NetKernel
can accommodate any application design.)
Resource requests use URI addresses expressed in textual form.
Because the address is text one can use
regular expression
pattern matching to define
mappings to endpoints as well as rewrite rules that transform the
address.
For example, you could route all requests for URI addresses that match the
regular expression (.*)/library/(.*) to a module containing library support code.
Similarly you could alter the address so the URI addresses that match the
regular expression (.*)/library/(.*) are rewritten to this new
pattern: $1/new-library/$2.
The use of pattern matching with textual URI addresses
creates enormous flexibility in applications.
The routing and matching rules can describe complex relationship
with a minimum of code.
While searching for an endpoint NetKernel consults mapping and
rewrite rules in various modules along a well defined search path.
If a rewrite rule is encountered the actual textual URI address
can be changed causing NetKernel to use this new address from that
point forward in the search.
These rewrite rules can be expressed using
Regular Expressions
,
code using string operations or address mapping functions.
Nothing like this exists in the physical world of objects
and fixed memory addresses.
Much of the power and flexibility of NetKernel comes from the use
of logical addresses that can be adapted and routed into
different address spaces.
NetKernel's use of logical addressing instead
physical binding
allows NetKernel applications to be extremely flexible and malleable.