KA-RMT is a module of the Tractus-X Knowledge Agents Reference Implementations.
- see copyright notice in the top folder
- see license file in the top folder
- see authors file in the top folder
This is a folder providing a FOSS implementations of a Function Binding (aka Remoting) Agent.
Binding Agents are needed by any Agent-Enabled dataspace providers to connect the dataspace protocol/representation (here: a combination of the SPARQL query language/operating on RDF triple graphs) to the underlying business data and logic.
The Remoting Agent in particular is able to interact with typical REST backend services based on XML and/or JSON payloads. The SPARQL profile which is used is called KA-BIND-F (the Knowledge Agent Functional Binding Profile).
Tractus-X Remoting Agent is built on Eclipse RDF4J by introducing a (virtual) storage and inference layer (SAIL) that is indeed is backed by local Java classes and/or remote REST services.
The Remoting SAIL provides the implementation of a so-called repository (=a SPARQL endpoint that can be used as the target address of an EDC asset and/or as a service context in federated queries).
Each remoting repository is configured in a TTL (Terse Triple Language) configuration file using the org.eclipse.tractusx.agents:Remoting
Sailtype and lists
the available functions (=a particular class of nodes). Each remoting repository is parsed, represented and possibly exported from the runtime by means of Remoting SAIL Config, for each function (class), a corresponding Service Config is maintained.
Here is an example repository configuration which uses the public service https://api.agify.io
to make a prediction of the age of a person given its name.
# ... PREFIX declarations
[] rdf:type rep:Repository ;
rep:repositoryID "prognosis" ;
rdfs:label "Prognosis Functions" ;
rep:repositoryImpl [
rep:repositoryType "openrdf:SailRepository" ;
sr:sailImpl [
sail:sailType "org.eclipse.tractusx.agents:Remoting" ;
cx-fx:callbackAddress <http://localhost:8888/callback>;
cx-fx:supportsInvocation prognosis:Prognosis;
]
].
# Function declaration
prognosis:Prognosis rdf:type cx-fx:Function;
dcterms:description "Prognosis is a sample simulation function with input and output bindings."@en ;
dcterms:title "Prognosis" ;
cx-fx:targetUri "https://api.agify.io";
cx-common:authenticationCode "Dummy-Authorization";
cx-common:authenticationKey "Dummy-Key";
cx-fx:input prognosis:name;
cx-fx:result prognosis:hasResult.
prognosis:name rdf:type cx-fx:Argument;
dcterms:description "Name is an argument to the Prognosis function."@en ;
dcterms:title "Name";
cx-fx:argumentName "name".
prognosis:hasResult rdf:type cx-fx:Result;
cx-fx:output prognosis:prediction;
cx-fx:output prognosis:support.
prognosis:prediction rdf:type cx-fx:ReturnValue;
dcterms:description "Prediction (Value) is an integer-based output of the Prognosis function."@en ;
dcterms:title "Prediction" ;
cx-fx:valuePath "age";
cx-fx:dataType xsd:int.
prognosis:support rdf:type cx-fx:ReturnValue;
dcterms:description "Support (Value) is another integer-based output of the Prognosis function."@en ;
dcterms:title "Support" ;
cx-fx:valuePath "count";
cx-fx:dataType xsd:int.
# Further declarations ...
When a concrete query is sent to the RDF4J controller, a Remoting SAIL Connection is setup which evaluates the query with the help of the stateful Query Executor. With the help of the Remoting Sail Configuraiton, The Query Executor instantiates all function nodes as Invocations. During processing, input and output variables are accessed and stored in a BindingSet Collection for which the Query Executor implements the IBindingHost.
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX prognosis: <https://w3id.org/catenax/ontology/prognosis#>
SELECT ?name ?invocation ?prediction ?support
WHERE {
VALUES (?name) { "Schorsch"^^xsd:string }
?invocation a prognosis:Prognosis;
prognosis:name ?name;
prognosis:prediction ?prediction;
prognosis:support ?support.
}
Currently, there are two principle methods of function bindings available
- Class Binding (Service Config.targetUri follows the pattern "class:#")
- REST Binding (Service ConfigtargetUri follows the pattern "https?://")
For REST Binding, we support the following outgoing request formats/content types (being configured via Service Config.method). Note that responses are always interpreted as XML or JSON depending on the response content type.
- GET: Input arguments are mapped to URL query parameters.
- POST-XML: Input Arguments are mapped into an XML document body with content-type "application/xml" T
- POST-JSON: Input Arguments are mapped into an JSON document body with content-type "application/json"
- POST-JSON-MF: Input Arguments are mapped into JSON-based files send in a multi-part request with content-type multipart/form-data (and XXX as boundary and "application/json" as Content-Disposition)
- POST-XML-MF: Input Arguments are mapped into XML-based files send in a multi-part request with content-type multipart/form-data (and XXX as boundary and application/json as Content-Disposition)
Invocations can be batched. Normally (Service Config.batch is set to 1, no Argument Config.formsBatchGroup is set to true) Remoting Agent will produce an outgoing REST call for each incoming tuple/binding. If Service Config.batch is greater than 1 or there is some Argument Config.formsBatchGroup set to true, several tuples/bindings can be sent in a single invocation (usually in an array or by using flexible argument paths using '{}' path elements). In that case, we also expect the responses to contain several individual results which are mapped/joined with the original input bindings using the ResultConfig.correlationInput reference.
Invocation can be asynchronous. That means that the called backend will not return a proper response, just a successful notification code. Instead we send the public URL of the builtin CallbackController which is configured in the callbackAddress property of the remoting repository (and is transmitted in the callbackAddressProperty of the ServiceConfig). In order to correlate outgoing (batch) requests with asynchronous responses sent to the CallbackController, we rely on setting a unique request identifier specified in ServiceConfig.invocationIdProperty and comparing it with the content of the ResultConfig.callbackProperty
mvn package
This will generate
- a standalone jar containing all necessary rdf4j components to build your own repository server.
- a pluging jar which maybe dropped into an rdf4j server for remoting support.
The standalone jar](target/remoting-agent-1.9.5-SNAPSHOT.jar) contains an example application that runs a sample repository against a sample source
java -jar target/remoting-agent-1.9.5-SNAPSHOT.jar -Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG
You could either call
mvn install -Pwith-docker-image
or invoke the following docker command after a successful package run
docker build -t ghcr.io/catenax-ng/product-agents/remoting-agent:1.9.5-SNAPSHOT -f src/main/docker/Dockerfile .
This will create a docker image including an extended rdf4j-server as well as an interactive rdf4j-workbench.
To run the docker image, you could invoke this command
docker run -p 8081:8081 \
-v $(pwd)/src/test:/var/rdf4j/config \
ghcr.io/catenax-ng/product-agents/remoting-agent:1.9.5-SNAPSHOT
Afterwards, you should be able to access the local SparQL endpoint via the browser or by directly invoking a query
curl --location --request POST 'http://localhost:8081/resources' \
--header 'Content-Type: application/sparql-query' \
--header 'Accept: application/json' \
--data-raw 'PREFIX : <http://example.org/voc#>
SELECT ?x
WHERE {
?x a :Professor .
}'
You may manipulate any of the following environment variables to configure the image behaviour. Note that there is no builtin security (ssl/auth) for the exposed endpoints. This must be provided by hiding them in an appropriate service network layer.
ENVIRONMENT VARIABLE | Required | Example | Description | List |
---|---|---|---|---|
JAVA_TOOL_OPTIONS | -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8090 | JMV (Debugging option) | X |
A helm chart for deploying the remoting agent can be found under this folder.
It can be added to your umbrella chart.yaml by the following snippet
dependencies:
- name: remoting-agent
repository: https://catenax-ng.github.io/product-knowledge/infrastructure
version: 1.9.5-SNAPSHOT
alias: my-remoting-agent
and then installed using
helm dependency update
In your values.yml, you configure your specific instance of the remoting agent like this
##############################################################################################
# API Binding Agent
##############################################################################################
my-remoting-agent:
securityContext: *securityContext
nameOverride: my-remoting-agent
fullnameOverride: my-remoting-agent
ingresses:
- enabled: true
# -- The hostname to be used to precisely map incoming traffic onto the underlying network service
hostname: "my-remoting-agent.public-ip"
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
# -- Agent endpoints exposed by this ingress resource
endpoints:
- default
tls:
enabled: true
secretName: my-remoting-tls
repositories:
prognosis: |-
#
# Rdf4j configuration for prognosis sample
#
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix rep: <http://www.openrdf.org/config/repository#>.
@prefix sr: <http://www.openrdf.org/config/repository/sail#>.
@prefix sail: <http://www.openrdf.org/config/sail#>.
@prefix sp: <http://spinrdf.org/sp#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix json: <https://json-schema.org/draft/2020-12/schema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix cx-fx: <https://w3id.org/catenax/ontology/function#>.
@prefix prognosis: <https://w3id.org/prognosis>.
[] rdf:type rep:Repository ;
rep:repositoryID "prognosis" ;
rdfs:label "Prognosis Functions" ;
rep:repositoryImpl [
rep:repositoryType "openrdf:SailRepository" ;
sr:sailImpl [
sail:sailType "org.eclipse.tractusx.agents:Remoting" ;
cx-fx:callbackAddress <https://my-remoting-agent.public-ip/callback>;
cx-fx:supportsInvocation prognosis:Prognosis;
]
].
# Function declaration
prognosis:Prognosis rdf:type cx-fx:Function;
dcterms:description "Prognosis is a sample simulation function with input and output bindings."@en ;
dcterms:title "Prognosis" ;
cx-fx:targetUri "https://api.agify.io";
cx-common:authenticationCode "Dummy-Authorization";
cx-common:authenticationKey "Dummy-Key";
cx-fx:input prognosis:name;
cx-fx:result prognosis:hasResult.
prognosis:name rdf:type cx-fx:Argument;
dcterms:description "Name is an argument to the Prognosis function."@en ;
dcterms:title "Name";
cx-fx:argumentName "name".
prognosis:hasResult rdf:type cx-fx:Result;
cx-fx:output prognosis:prediction;
cx-fx:output prognosis:support.
prognosis:prediction rdf:type cx-fx:ReturnValue;
dcterms:description "Prediction (Value) is an integer-based output of the Prognosis function."@en ;
dcterms:title "Prediction" ;
cx-fx:valuePath "age";
cx-fx:dataType xsd:int.
prognosis:support rdf:type cx-fx:ReturnValue;
dcterms:description "Support (Value) is another integer-based output of the Prognosis function."@en ;
dcterms:title "Support" ;
cx-fx:valuePath "count";
cx-fx:dataType xsd:int.