This page holds a mixed-up collection of gotchas, tips and hard won advice when working with NetKernel applications.
<element>
tagsWhen 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>".
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>
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:
<category>doc accessor</category>
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.
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 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:
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 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).
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)
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).
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 <regex>
assert can successfully be used on any representation object that has a toString() method.
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:
this:storeURI
assignment representation (a resource URI in this case)response
from the sequence
.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:
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)
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!
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