-
Notifications
You must be signed in to change notification settings - Fork 72
Data Services for IO
The Data Services approach provides an interface on a middle tier or other backend server for data operations implemented by an endpoint on a MarkLogic enode. This approach supports a good division of responsibilities between the middle-tier or backend generalist and the MarkLogic specialist as well as encapsulation of database knowledge within the data service.
As described elsewhere, the Java API provides tooling for generating a Java interface based on an endpoint declaration. For more information about that approach, see:
http://docs.marklogic.com/guide/java/DataServices
The Java API also provides the following out-of-the-box interfaces in the dataservices package for Data Service endpoints that implement document IO:
Interface | Behavior required for the implementing endpoint |
---|---|
InputCaller | Takes zero or more documents as input with no output |
OutputCaller | Returns zero or more documents as output with no input |
InputOutputCaller | Both takes documents as input and returns documents as output |
ExecCaller | Executes with neither input or output |
An instance of one of the interfaces is constructed by calling its on()
factory method with
- a DatabaseClient specifying the appserver and user authentication
- a JSONWriteHandle providing the
*.api
declaration for the endpoint - a BufferableContentHandle specifying the Java representation of the input documents if the endpoint takes input
- a BufferableContentHandle specifying the Java representation of the output documents if the endpoint takes output
Classes implementing BufferableContentHandle include InputStreamHandle for representing and a document as an InputStream and StringHandle for representing a document as a string.
The following example constructs an InputCaller instance for calling an endpoint that takes JSON document input as Java String instances without returning any output:
InputCaller<String> caller = InputCaller.on(
dbClient, apiDeclaration, new StringHandle()
);
The *.api
declaration must have an endpoint
property specifying the full path
of the main module in the modules database. Any functionName
property in
the *.api
declaration is ignored when using an out-of-the-box IO endpoint interface.
In most cases, the data type of the input parameter or return value specifies
the format of the input or output documents. The only exception is the anyDocument
data type, which allows a mix of formats such as a mix of JSON and XML documents.
For the anyDocument
data type, us the onHandles()
factory method instead of
the on()
factory method to construct the caller. The input or output must be
sent or received as handle instances of the same BufferableContentHandle subclass
passed to the onHandles()
factory method. In particular, each input handle must
declare the format of the input document (for instance, by calling the
withFormat()
fluent setter).
For other data types, the BufferableContentHandle passed to the on()
factory
method must either specify a Format consistent with the document data type
in the *.api
declaration or specify no format.
When constructing an InputCaller instance, the endpoint must conform to
the following *.api
declaration:
{
"endpoint": "INPUT_CALLER_PATH",
"params": [
{"name":"input", "datatype":"DOCUMENT_TYPE", "multiple":true, "nullable":true}
]
}
To call the specified input caller, use the InputCaller.call() method, passing an array of objects in the representation supported by the input BufferableContentHandle:
void call(I[] input);
For instance, for an input caller constructed with a StringHandle, the call() method takes a String[] array.
Note: Where possible, supply input documents in a representation that can be resent if the request needs to be retried. Where the document representation can be sent more than once (as with String), the handle implements the ResendableContentHandle marker interface. Conversely, where the document representation can only be sent once (as with InputStream), the handle implements the StreamingContentHandle marker interface.
When constructing an OutputCaller instance, the endpoint must conform to
the following *.api
declaration:
{
"endpoint": "OUTPUT_CALLER_PATH",
"return": {"datatype":"DOCUMENT_TYPE", "multiple":true, "nullable":true}
}
To call the specified Output caller, use the OutputCaller.call() method to receive an array of objects in the representation supported by the output BufferableContentHandle:
O[] call();
For instance, for an output caller constructed with a InputStreamHandle, the call() method returns an InputStream[] array.
Where input documents should be resendable, output documents can be streaming because the output are received instead of sent.
When constructing an InputOutputCaller instance, the endpoint must conform to
the following *.api
declaration:
{
"endpoint": "INPUT_OUTPUT_CALLER_PATH",
"params": [
{"name":"input", "datatype":"DOCUMENT_TYPE", "multiple":true, "nullable":true}
],
"return": {"datatype":"DOCUMENT_TYPE", "multiple":true, "nullable":true}
}
To call the specified input-output caller, use the InputOutputCaller.call() method:
O[] call(I[] input);
When constructing an ExecCaller instance, the endpoint must conform to
the following *.api
declaration:
{
"endpoint": "EXEC_CALLER_PATH"
}
To call the specified exec caller, use the ExecCaller.call() method:
void call();
Note: The same interfaces are also used for constructing bulk IO callers when Integrating Dataflow Frameworks With MarkLogic.