WARNING: This server provides a static reference view of the NetKernel documentation. Links to dynamic content do not work. For the best experience we recommend you install NetKernel and view the documentation in the live system .

Significant portions of applications can be composed with DPML using the tools and services provided by resource models. However, sometimes you will want to develop a new tool or service using a language such as Java, Scala, Groovy, Ruby, Python, etc.

Developing in NetKernel is similar to developing a script or program called by a web server. A web server manages the relationship with the Web: it receives requests, determines which script or program to call, invokes it and then returns the response of the script to the requesting client.

Similarly, in NetKernel requests are resolved to executable services called endpoints (you will see how this occurs in the next section) which are invoked and the response returned to the requestor.

Programming languages in NetKernel can make and receive requests through the NetKernel Foundation API (NKF).

Java Endpoint Example

Let's look at the Java implementation of the active:toUpper service we used in an earlier example and see how it works. If you recall from the example, the service was requested when the following identifier was used for a request:

active:toUpper+operand@res:/greeting

The example can be run by clicking on: active:toUpper+operand@res:/greeting

A request with this identifier is resolved to our endpoint, an instance of the class ToUpperAccessor, and the kernel calls the endpoint's onSource(...) method because the SOURCE verb was used in the request.

Notice that the onSource(...) method is passed an instance of INKFRequestContext, which provides the endpoint all of the contextual information related to the request.

import org.netkernel.layer0.nkf.INKFRequestContext;
import org.netkernel.layer0.nkf.INKFResponse;
import org.netkernel.module.standard.endpoint.StandardAccessorImpl;

public class ToUpperAccessor extends StandardAccessorImpl
  {
  public void onSource(INKFRequestContext context) throws Exception
    {
    // Issue a sub-request to SOURCE the resource specified by the "operand" argument
    String operand = context.source("arg:operand", String.class);
    //Transform the resource to uppercase
    operand = operand.toUpperCase();
    //Return the transformed resource
    context.createResponseFrom(operand).setMimeType("text/plain");
    }
  }

It is important to note the stateless nature of the code; when the onSource() method is called it is provided all the state required to evaluate the request. Specifically, the context object passed to the onSource() method provides access to the full logical context of the request including request arguments, address spaces, etc.

Request evaluation involves four steps:

  1. Analysis of the request (what is being asked?)
  2. Gather additional information (construct and issue more requests)
  3. Add value (compute a representation from all the gathered state)
  4. Create a response with the representation.

This physical level code still has full access to the logical resource address space.

In a resource oriented computing platform, a service (an endpoint) is given a URI identifier for each argument.

In this case, the argument operand has as its value the URI res:/greeting, which identifies the resource the service is to transform. The endpoint must then make a resource request for the information it is to transform. It does this in the first line:

String operand = context.source("arg:operand", String.class);

Which simply means

"Locate and return the resource identified by the value of the operand argument and return it as a String representation."

More often than not, this sub-request will find the requested resource in cache. For example, if you tried the DPML exercise of changing the active:toUpper transform to request the Web resource http://resources.1060research.com/greeting.txt - then the first time you requested it, it was pulled off the remote server (by an endpoint that handles http requests) and was locally cached, so the second and subsequent uses cost us nothing to retrieve from cache. Therefore by re-entering the logical resource address space we will yield net performance benefits.

Dynamic Languages

An endpoint can be implemented just as easily using a dynamic language such as Groovy, Python or Ruby. In NetKernel dynamic languages are implemented as requestable services called a language runtime. For example to execute groovy scripts you call the active:groovy language runtime and tell it the URI of the script to execute. (Yes programs are also modelled as resources).

A version of toUpper written in Groovy is shown below. In scripting languages, the language runtime provides the context object which is an instance of the INKFRequestContext we met earlier in the Java example...

operand = context.source("arg:operand", String.class)
operand = operand.toUpperCase()
response = context.createResponseFrom(operand)
response.setMimeType("text/plain")

This example can be run by clicking this link: active:groovy+operator@res:/toUpper.gy+operand@res:/greeting

Comments

We covered a lot of concepts and details in this section. The crucial thing to remember is that physical code resides within a logical address space and is sent requests, can make its own requests for resources and ultimately returns a response with a representation.