Gotchas

This page holds a mixed-up collection of gotchas, tips and hard won advice when working with NetKernel applications.

Markdown documentation unterminated <element> tags

When writing NetKernel book or endpoint documentation markup files, any xml element tags in the text must be either teminated or `quoted` with backticks.

This markup line:

2. Created a <rootspace> with public="false" (want to hide csv file from rest of system)

will cause the following exception to be reported in the NetKernel system log:

org.xml.sax.SAXParseException
The element type "rootspace" must be terminated by the matching end-tag "</rootspace>".

Test xpath expressions with active:fragmentHDS

Use the active:fragmentHDS resource in conjunction with the RequestTrace tool to experiment with xpath expressions (where the expression is supposed to return a single node). You need a org.netkernel.mod.hds space imported into the application space, and then inject a request into an application space, using other resources and test data available:

<request>
  <identifier>active:fragmentHDS</identifier>
  <argument name="xpath"><literal type="string">/teamResults/teamResult[team='Liverpool']</literal></argument>
  <argument name="operand">
        <request>
          <identifier>active:HomeResults</identifier>
            <argument name="matches">active:MatchResults+season@2014-2015</argument>
        </request>
  </argument>
</request>

Endpoint documentation

NetKernel automatically generates a documentation page for every space and endpoint from information provided in the module.xml file. These pages can be enhanced with additional content:

  1. to add a doc (referenced in the module’s etc/system/Docs.xml) for each endpoint you want to document, also specifying <category>doc accessor</category>
  2. adding {endpoint}MyEndpointUri{endpoint} macro to bring in the auto-generated endpoint documentation.

Also, if you add a doc for an endpoint (using the {endpoint .. {/endpoint}) macro, it will not show up properly in the Space Explorer until you rebuild the search index of the NK instance.

XUnit test space endpoints must be public

All endpoints in a NetKernel XUnit unit test space MUST BE PUBLIC! This includes any <import>ed spaces required for the tests. Private endpoints (with <private />) simply cannot be resolved by the external XUnit test manager, and your tests will fail mysteriously with Request Resolution Failure errors.

Exporting classes from a module

Exporting contents of jars from a module using the <system><classpath></classpath><export> must specify the correct regex to include all classes and other files you want to expose to other modules. eg:

  1. “com.foo.bar..*” for all java classes in the com.foo.bar package (and sub-packages).
  2. “com/foo/bar/..*” for java resource files of any type under the module file path com/foo/bar

NB: Use the backend fulcrum ClassTrace tool to test if the exported classes are resolvable as expected.

NB: (Another gotcha!) Exported classes from a module are only available within spaces that direct import a public space in that module. They do not automatically export higher up in the superstack. If that is required, the higher-level module must declare its own classpath element for the same classes.

The active:java resource cannot access classes from request superstack

The active:java language runtime endpoint does not get access to Netkernel’s superstack classloader (ie. access to classes via modules imported into the module containing the active:java endpoint). It only gets access to the local module lib/ folder and classes in the module src tree itself (unlike other language runtime endpoints like active:groovy).

Empty XUnit declaration

AN XUnit test definition must have a non-empty <request> element, specifying a declarative request, else the test manager runtime throws a confusing IndexOutOfBoundsException (Index: 0, Size: 0)

Mapper Endpoint Declarative Request Typo

This mapper endpoint declarative request snippet contains a typo (”identifer”):

<endpoint>
    <grammar .... </grammar>
    <request>
        <identifer>res:/response</identifer>
    </request>
</endpoint>

The module.xml is loaded OK by NetKernel, but when a request issued to the Mapper endpoint, the following error is reported:

Failure to resolve mapped resource in a mapper endpoint
Request Resolution Failure
SOURCE SUBe42d8edd-13d8-4b07-a451-de457ebbd8cf as Object

The reason that NetKernel did not detect the typo when parsing the module.xml is that it assumed it was using an abbreviated request declaration (because of the absence of an <identifier> tag).

Lang/SCXML State Machine Module

Must use pass-by-value into active:scxml endpoint:

def dataMap = ["foo": "bar"]
                
smReq=context.createRequest("active:scxml");
smReq.addArgument("operator","res:/some/scxml.xml");
smReq.addArgument("state",persistenceURI);
smReq.addArgument("event",event);
smReq.addArgumentByValue("data", dataMap);
smReq.addArgumentByValue("debug", 10);
newState=context.issueRequest(smReq);

SCXML runtime debug trace visible in Representation Cache Viewer against active:getSCXMLState resource:

  DEBUG : null
    EVENT : null
      TIMESTAMP : 01:00:00.000
      ENTRY : raised
        REQUEST : active:myService+foo@pbv%3Afoo
    EVENT : raised
      TIMESTAMP : 09:16:14.388

XUnit built-in assertion

XUnit assert Contrary to the current (c. May 2018) XUnit documentation (http://docs.netkernel.org/book/view/book:mod:test:book/doc:mod:test:guide:builtin-asserts) which states “regex - representation must be a java.lang.String and must match the regular expression pattern specified as the value.”, the <regex> assert can successfully be used on any representation object that has a toString() method.

DPML dereference

Use the DPML dereference element to issue a request for a resource returned from a previous request in a DPML sequence or closure.

Example:

<sequence>
  <request assignment="storeURI">
          <identifier>active:store</identifier>
          <verb>NEW</verb>
          <argument name="prefixURI">uk/co/rsbatechnology/gotchas</argument>
          <argument name="primary">
            <literal type="hds">
              <abc />
            </literal>
          </argument>
  </request>
  <dereference assignment="response">this:storeURI</dereference>
</sequence>

Here, the active:store request returns the full resource URI of a newly-created resource, which is assigned to the storeURI local assignment. Then the dereference does the following:

  1. SOURCEs the this:storeURI assignment representation (a resource URI in this case)
  2. SOURCEs the resource URI
  3. Assigns the returned representation as the response from the sequence.

Always use setRepresentationClass on a programmatic sub-request when using issueRequest or issueAsyncRequest

It is good practise to always explicitly declare the type of a resource representation with the setRepresentationClass method on a INKFRequest object when programmatically issuing a general request. If you don’t, you will get whatever representation type is supplied back from the request (which may not be what you expect - see below!).

So, always do this:

INKFRequest request = context.createRequest(...);
request.setRepresentationClass(MyClass.class);
MyClass response = (MyClass) context.issueRequest(request);

Another best-practise example, this time in groovy code:

existsReq = context.createRequest(...);
existsReq.setRepresentationClass(Boolean.class);
existsReq.setVerb(INKFRequestReadOnly.VERB_EXISTS);
doesExist = context.issueRequest(existsReq);

Yet another example, this time as a declared subrequest in a SCXML runtime configuration resource:

<nk:request>
  <nk:identifier>active:isSomethingTrue</nk:identifier>
  <nk:representation>java.lang.Boolean</nk:representation>
</nk:request>

Notes:

  1. Using setRepresentationClass further de-couples your endpoint from the implementation of the sub-request endpoint. You should not need to know or care what Java type is actually returned from the requested endpoint, just whether you can obtain the request’s returned representation in the type you want. NetKernel’s automatic transreption capability will take care of any type conversion necessary (or tell you immediately that a converson is not possible by throwing an exception)

  2. When using NetKernel’s distributed architecture across multiple Java processes, the NKP protocol converts all request representations into binary before transmitting over a network. That means that the Java type of a sub-request’s returned representation might be in binary format (actually an object of the NetKernel IBinaryStreamRepresentation type) if it happened to be handled by another NetKernel instance. But if the sub-request was handled in the same NetKernel instance as the requesting endpoint instead, it would return an object of the original type (e.g. String).

    When you write an endpoint that issues sub-requests, you must not assume that the subrequest will be transmitted over NKP or handled locally .. what if that changes in the future. So use setRepresentationClass and relax!

jvmsettings.cnf

The jvmsettings.cnf file in the NetKernel installation bin folder enables additional arguments to be passed to the java command line that launches NetKernel (via the bin/netkernel.sh or bin/netkernel.bat scripts).

It is important to remember that both launch scripts expect the contents of the jvmsettings.cnf file to be a single line. The scripts only add the first line in the jvmsettings.cnf file to the java comnmand that launches NetKernel.

An example of a working one-line jvmsettings.cnf file:

-server -Dnetkernel.http.backend.port=1071 -Dnetkernel.http.frontend.port=8081 -XX:+UseParallelOldGC -Xmx1024m -Xms1024m -Dfile.encoding=UTF-8