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 .

Instead of overriding the onRequest(...) method, most endpoints will leverage verb detection and override one of the methods onSource(...), onSink(...). etc.

Request analysis, the first step in request evaluation, involves examining the request to determine what is being asked of the endpoint. The kernel provides access to the request context through an argument pass to the endpoint's onRequest(...) method. Request analysis can be simple or sophisticated and can include examining the identifier, verb, arguments, and the requested representation class. Information specific to the request is provided in an instance of INKFRequestReadOnly which can be retrieved from the context with a call the context's getThisRequest() method:

INFKRequestReadOnly thisRequest = context.getThisRequest();

Identifier

The method getIdentifier() returns the resource identifier used in the request.

String identifier = thisRequest.getIdentifier();

This method provides the complete opaque identifier string token of the request. Usually an endpoint uses a grammar to define how the opaque identifier is to be parsed into useful constituent parts. Those parts have assigned group names which maps to arguments; INFKRequestReadOnly provides methods to obtain and reference arguments directly (see below).

Endpoint Identifier

When implementing overlays and other endpoints which may receive requests for many logical endpoints it is often useful to identify which of those logical endpoints the received request was resolved to. The INKFRequestReadOnly.getResolvedElementId() method returns this.

String logicalEndpointId = thisRequest.getResolvedElementId();

Example

An accessor endpoint is declared in a space and uses the endpoint identifier "customer:list" as show in part below:

<accessor>
  <id>customer:list</id>
  <!--- rest of accessor endpoint declaration -->
</accessor>

When the endpoint processes a SOURCE request, it is able to find the identifier is has been declared with as shown in the following code:

public void onSource(INKFRequestContext context)
{ String elementId = context.getThisRequest().getResolvedElementId();
  ...
}

Verb

Automatic

The base classes detect if any on... methods (such as onSource(...)) are used and will automatically set meta information for the endpoint indicating which verbs the endpoint handles.

The recommend way to detect the request verb is to delegate the task to the endpoint's base classes. To use automatic verb detection, simply override one or more of these methods.

  • onSource(...)
  • onSink(...)
  • onNew(...)
  • onDelete(...)
  • onExists(...)
  • onTransrept(...)
  • onMeta(...)

Example

public void onSource(INKFRequestContext context)
  {
  // Process the request when the SOURCE verb is used
  }

public void onSink(INKFRequestContext context)
  {
  // Process the request when the SINK verb is used
  }

Manual

When the majority of code in an endpoint is common to all supported verbs, it is often easier to use manual verb detection. To use manual detection, add endpoint meta data listing the supported verbs with the declareSupportedVerbs(...) method and override the onRequest(...) method.

For example, the following no-argument constructor sets endpoint meta data indicating that the SOURCE and SINK verbs are handled by the endpoint:

public MyEndpoint()
  {
  declareSupportedVerbs(INKFRequestReadOnly.VERB_SOURCE | INKFRequestReadOnly.VERB_SINK);
  }

The request verb is available as an integer value. Constants defining the verb values are included in the interface INKFRequestReadOnly as:

INKFRequestReadOnly.VERB_SOURCE
INKFRequestReadOnly.VERB_SINK
INKFRequestReadOnly.VERB_NEW
INKFRequestReadOnly.VERB_EXISTS
INKFRequestReadOnly.VERB_DELETE
INKFRequestReadOnly.VERB_TRANSREPT
INKFRequestReadOnly.VERB_META

For example, the following code tests to see if the request uses the SOURCE verb:

onRequest(INKFRequestContext context)
  {
  if (context.getThisRequest.getVerb() == INKFRequestReadOnly.VERB_SOURCE) 
    {
    ...   
    }
  }

Argument Processing

Operand / Operator Convention

A convention you will encounter is the use of the generic argument names operand and operator. In this convention, operand is the resource to be transformed and the operator is the resource that specifies the transformation. This pattern occurs so frequently that it becomes very convenient to use these names to implicitly hint at the semantics of the endpoint.

For example, the service active:xslt uses operand for the document to be transformed and operator for the XSLT transform.

Information is passed in requests using named arguments.

Usually the value of a named argument is a reference, a resource identifier referencing information the endpoint needs to perform its work. In other cases the argument value is the actual value being passed.

Argument Value as Reference

When the value associated with a named argument is an identifier, the endpoint may treat the value in two ways.

If it needs the referenced resource to perform its work, then it will issue a SOURCE request to obtain a representation of the information. The "arg" URI scheme can be used to refer, indirectly, to the identifier associated with a named argument. For example, "arg:operand", will be automatically dereferenced by NKF, and is understood to be the identifier associated with the named argument "operand".

A specific example will make this clear. Within the endpoint that resolves the identifier active:toUpper+operand@res:/readme.txt, the following code:

Object representation = context.source("arg:operand");

results in a SOURCE request being issued for the resource res:/readme.txt.

If instead the endpoint needs to work with the resource reference itself, (potentially modifying it and then using it for a request), then it will obtain the value of the argument directly as shown in the following code:

String resourceIdentifier = thisRquest.getArgumentValue("operand");

in which case the variable resourceIdentifier will be set to res:/readme.txt.

Argument Value as Value

In some situations the endpoint will be passed a value directly as the value of a named argument. The value can be requested as a String with the getArgumentValue(...) method. For example, if the request identifier is active:random+lower@0+upper@100 and the endpoint needs the values of the arguments ("0" and "100") the following code obtains the literal values:

String lower = thisRequest.getArgumentValue("lower");
String upper = thisRequest.getArgumetnValue("upper");

Setting the variable lower to "0" and the variable upper to "100".

Optional Arguments

And endpoint may check to see if a specific named argument is present in the current request by using the argumentExists(...) method. For example, the following code checks to see if the argument operand is included in the request:

if (thisRequest.argumentExists("operand")) {
  {
  //...
  }

As another example, consider our endpoint which resolves active:random+lower@0+upper@100. The following code will see if the lower argument is provided and set an internal variable to its value, otherwise, it will use a default value:

private static final int DEFAULT_LOWER_RANDOM_VALUE = 0;
...
// Get lower limit to random number
int lowerRandomValue = DEFAULT_LOWER_RANDOM_VALUE;
if (thisRequest.argumentExists("lower"))
  {
  try
    {
    int lowerRandomValue = Integer.parseInt(thisRequest.getArgumentValue("lower"));
    }
  catch(NumberFormatException nfe)
    {
    throw new NetKernelException("Invalid value provided for lower argument", "Details", nfe);
    }    
  }

Variable Number of Arguments

It is possible to create an endpoint binding with a grammar that uses variable arguments:

<grammar>
  <active>
    <identifier>active:myService</identifier>
    <varargs />
  </active>
</grammar>

Such a grammar will match active:myService with zero or more argument with any name and values. To assess a request that resolves with this grammar the endpoint code must iterate through the arguments and analyze them individually. The following example illustrates one such approach:

int numberOfArguments = thisRequest.getArgumentCount();

With this count a iteration loop can be written:

int numberOfArguments = thisRequest.getArgumentCount();
for (i=0; i < numberOfArguments; i++)
  {
  String argumentName  = thisRequest.getArgumentName(i);
  String argumentValue = thisRequest.getArgumentValue(i);
  // Process argument...
  }

Primary Argument

Some requests need to supply a single implicit argument. A request with the SINK verb needs to supply a representation to sink to the resource. A request with the TRANSREPT verb needs to supply a representation to be transformed into a different representation. A single, implicit argument is called a primary argument.

Direct

An endpoint can obtain the primary argument information in two ways. The first retrieves the same representation, as it was set in the request, using the getPrimary() method:.

Object primary = thisRequest.getPrimary();

Example

The requestor creates a SINK request and supplies information in a String representation.

request = context.createRequest("transient:ID");
request.addPrimaryArgument("RT44938");
request.setVerb(INKFRequestReadOnly.VERB_SINK);
context.issueRequest(request);

The resolved endpoint can retrieve the representation with the following code:

public void onSink(INKFRequestContext context)
  {
  Object primaryRepresentation = context.getPrimary();
  ...
  }

In this example the variable primaryRepresentation refers to exactly the same object that was set as the primary argument by the requestor.

Request

The second way an endpoint can retrieve the information passed as a primary argument is to issue a SOURCE request using the sourcePrimary(...) method. This is the preferred method when the resolved endpoint expects representation in a particular form.

Example

An endpoint resolves SINK requests and stores information in binary stream form. It will retrieve the primary argument as a IBinaryStreamRepresentation:

public void onSink(INKFRequestContext context)
  {
  IBinaryStreamRepresentation primary = context.sourcePrimary(IBinaryStreamRepresentation.class);
  ...
  }

Representation Class

The specific representation class requested by the requesting client can be determined with the following code:

Class requestedRepresentationClass = thisRequest.getRepresentationClass();

Generally, accessors can safely ignore the request representation class and rely on transreptors to transform the representation returned to the one requested. Transreptors do need the specific requested representation class; this is discussed in detail in the documentation on transreptor development.