The NetKernel Foundation API (NKF) is provided as
a set of java interfaces exported by the Layer1 module (urn:org:ten60:netkernel:ext:layer1).
It provides a clean foundation for developing scripts, accessors, transports and transreptors.
NKF offers an abstraction which manages the complexity of direct request interaction with the kernel APIs.
A single consistent request context is available, through which NetKernel requests are made and responses may be
issued.
NKF is the recommended API for developing netkernel components and is also the standard API provided to scripts executing in
the NetKernel Scripting Framework.
NKF role is to provide 95% of the functionality a developer will ever need with a fraction of the complexity.
If low-level access to the kernel is needed or you wish to develop accessors that
return their responses asychronously (Note: this is different to making asychronous sub-requests) you
can subclass the
org.ten60.netkernel.layer1.accessor.AccessorImpl from the Layer1 module and
use the kernel's URII and URRequest APIs directly.
NKF provides base-classes which should be extended to implement Accessors, Transports
and Transreptors.
Javadoc
Here is the Javadoc for the NetKernel Foundation API.
Script Demonstrations
A number of demonstrations of the use of NKF can be seen in the scripting trailmap located here.
General Processing Model
The general operational pattern for all NKF components is:
- Retrieve and process arguments from the initiating request
- Perform necessary processing including, if necessary, issuing further sub-requests to other services.
- Create a response, configure it and issue it as the response to the intiating request.
Note: a Transport has no initiating NetKernel request - transports initiate NetKernel requests based upon some external event, such as for example an HTTP request.
Therefore Transports are a special case that are purely concerned with stage 2.
NKF Accessors
Accessors are the most common NetKernel software component. They are client/servers which are invoked by the kernel when a matching URI request is made.
The org.ten60.netkernel.layer1.nkf.impl.NKFAccessorImpl class is the base class for developing accessors which use
the NetKernel Foundation API. The NKFAccessorImpl must implement:
void processRequest(INKFConvenienceHelper context)
A URI request which matches an NKF Accessor's URI address space will cause the kernel to invoke the processRequest method. The underlying NKFAccessorImpl
manages the initiating kernel request and provides a number of services for interacting with the kernel, these are made available through the
INKFConvenienceHelper.
The INKFConvenienceHelper or context object is the primary means to access initiating requests, to issue sub-requests to the kernel and to issue a response
to the invoking request.
Scripting Note: In the NetKernel Scripting Framework a script execution commences as the result of a call to processRequest() in the underlying ScriptEngine
accessor.Each script receives the INKFConvenienceHelper object which in all scripts is called the context object and which, in the script, has global scope.
Conceptually you can think of a script execution as a dynamically coded accessor and the context object provides access to the initiating request in just the same way.
Requests
NetKernel requests are active URIs with arguments which are URI addressable. The
request which initiated a component can be retrieved with
INKFRequestReadOnly reqro=context.getThisRequest()
The INKFRequestReadOnly interface allows
the components of an active URI request to be queried and/or retrieved.
In addition, as with DPML, arguments can be accessed using the this:param URI scheme. For example, suppose we had a request URI
active:myAccessor+arg1@ffcpl:/myResource.xml. The resource ffcpl:/myResource.xml can be sourced with
context.source("this:param:arg1")
Sub-Requests
A sub-request is just a request which is issued from the current accessor to the kernel which will attempt to find a service to fulfil the request in the
local URI address space. INKFHelperImpl provides a method to create a new sub-request
INKFRequest req=context.createSubRequest()
Before the sub-request can be issued it must be configured. The base URI must be set using
req.setURI("..")
For example, to request an XSLT transform you would set the base URI to active:xslt.
Arguments on the active URI request can be configured with
req.addArgument("myArg", ...). The addArgument() method is overloaded and supports a number of means for passing arguments either by
reference (URI) or by value (Aspect).
The INKFRequest also permits setting the Aspect (type of resource) which you wish to receive as the result of the request. This is done with
req.setAspectClass(...), which takes as it's argument the interface class of the aspect to be returned. For example to
return a binary stream use IAspectBinaryStream.class, or to get an XML aspect, use IXAspect.class.
Once a request has been configured it can be issued to the kernel for fulfilment with
IURRepresentation result=context.issueSubRequest(req)
The result of the request will be an
IURRepresentation - from which you can obtain the Aspect you requested with the getAspect(...) method.
Synchronous sub-requests issued from the NKF API will block until serviced - NetKernel is architected to guarantee that synchronous requests do not
lead to the creation of unneccessary threads and that thread starvation will not occur. In short, synchronous calls don't cause any problems to NetKernel.
However, NetKernel is fully asynchronous, see the next section for asynchronous requests.
The NKF API provides all the necessary infrastructure for handling and initiating requests. However if you need more detail on the
low-level NetKernel URRequest API see the guide here.
Asynchronous Sub-Requests
A URI request may be issued asynchronously (ie executed concurrently). This is achieved by calling the issueAsyncSubRequest() method.
INKFAsyncRequestHandle handle=context.issueAsyncSubRequest(req)
This method is non-blocking, an asynchronous request is issued to the kernel scheduler and returns immediately with an
INKFAsyncRequestHandle. The request handle may be used to
join the sub-request and retrieve it's result. This is accomplished with the join() method - which is blocking and will wait until the sub-request has completed.
IURRepresentation rep=handle.join();
If the sub-request is never joined it's result is discarded. The intitiating process may then complete but the child sub-request will continue execution
until it completes. In this way child processes are spawned.
Response
In general an accessor will issue some resource as it's response. To issue a response an
INKFResponse object must be created and configured.
The INKFConvenienceHelper allows a
INKFResponse object to be created from either a representation or an aspect.
INKFResponse resp=context.createResponseFrom(..)
For convenience createResponseFrom() accepts either an aspect or representation. In fact NetKernel only works with representations,
so if you use an aspect the underlying NKFAccessorImpl will take care of creating a representation
with correct dependencies. If you need fine control you may create a representation holding your aspect and use it to construct your INKFResponse.
A number of optional methods may be used to configure the response. These include setting the mimetype and also the detailed caching
parameters such as cost and expiry time.
When the response is configured it should be issued by calling
context.setResponse(resp)
Transport/Transreptor Variations
This document has introduced NKF from the prespective of Accessors which is the most common component. The request context and INKFCovenienceHelper is
a common API used throughout all NKF-based components. See the Transport and
Transreptor guides for example of the NKF API in use by other components.