diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index b65da824d..ec84749fe 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -14,10 +14,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - name: Set up JDK 17
+ - name: Set up JDK 25
uses: actions/setup-java@v3
with:
- java-version: '17'
+ java-version: '25'
distribution: 'temurin'
- uses: actions/checkout@v4
- name: Set up QEMU
diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml
index 4e5bcecc8..227241b4d 100644
--- a/.github/workflows/draft-release.yml
+++ b/.github/workflows/draft-release.yml
@@ -16,7 +16,7 @@ jobs:
setup:
runs-on: ubuntu-latest
container:
- image: maven:3.9.9-eclipse-temurin-17-focal
+ image: maven:3.9.14-eclipse-temurin-25
options: --user 1001
steps:
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 170a9c747..15495980c 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -21,7 +21,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
- container: maven:3.8.7-eclipse-temurin-17-alpine
+ container: maven:3.9.14-eclipse-temurin-25
steps:
- uses: actions/checkout@v4
diff --git a/admin-ui/Dockerfile b/admin-ui/Dockerfile
index 4caf48430..2fea2258b 100644
--- a/admin-ui/Dockerfile
+++ b/admin-ui/Dockerfile
@@ -1,4 +1,4 @@
-FROM eclipse-temurin:21-alpine
+FROM eclipse-temurin:25-alpine
LABEL org.opencontainers.image.source https://github.com/tno/knowledge-engine
LABEL org.opencontainers.image.description="Knowledge Engine: Admin UI"
LABEL org.opencontainers.image.licenses=Apache-2.0
diff --git a/admin-ui/pom.xml b/admin-ui/pom.xml
index cd14c5c94..81c06c90a 100644
--- a/admin-ui/pom.xml
+++ b/admin-ui/pom.xml
@@ -15,7 +15,7 @@
A user interface for managing a Knowledge Network.
- 2.2.42
+ 2.2.45
UTF-8
@@ -126,7 +126,7 @@
org.openapitools
openapi-generator-maven-plugin
- 7.18.0
+ 7.20.0
generate-sources
@@ -186,7 +186,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.6.1
+ 3.6.2
true
with-dependencies
diff --git a/admin-ui/src/main/java/eu/knowledge/engine/admin/AdminUIConfig.java b/admin-ui/src/main/java/eu/knowledge/engine/admin/AdminUIConfig.java
index 930d52bb4..471522dc0 100644
--- a/admin-ui/src/main/java/eu/knowledge/engine/admin/AdminUIConfig.java
+++ b/admin-ui/src/main/java/eu/knowledge/engine/admin/AdminUIConfig.java
@@ -3,11 +3,11 @@
public class AdminUIConfig {
/**
- * The key to configure how long (in milliseconds) should the Admin UI wait
+ * The key to configure how long (in milliseconds) should the MetadataKB wait
* until it tries to ask for all KBs in the network. This value should probably
* be higher in distributed mode, to allow the participants to reach equilibrium
* with respect to knowledge about each other.
*/
- public static final String CONF_KEY_INITIAL_ADMIN_UI_DELAY = "initial.admin.ui.delay";
+ public static final String CONF_KEY_INITIAL_METADATA_DELAY = "initial.metadata.delay";
}
diff --git a/admin-ui/src/main/java/eu/knowledge/engine/admin/MetadataKB.java b/admin-ui/src/main/java/eu/knowledge/engine/admin/MetadataKB.java
index a6316d8cc..fcad2df0e 100644
--- a/admin-ui/src/main/java/eu/knowledge/engine/admin/MetadataKB.java
+++ b/admin-ui/src/main/java/eu/knowledge/engine/admin/MetadataKB.java
@@ -105,7 +105,7 @@ public void syncKIs() {
// to receive the initial state, we do a single Ask (after sleeping for a
// specific amount of time)
try {
- Thread.sleep(ConfigProvider.getConfig().getValue(AdminUIConfig.CONF_KEY_INITIAL_ADMIN_UI_DELAY,
+ Thread.sleep(ConfigProvider.getConfig().getValue(AdminUIConfig.CONF_KEY_INITIAL_METADATA_DELAY,
Integer.class));
} catch (InterruptedException e) {
LOG.error("Initial metadata KB delay should not fail.", e);
diff --git a/admin-ui/src/main/resources/META-INF/microprofile-config.properties b/admin-ui/src/main/resources/META-INF/microprofile-config.properties
index 01929b25d..3849e889f 100644
--- a/admin-ui/src/main/resources/META-INF/microprofile-config.properties
+++ b/admin-ui/src/main/resources/META-INF/microprofile-config.properties
@@ -1 +1 @@
-initial.admin.ui.delay = 5000
\ No newline at end of file
+initial.metadata.delay = 5000
\ No newline at end of file
diff --git a/docs/docs/get-started/knowledge-base.md b/docs/docs/get-started/knowledge-base/knowledge-base.md
similarity index 77%
rename from docs/docs/get-started/knowledge-base.md
rename to docs/docs/get-started/knowledge-base/knowledge-base.md
index 1215d0609..71b34e0c5 100644
--- a/docs/docs/get-started/knowledge-base.md
+++ b/docs/docs/get-started/knowledge-base/knowledge-base.md
@@ -7,12 +7,9 @@ This page describes how to implement your own Knowledge Base given a data source
There are three approaches to implement your own Knowledge Base:
1. Java
2. REST Developer API
-3. Knowledge Mapper (based on a Python client)
+3. [Knowledge Mapper](./knowledge-mapper.md) (based on a Python client)
4. JavaScript client
-The Knowledge Mapper is a tool we have built to easily connect to several common data sources (SQL, RDF, APIs).
-If you're interested in using the Knowledge Mapper or JavaScript client, please reach out to us as they are not yet open source.
-
## Implementing your own Knowledge Interaction
When you receive a request for data via an ANSWER or REACT Knowledge Interaction, you should return the expected results, e.g. by retrieving data from an API.
diff --git a/docs/docs/get-started/knowledge-base/knowledge-mapper.md b/docs/docs/get-started/knowledge-base/knowledge-mapper.md
new file mode 100644
index 000000000..ab25e16d4
--- /dev/null
+++ b/docs/docs/get-started/knowledge-base/knowledge-mapper.md
@@ -0,0 +1,61 @@
+---
+sidebar_position: 3
+---
+# Knowledge Mapper
+The Knowledge Mapper makes it easier to connect to common data sources including SQL, SPARQL and Python classes (e.g. to connect to APIs).
+It allows your Knowledge Base to be connected to the network using a single configuration file.
+The mapper takes care of connecting to the Knowledge Network and helps in registering your Knowledge Base and Knowledge Interactions.
+
+It is openly available at https://github.com/TNO/knowledge-mapper.
+
+## What's included?
+- Software to easily connect to SQL, SPARQL and Python classes (e.g. to connect to APIs)
+- Python client to connect to a Knowledge Network
+- Web interface to initialize a Knowledge Base that loads static JSON data
+
+## How to use it
+Examples of how to use the Knowledge Mapper to a SQL/SPARQL/Python data source are available at https://github.com/TNO/knowledge-mapper/tree/main/mapper/examples.
+
+### Typical project setup
+In a project that uses the Knowledge Mapper to connect to a network, you'll typically find the following files:
+```
+my-project
+├── .gitignore
+├── Dockerfile # For easy deployment
+├── README.md
+└── config.jsonc # Configuration file
+```
+When connecting to a Python class, you'll also find either a `src/` directory or a `.py` file.
+
+The configuration file is important as it defines which Knowledge Interactions your connector provides to the network.
+
+### Configuration file
+Below you can find what such a configuration file looks like.
+Depending on whether you're connecting to SQL/SPARQL/Python, some additional variables need to be defined (see [examples](https://github.com/TNO/knowledge-mapper/tree/main/mapper/examples) for more details).
+
+```json
+{
+ // The endpoint where a knowledge engine runtime is available.
+ "knowledge_engine_endpoint": "http://tke-runtime:8280/rest",
+ "knowledge_base": {
+ // An URL representing the identity of this knowledge base
+ "id": "https://example.org/a-custom-knowledge-base",
+ // A name for this knowledge base
+ "name": "Some knowledge base",
+ // A description for this knowledge base
+ "description": "This is just an example."
+ },
+
+ // Several knowledge interaction definitions can be placed here
+ "knowledge_interactions": [
+ {
+ // The type of this knowledge interaction. If we have knowledge available that is requestable, the type should be "answer"
+ "type": "answer",
+ // The graph pattern that expresses the 'shape' of our knowledge
+ "pattern": "?tree ?height . ?tree ?name .",
+ // An optional name of this knowledge interaction
+ "name": "answer-trees-with-heights-and-names"
+ }
+ ]
+}
+```
\ No newline at end of file
diff --git a/docs/docs/reasoning.md b/docs/docs/reasoning.md
index 0ed39b506..73a74754a 100644
--- a/docs/docs/reasoning.md
+++ b/docs/docs/reasoning.md
@@ -214,7 +214,7 @@ If you set the domain knowledge via the Java or REST API multiple times, it'll o
:::
:::tip
-There are multiple reasoner levels (1-5) and utilizing domain knowledge requires at least reasoner level 2. See [SmartConnectorConfig](https://github.com/TNO/knowledge-engine/blob/master/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java#L62-L79) class for more info.
+There are multiple reasoner levels (1-5) and utilizing domain knowledge requires at least reasoner level 2. See [SmartConnectorConfig](https://github.com/TNO/knowledge-engine/blob/master/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java#L90-L106) class for more info.
:::
diff --git a/examples/java-api/.gitignore b/examples/java-api/.gitignore
deleted file mode 100644
index 279783867..000000000
--- a/examples/java-api/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-target
-/.classpath
-/.project
-/.settings/
diff --git a/examples/java-api/pom.xml b/examples/java-api/pom.xml
deleted file mode 100644
index 125c0f9b6..000000000
--- a/examples/java-api/pom.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
- 4.0.0
- examples
- jar
- Knowledge Engine - Java API Example
-
- eu.knowledge.engine
- ke-parent
- ${revision}
- ../..
-
-
- A Knowledge Base that shares power measurements of an EEBUS
- submeter.
-
-
-
- eu.knowledge.engine
- smart-connector
- ${project.version}
-
-
-
-
- org.apache.jena
- apache-jena-libs
- pom
-
-
-
- org.eclipse.paho
- org.eclipse.paho.mqttv5.client
- 1.2.5
-
-
-
- org.json
- json
- 20251224
-
-
-
-
- org.slf4j
- slf4j-simple
-
-
-
-
- org.junit.jupiter
- junit-jupiter-api
- test
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
-
-
diff --git a/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/KEODemo.java b/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/KEODemo.java
deleted file mode 100644
index bd52ca04a..000000000
--- a/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/KEODemo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package eu.knowledge.engine.examples.keo;
-
-import java.net.URISyntaxException;
-
-import org.eclipse.paho.mqttv5.common.MqttException;
-
-import eu.knowledge.engine.smartconnector.api.KnowledgeBase;
-
-public class KEODemo {
- public static void main(String[] args) throws MqttException, URISyntaxException {
- KnowledgeBase powerGateway = new PowerGateway("tcp://127.0.0.1:1883");
- KnowledgeBase powerUI = new PowerUI();
-
- // Next steps:
- // 1. Sending action (power limit) to device instead of reading events from device (communicative act validation)
- // 2. Send other simple messages such as frequency.
- // 3. More complex messages (lists, phases)
- // 4. Auto generate graph pattern from thing description
- }
-}
diff --git a/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/PowerGateway.java b/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/PowerGateway.java
deleted file mode 100644
index 4c103d93e..000000000
--- a/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/PowerGateway.java
+++ /dev/null
@@ -1,262 +0,0 @@
-package eu.knowledge.engine.examples.keo;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.UUID;
-
-import org.apache.jena.shared.PrefixMapping;
-import org.apache.jena.sparql.graph.PrefixMappingMem;
-import org.apache.jena.sparql.sse.SSE;
-import org.eclipse.paho.mqttv5.client.IMqttToken;
-import org.eclipse.paho.mqttv5.client.MqttAsyncClient;
-import org.eclipse.paho.mqttv5.client.MqttCallback;
-import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
-import org.eclipse.paho.mqttv5.client.MqttDisconnectResponse;
-import org.eclipse.paho.mqttv5.common.MqttException;
-import org.eclipse.paho.mqttv5.common.MqttMessage;
-import org.eclipse.paho.mqttv5.common.packet.MqttProperties;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import eu.knowledge.engine.smartconnector.api.Binding;
-import eu.knowledge.engine.smartconnector.api.BindingSet;
-import eu.knowledge.engine.smartconnector.api.CommunicativeAct;
-import eu.knowledge.engine.smartconnector.api.GraphPattern;
-import eu.knowledge.engine.smartconnector.api.KnowledgeBase;
-import eu.knowledge.engine.smartconnector.api.PostKnowledgeInteraction;
-import eu.knowledge.engine.smartconnector.api.ReactKnowledgeInteraction;
-import eu.knowledge.engine.smartconnector.api.SmartConnector;
-import eu.knowledge.engine.smartconnector.api.Vocab;
-import eu.knowledge.engine.smartconnector.impl.SmartConnectorBuilder;
-
-public class PowerGateway implements MqttCallback, KnowledgeBase {
- private static final Logger LOG = LoggerFactory.getLogger(PowerGateway.class);
-
- private MqttConnectionOptions mqttConnectionOptions;
- private MqttAsyncClient mqttClient;
-
- private final URI knowledgeBaseId;
- private final SmartConnector sc;
-
- private PostKnowledgeInteraction pkiPower;
- private ReactKnowledgeInteraction rkiPowerLimit;
-
- private PrefixMappingMem prefixes;
-
- private static final String SUB_TOPIC = "keo/json_api/from_eebus";
- private static final String PUB_TOPIC = "keo/json_api/to_eebus";
-
- private static final String EX_DATA = "https://www.interconnectproject.eu/knowledge-engine/data/example/keo/";
-
- public PowerGateway(String mqttURI) throws MqttException, URISyntaxException {
- this.setupMQTT(mqttURI);
- this.connectMQTT();
- this.subscribe(SUB_TOPIC);
-
- this.prefixes = new PrefixMappingMem();
- this.prefixes.setNsPrefixes(PrefixMapping.Standard);
- this.prefixes.setNsPrefix("kb", Vocab.ONTO_URI);
- this.prefixes.setNsPrefix("om", "http://www.ontology-of-units-of-measure.org/resource/om-2/");
- this.prefixes.setNsPrefix("sosa", "http://www.w3.org/ns/sosa/");
- this.prefixes.setNsPrefix("saref", "https://saref.etsi.org/core/");
- this.prefixes.setNsPrefix("interconnect", "http://ontology.tno.nl/Interconnect#");
- this.prefixes.setNsPrefix("ex-data", EX_DATA);
-
- this.knowledgeBaseId = new URI(
- "https://www.interconnectproject.eu/knowledge-engine/knowledgebase/example/power-gateway");
-
- this.sc = SmartConnectorBuilder.newSmartConnector(this).create();
- }
-
- private void setupMQTT(String mqttURI) throws MqttException {
- // Issue client ID based on thread id.
- String clientID = "mqtt-client-" + Thread.currentThread().getId();
-
- LOG.info("Setting up MQTT client with id '{}'.", clientID);
-
- this.mqttClient = new MqttAsyncClient(mqttURI, clientID, null);
- this.mqttClient.setCallback(this);
-
- this.mqttConnectionOptions = new MqttConnectionOptions();
- this.mqttConnectionOptions.setServerURIs(new String[] { mqttURI });
- }
-
- private void connectMQTT() throws MqttException {
- LOG.info("Connecting to MQTT at {}", this.mqttConnectionOptions.getServerURIs()[0]);
- IMqttToken connectToken = this.mqttClient.connect(this.mqttConnectionOptions);
- connectToken.waitForCompletion(500);
- }
-
- private void subscribe(String topic) throws MqttException {
- LOG.info("Subscribing to topic '{}'.", topic);
- IMqttToken subToken = this.mqttClient.subscribe(topic, 0);
- subToken.waitForCompletion(500);
- }
-
- @Override
- public void authPacketArrived(int reasonCode, MqttProperties properties) {
- LOG.info("AUTH PACKET ARRIVED");
- }
-
- @Override
- public void connectComplete(boolean reconnect, String serverURI) {
- LOG.info("CONNECTED");
- }
-
- @Override
- public void deliveryComplete(IMqttToken token) {
- LOG.info("DELIVERED");
- }
-
- @Override
- public void disconnected(MqttDisconnectResponse disconnectResponse) {
- LOG.warn("DISCONNECTED");
- }
-
- @Override
- public void messageArrived(String topic, MqttMessage message) throws Exception {
- LOG.info("MESSAGE ARRIVED in topic {}: {}", topic, message);
-
- var jsonObj = new JSONObject(message.toString());
-
- if (!jsonObj.getString("type").equals("de.keo-connectivity.generic.mpc.powerTotal")) {
- LOG.info("Ignoring message type '{}'", jsonObj.getString("type"));
- return;
- }
-
- String msgId = jsonObj.getString("id");
-
- int number = jsonObj.getJSONObject("data").getJSONObject("power").getInt("number");
- int scale = jsonObj.getJSONObject("data").getJSONObject("power").getInt("scale");
- String actorId = jsonObj.getJSONObject("data").getString("actorId");
- double value = number * Math.pow(10, scale);
-
- var bindings = new BindingSet();
- var binding = new Binding();
-
- binding.put("sensor", "<" + EX_DATA + "actor-" + actorId + ">");
- binding.put("observation", "<" + EX_DATA + "observation-" + msgId + ">");
- binding.put("result", "<" + EX_DATA + "result-" + msgId + ">");
- binding.put("value", "\"" + Double.toString(value) + "\"^^");
- // We record the current time. This is not necessarily the time of the
- // observation.
- binding.put("time", "\"" + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)
- + "\"^^");
-
- bindings.add(binding);
-
- LOG.info("Posting binding: {}", binding);
-
- this.sc.post(this.pkiPower, bindings);
- }
-
- @Override
- public void mqttErrorOccurred(MqttException exception) {
- LOG.error("MQTT ERROR", exception);
- }
-
- @Override
- public URI getKnowledgeBaseId() {
- return this.knowledgeBaseId;
- }
-
- @Override
- public String getKnowledgeBaseName() {
- return "InterConnect KEO demo knowledge base";
- }
-
- @Override
- public String getKnowledgeBaseDescription() {
- return "A knowledge base that publishes power measurements.";
- }
-
- @Override
- public void smartConnectorReady(SmartConnector aSC) {
- LOG.info("Smart connector ready.");
- this.pkiPower = new PostKnowledgeInteraction(
- new CommunicativeAct(),
- new GraphPattern(this.prefixes,
- "?observation rdf:type sosa:Observation .",
- "?observation sosa:madeBySensor ?sensor .",
- "?observation sosa:observedProperty saref:Power .",
- "?observation sosa:hasResult ?result .",
- "?observation sosa:resultTime ?time .",
- "?result om:hasNumericalValue ?value .",
- "?result om:hasUnit om:watt ."
- ),
- null
- );
- this.sc.register(this.pkiPower);
-
- // The following KI listens for actuation commands.
- this.rkiPowerLimit = new ReactKnowledgeInteraction(
- new CommunicativeAct(new HashSet<>(Arrays.asList(Vocab.PURPOSE)), new HashSet<>(Arrays.asList(Vocab.ACTUATION_PURPOSE))),
- new GraphPattern(this.prefixes,
- "?limit om:hasUnit om:watt .",
- "?command rdf:type saref:SetLevelCommand .",
- "?command saref:actsUpon saref:PowerLimit .",
- "?limit om:hasNumericalValue ?limitValue .",
- "?command interconnect:SetsValue ?limit ."
- ),
- null
- );
-
- // When receiving an actuation command, send it to EEBUS via the queue
- this.sc.register(this.rkiPowerLimit, (rki, aReactExchangeInfo) -> {
- var argument = aReactExchangeInfo.getArgumentBindings();
- try {
- var b = argument.iterator().next();
- var limit = (Float) SSE.parseNode(b.get("limitValue")).getLiteralValue();
- LOG.info("Setting limit at {}", limit);
- this.sendPowerLimitMessage(Math.round(limit * 100), -2, 5);
- } catch (MqttException e) {
- LOG.error("Could not send message to MQTT.", e);
- }
- return new BindingSet();
- });
- }
-
- @Override
- public void smartConnectorConnectionLost(SmartConnector aSC) {
- LOG.warn("Connection lost with smart connector.");
- }
-
- @Override
- public void smartConnectorConnectionRestored(SmartConnector aSC) {
- LOG.info("Connection with smart connector restored.");
- }
-
- @Override
- public void smartConnectorStopped(SmartConnector aSC) {
- LOG.info("Smart connector stopped.");
- }
-
- private void sendPowerLimitMessage(int number, int scale, int ttl) throws MqttException {
- // Send a message back saying we want to limit the power.
- var msg = new JSONObject();
- msg.put("type", "de.keo-connectivity.generic.lpc.powerLimit");
- msg.put("source", "PowerGateway Knowledge Base");
- msg.put("id", UUID.randomUUID().toString());
- msg.put("specversion", "1.0");
- var data = new JSONObject();
- data.put("actorId", "d:_n:KEO_json_grid_server/1/");
- var limit = new JSONObject();
- var limitValue = new JSONObject();
- limitValue.put("number", number);
- limitValue.put("scale", scale);
- limit.put("value", limitValue);
- limit.put("active", true);
- limit.put("ttl", ttl);
- data.put("limit", limit);
- msg.put("data", data);
-
- this.mqttClient.publish(PUB_TOPIC, msg.toString().getBytes(StandardCharsets.UTF_8), 0, false);
- }
-}
diff --git a/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/PowerUI.java b/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/PowerUI.java
deleted file mode 100644
index 7bad18218..000000000
--- a/examples/java-api/src/main/java/eu/knowledge/engine/examples/keo/PowerUI.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package eu.knowledge.engine.examples.keo;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.HashSet;
-
-import org.apache.jena.shared.PrefixMapping;
-import org.apache.jena.sparql.graph.PrefixMappingMem;
-import org.apache.jena.sparql.sse.SSE;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import eu.knowledge.engine.smartconnector.api.Binding;
-import eu.knowledge.engine.smartconnector.api.BindingSet;
-import eu.knowledge.engine.smartconnector.api.CommunicativeAct;
-import eu.knowledge.engine.smartconnector.api.GraphPattern;
-import eu.knowledge.engine.smartconnector.api.KnowledgeBase;
-import eu.knowledge.engine.smartconnector.api.PostKnowledgeInteraction;
-import eu.knowledge.engine.smartconnector.api.ReactKnowledgeInteraction;
-import eu.knowledge.engine.smartconnector.api.SmartConnector;
-import eu.knowledge.engine.smartconnector.api.Vocab;
-import eu.knowledge.engine.smartconnector.impl.SmartConnectorBuilder;
-
-public class PowerUI implements KnowledgeBase {
- private static final Logger LOG = LoggerFactory.getLogger(PowerUI.class);
-
- private PrefixMappingMem prefixes;
- private URI knowledgeBaseId;
-
- private ReactKnowledgeInteraction rkiPower;
- private PostKnowledgeInteraction pkiPowerLimit;
-
- private SmartConnector sc;
-
- private static final String EX_DATA = "https://www.interconnectproject.eu/knowledge-engine/data/example/keo/";
-
- public PowerUI() throws URISyntaxException {
- this.prefixes = new PrefixMappingMem();
- this.prefixes.setNsPrefixes(PrefixMapping.Standard);
- this.prefixes.setNsPrefix("kb", Vocab.ONTO_URI);
- this.prefixes.setNsPrefix("om", "http://www.ontology-of-units-of-measure.org/resource/om-2/");
- this.prefixes.setNsPrefix("sosa", "http://www.w3.org/ns/sosa/");
- this.prefixes.setNsPrefix("saref", "https://saref.etsi.org/core/");
- this.prefixes.setNsPrefix("interconnect", "http://ontology.tno.nl/Interconnect#");
- this.prefixes.setNsPrefix("ex-data", EX_DATA);
-
- this.knowledgeBaseId = new URI(
- "https://www.interconnectproject.eu/knowledge-engine/knowledgebase/example/power-ui");
-
- this.sc = SmartConnectorBuilder.newSmartConnector(this).create();
- }
-
- @Override
- public URI getKnowledgeBaseId() {
- return this.knowledgeBaseId;
- }
-
- @Override
- public String getKnowledgeBaseName() {
- return "Epic Power Visualization Knowledge Base";
- }
-
- @Override
- public String getKnowledgeBaseDescription() {
- return "This knowledge base visualizes power measurements in an epic manner.";
- }
-
- @Override
- public void smartConnectorReady(SmartConnector aSC) {
- LOG.info("Smart connector ready.");
-
- // This KI listens for power measurements published on the network.
- this.rkiPower = new ReactKnowledgeInteraction(new CommunicativeAct(),
- new GraphPattern(this.prefixes, "?observation rdf:type sosa:Observation .",
- "?observation sosa:madeBySensor ?sensor .", "?observation sosa:observedProperty saref:Power .",
- "?observation sosa:hasResult ?result .", "?observation sosa:resultTime ?time .",
- "?result om:hasNumericalValue ?value .", "?result om:hasUnit om:watt ."),
- null
- );
-
- // When receiving such a power measurement, do some business logic and post
- // a power limit to the network.
- this.sc.register(this.rkiPower, (rki, aReactExchangeInfo) -> {
- var bindings = aReactExchangeInfo.getArgumentBindings();
- var binding = bindings.iterator().next();
- var value = binding.get("value");
-
- var n = (Float) SSE.parseNode(value).getLiteralValue();
- LOG.info("The power was {} at {}", n, binding.get("time"));
-
- BindingSet newBindings = new BindingSet();
- Binding powerLimitBinding = new Binding();
-
- // TODO: These should be unique.
- powerLimitBinding.put("limit", "");
- powerLimitBinding.put("command", "");
-
- if (n > 500) {
- powerLimitBinding.put("limitValue", "\"500\"^^");
- } else {
- powerLimitBinding.put("limitValue", "\"100\"^^");
- }
- newBindings.add(powerLimitBinding);
-
- this.sc.post(this.pkiPowerLimit, newBindings);
-
- return new BindingSet();
- });
-
- // This KI allows to post power limit commands (actuations).
- this.pkiPowerLimit = new PostKnowledgeInteraction(
- new CommunicativeAct(new HashSet<>(Arrays.asList(Vocab.ACTUATION_PURPOSE)), new HashSet<>(Arrays.asList(Vocab.PURPOSE))),
- new GraphPattern(this.prefixes,
- "?limit om:hasUnit om:watt .",
- "?command rdf:type saref:SetLevelCommand .",
- "?command saref:actsUpon saref:PowerLimit .",
- "?limit om:hasNumericalValue ?limitValue .",
- "?command interconnect:SetsValue ?limit ."
- ),
- null
- );
- this.sc.register(this.pkiPowerLimit);
- }
-
- @Override
- public void smartConnectorConnectionLost(SmartConnector aSC) {
- LOG.warn("Connection lost with smart connector.");
- }
-
- @Override
- public void smartConnectorConnectionRestored(SmartConnector aSC) {
- LOG.info("Connection with smart connector restored.");
- }
-
- @Override
- public void smartConnectorStopped(SmartConnector aSC) {
- LOG.info("Smart connector stopped.");
- }
-}
diff --git a/knowledge-directory/Dockerfile b/knowledge-directory/Dockerfile
index b507e577c..29f86b2a0 100644
--- a/knowledge-directory/Dockerfile
+++ b/knowledge-directory/Dockerfile
@@ -1,4 +1,4 @@
-FROM eclipse-temurin:21-alpine
+FROM eclipse-temurin:25-alpine
LABEL org.opencontainers.image.source https://github.com/tno/knowledge-engine
LABEL org.opencontainers.image.description="Knowledge Engine: Knowledge Directory"
LABEL org.opencontainers.image.licenses=Apache-2.0
diff --git a/knowledge-directory/pom.xml b/knowledge-directory/pom.xml
index 0f7bf699e..10ed6b594 100644
--- a/knowledge-directory/pom.xml
+++ b/knowledge-directory/pom.xml
@@ -14,7 +14,7 @@
- 2.2.42
+ 2.2.45
3.1.1
UTF-8
@@ -79,7 +79,7 @@
com.fasterxml.jackson.core
jackson-annotations
- 2.20
+ 2.21
com.fasterxml.jackson.datatype
@@ -137,7 +137,7 @@
org.openapitools
openapi-generator-maven-plugin
- 7.18.0
+ 7.20.0
generate-sources
@@ -192,7 +192,7 @@
org.apache.maven.plugins
maven-dependency-plugin
- 3.9.0
+ 3.10.0
install
@@ -211,7 +211,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.6.1
+ 3.6.2
true
with-dependencies
diff --git a/pom.xml b/pom.xml
index 3586fd6ea..4fc497556 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,6 @@
smart-connector
admin-ui
- examples/java-api
knowledge-directory
smart-connector-rest-server
smart-connector-api
@@ -25,7 +24,7 @@
maven-surefire-plugin
- 3.5.4
+ 3.5.5
org.codehaus.mojo
@@ -75,10 +74,10 @@
11.0.26
17
3.1.11
- 2.20.1
- 6.0.1
- 17
- 17
+ 2.20.2
+ 6.0.3
+ 25
+ 25
1.4.1-SNAPSHOT
@@ -123,6 +122,11 @@
jersey-container-servlet
${jersey3-version}
+
+ org.glassfish.jersey.ext
+ jersey-bean-validation
+ ${jersey3-version}
+
com.fasterxml.jackson.datatype
@@ -155,7 +159,7 @@
org.apache.jena
apache-jena-libs
- 5.6.0
+ 6.0.0
pom
diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveAntRuleNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveAntRuleNode.java
index 42c3cdd30..75ec2b4e0 100644
--- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveAntRuleNode.java
+++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveAntRuleNode.java
@@ -1,7 +1,6 @@
package eu.knowledge.engine.reasoner.rulenode;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import eu.knowledge.engine.reasoner.BaseRule;
diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveConsRuleNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveConsRuleNode.java
index d9665f01c..b620ff529 100644
--- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveConsRuleNode.java
+++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ActiveConsRuleNode.java
@@ -1,7 +1,5 @@
package eu.knowledge.engine.reasoner.rulenode;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import eu.knowledge.engine.reasoner.BaseRule;
diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/AntRuleNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/AntRuleNode.java
index 9caf4a89e..60efeebe2 100644
--- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/AntRuleNode.java
+++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/AntRuleNode.java
@@ -4,7 +4,6 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
import eu.knowledge.engine.reasoner.AntSide;
import eu.knowledge.engine.reasoner.BaseRule;
diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ConsRuleNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ConsRuleNode.java
index 329902e1c..2a51d473f 100644
--- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ConsRuleNode.java
+++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulenode/ConsRuleNode.java
@@ -4,7 +4,6 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
import eu.knowledge.engine.reasoner.BaseRule;
import eu.knowledge.engine.reasoner.BaseRule.CombiMatch;
diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java
index ecaa40850..c5bed6e07 100644
--- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java
+++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/MatchNode.java
@@ -1,7 +1,6 @@
package eu.knowledge.engine.reasoner.rulestore;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
diff --git a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java
index 483465ac7..728279885 100644
--- a/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java
+++ b/reasoner/src/main/java/eu/knowledge/engine/reasoner/rulestore/RuleStore.java
@@ -6,7 +6,6 @@
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.EnumSet;
import java.util.HashMap;
@@ -349,34 +348,9 @@ private String generateName(BaseRule r) {
}
String consequent = trimAtLength(sb.toString(), MAX_STR_LENGTH);
-
- String name = r.getName();
- MessageDigest digest;
- String encodedhash = "unknown";
- try {
- digest = MessageDigest.getInstance("SHA-256");
-
-// encodedhash = digest.digest(name.getBytes(StandardCharsets.UTF_8));
- encodedhash = Integer.toHexString(System.identityHashCode(r));
- } catch (NoSuchAlgorithmException e) {
- LOG.error("{}", e);
- }
- // bytesToHex(...)
return "\"" + antecedent + "→\\n" + consequent + "\"";
}
- private static String bytesToHex(byte[] hash) {
- StringBuilder hexString = new StringBuilder(2 * hash.length);
- for (int i = 0; i < hash.length; i++) {
- String hex = Integer.toHexString(0xff & hash[i]);
- if (hex.length() == 1) {
- hexString.append('0');
- }
- hexString.append(hex);
- }
- return hexString.toString();
- }
-
private String generateName(TriplePattern tp) {
String name = BaseRule.EMPTY;
diff --git a/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaTest.java b/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaTest.java
index 7e65e8bee..e15077b97 100644
--- a/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaTest.java
+++ b/reasoner/src/test/java/eu/knowledge/engine/reasoner/JenaTest.java
@@ -12,7 +12,7 @@ public class JenaTest {
public void testFloatsAndDecimals() {
Node_Literal node1 = (Node_Literal) SSE.parseNode("\"12\"^^xsd:float");
Node_Literal node2 = (Node_Literal) SSE.parseNode("\"12\"^^xsd:decimal");
- assertFalse(node1.matches(node2));
+ assertFalse(node1.sameValueAs(node2));
assertNotEquals(node1, node2);
}
}
diff --git a/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java b/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java
index f7ded2fd0..5f066917f 100644
--- a/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java
+++ b/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java
@@ -16,16 +16,6 @@ public class SmartConnectorConfig {
*/
public static final String CONF_KEY_VALIDATE_OUTGOING_BINDINGS_WRT_INCOMING_BINDINGS = "sc.validate.outgoing.bindings.wrt.incoming.bindings";
- /**
- * Key to configure the hostname of the machine this Knowledge Engine Runtime
- * (KER) runs on.
- *
- * @deprecated Replaced by
- * {@link SmartConnectorConfig#CONF_KEY_KE_RUNTIME_EXPOSED_URL}
- */
- @Deprecated
- public static final String CONF_KEY_KE_RUNTIME_HOSTNAME = "ke.runtime.hostname";
-
/**
* Key to configure the URL of the Knowledge Directory where this KER can find
* other KERs in the network. Note that overriding this configuration property
@@ -65,11 +55,11 @@ public class SmartConnectorConfig {
public static final String CONF_KEY_KE_RUNTIME_USE_EDC = "ke.runtime.use.edc";
/**
- * Key to configure the EDC participant ID for this KER, matching the participant ID
- * of its control plane and identity hub.
+ * Key to configure the EDC participant ID for this KER, matching the
+ * participant ID of its control plane and identity hub.
*/
public static final String CONF_KEY_KE_EDC_PARTICIPANT_ID = "ke.edc.participant.id";
-
+
/**
* Key to configure where a KER can reach the protocol API of its own control
* plane if using EDC.
@@ -83,7 +73,8 @@ public class SmartConnectorConfig {
public static final String CONF_KEY_KE_EDC_MANAGEMENT_URL = "ke.edc.management.url";
/**
- * Key to configure where a KER can reach its data plane public API if using EDC.
+ * Key to configure where a KER can reach its data plane public API if using
+ * EDC.
*/
public static final String CONF_KEY_KE_EDC_DATAPLANE_PUBLIC_URL = "ke.edc.dataplane.public.url";
diff --git a/smart-connector-rest-dist/Dockerfile b/smart-connector-rest-dist/Dockerfile
index bca11501e..38fe314d2 100644
--- a/smart-connector-rest-dist/Dockerfile
+++ b/smart-connector-rest-dist/Dockerfile
@@ -1,4 +1,4 @@
-FROM eclipse-temurin:21-alpine
+FROM eclipse-temurin:25-alpine
LABEL org.opencontainers.image.source https://github.com/tno/knowledge-engine
LABEL org.opencontainers.image.description="Knowledge Engine: Smart Connector (with HTTP API)"
LABEL org.opencontainers.image.licenses=Apache-2.0
diff --git a/smart-connector-rest-dist/pom.xml b/smart-connector-rest-dist/pom.xml
index 21a4bd473..260a47575 100644
--- a/smart-connector-rest-dist/pom.xml
+++ b/smart-connector-rest-dist/pom.xml
@@ -51,7 +51,7 @@
org.apache.maven.plugins
maven-dependency-plugin
- 3.9.0
+ 3.10.0
install
@@ -71,7 +71,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.6.1
+ 3.6.2
true
with-dependencies
diff --git a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestScLifeCycle.java b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestScLifeCycle.java
index 99db41939..50043d866 100644
--- a/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestScLifeCycle.java
+++ b/smart-connector-rest-dist/src/test/java/eu/knowledge/engine/rest/api/TestScLifeCycle.java
@@ -1,6 +1,9 @@
package eu.knowledge.engine.rest.api;
import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
@@ -8,6 +11,7 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
+import org.slf4j.helpers.MessageFormatter;
import eu.knowledge.engine.rest.RestServerHelper;
import eu.knowledge.engine.test_utils.HttpTester;
@@ -17,14 +21,31 @@ public class TestScLifeCycle {
private final RestServerHelper rsh = new RestServerHelper();
private static int PORT = 8280;
+ private String[] validKbIds = new String[] {
+ //@formatter:off
+ "https://asdlkasld.com",
+ "mailto:hello",
+ "https://hello",
+ //@formatter:on
+ };
+
+ private String[] invalidKbIds = new String[] {
+ //@formatter:off
+ "",
+ "https://",
+ "strange characters and spaces | & ^",
+ "/relative.nl"
+ //@formatter:on
+ };
+
@BeforeAll
public void setUpServer() {
rsh.start(PORT);
}
@Test
- public void testInvalidJson() throws IOException {
- URL url = new URL("http://localhost:" + PORT + "/rest/sc");
+ public void testInvalidJson() throws IOException, URISyntaxException {
+ URL url = new URI("http://localhost:" + PORT + "/rest/sc").toURL();
HttpTester httpTest = new HttpTester(url, "POST", "{\"bla\"{}",
Map.of("Content-Type", "application/json", "Accept", "*/*"));
@@ -32,8 +53,8 @@ public void testInvalidJson() throws IOException {
}
@Test
- public void testValidJson() throws IOException {
- URL url = new URL("http://localhost:" + PORT + "/rest/sc");
+ public void testValidJson() throws IOException, URISyntaxException {
+ URL url = new URI("http://localhost:" + PORT + "/rest/sc").toURL();
HttpTester httpTest = new HttpTester(url, "POST",
"{\"knowledgeBaseId\": \"http://example.com/kb\", \"knowledgeBaseName\": \"KB\", \"knowledgeBaseDescription\": \"KB\"}",
@@ -41,6 +62,33 @@ public void testValidJson() throws IOException {
httpTest.expectStatus(200);
}
+ @Test
+ public void testKnowledgeBaseIdsValidity() throws MalformedURLException, URISyntaxException {
+ URL url = new URI("http://localhost:" + PORT + "/rest/sc").toURL();
+
+ String template = """
+ {
+ \"knowledgeBaseId\": \"{}\",
+ \"knowledgeBaseName\": \"KB\",
+ \"knowledgeBaseDescription\": \"KB\"
+ }
+ """;
+
+ for (String kbId : this.validKbIds) {
+ String jsonBody = MessageFormatter.format(template, kbId).getMessage();
+ HttpTester httpTest = new HttpTester(url, "POST", jsonBody,
+ Map.of("Content-Type", "application/json", "Accept", "*/*"));
+ httpTest.expectStatus(200);
+ }
+
+ for (String kbId : this.invalidKbIds) {
+ String jsonBody = MessageFormatter.format(template, kbId).getMessage();
+ HttpTester httpTest = new HttpTester(url, "POST", jsonBody,
+ Map.of("Content-Type", "application/json", "Accept", "*/*"));
+ httpTest.expectStatus(400);
+ }
+ }
+
@AfterAll
public void cleanUp() {
TestUtil.unregisterAllKBs("http://localhost:" + PORT + "/rest");
diff --git a/smart-connector-rest-server/pom.xml b/smart-connector-rest-server/pom.xml
index 5e0686d20..f4d853f08 100644
--- a/smart-connector-rest-server/pom.xml
+++ b/smart-connector-rest-server/pom.xml
@@ -11,7 +11,7 @@
- 2.2.42
+ 2.2.45
UTF-8
@@ -70,6 +70,10 @@
org.glassfish.jersey.containers
jersey-container-servlet
+
+ org.glassfish.jersey.ext
+ jersey-bean-validation
+
@@ -125,7 +129,7 @@
org.apache.maven
maven-model
- 3.9.12
+ 3.9.14
@@ -134,7 +138,7 @@
org.openapitools
openapi-generator-maven-plugin
- 7.18.0
+ 7.20.0
generate-sources
diff --git a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/JsonExceptionMapper.java b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/JsonExceptionMapper.java
index c9604e922..205d00b59 100644
--- a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/JsonExceptionMapper.java
+++ b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/JsonExceptionMapper.java
@@ -1,12 +1,13 @@
package eu.knowledge.engine.rest.api;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import eu.knowledge.engine.rest.model.ResponseMessage;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
-import com.fasterxml.jackson.core.JsonProcessingException;
-
/**
* Since apparently Jersey gives a status 500 response when it encounters
* unexpected input in request bodies, this exception mapper maps those
@@ -16,10 +17,11 @@
public class JsonExceptionMapper implements ExceptionMapper {
@Override
public Response toResponse(JsonProcessingException exception) {
- return Response
- .status(Response.Status.BAD_REQUEST)
- .entity(exception.getOriginalMessage())
- .type(MediaType.TEXT_PLAIN)
- .build();
+
+ var response = new ResponseMessage();
+ response.setMessageType("error");
+ response.setMessage(exception.getClass().getSimpleName() + ": " + exception.getOriginalMessage());
+
+ return Response.status(Response.Status.BAD_REQUEST).entity(response).type(MediaType.APPLICATION_JSON).build();
}
}
diff --git a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/RestServer.java b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/RestServer.java
index 66e294dc4..209ca73ea 100644
--- a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/RestServer.java
+++ b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/RestServer.java
@@ -1,7 +1,5 @@
package eu.knowledge.engine.rest.api;
-import java.net.InetSocketAddress;
-
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
diff --git a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/ValidationExceptionMapper.java b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/ValidationExceptionMapper.java
new file mode 100644
index 000000000..93da1f7c2
--- /dev/null
+++ b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/ValidationExceptionMapper.java
@@ -0,0 +1,34 @@
+package eu.knowledge.engine.rest.api;
+
+import eu.knowledge.engine.rest.model.ResponseMessage;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.ext.Provider;
+
+/**
+ * Validation errors by default are returned as plain text and this class maps
+ * those errors to our {@link ResponseMessage}.
+ */
+@Provider
+public class ValidationExceptionMapper implements ExceptionMapper {
+ @Override
+ public Response toResponse(ConstraintViolationException exception) {
+
+ var response = new ResponseMessage();
+ response.setMessageType("error");
+ response.setMessage(exception.getClass().getSimpleName() + ": " + prepareMessage(exception));
+
+ return Response.status(Response.Status.BAD_REQUEST).entity(response).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ private String prepareMessage(ConstraintViolationException exception) {
+ StringBuilder message = new StringBuilder();
+ for (ConstraintViolation> cv : exception.getConstraintViolations()) {
+ message.append(cv.getPropertyPath() + " " + cv.getMessage() + "\n ");
+ }
+ return message.toString();
+ }
+}
diff --git a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/ProactiveApiServiceImpl.java b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/ProactiveApiServiceImpl.java
index 0d00c2ada..d15927882 100644
--- a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/ProactiveApiServiceImpl.java
+++ b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/ProactiveApiServiceImpl.java
@@ -18,7 +18,6 @@
import com.fasterxml.jackson.databind.JsonNode;
-import eu.knowledge.engine.rest.api.NotFoundException;
import eu.knowledge.engine.rest.model.AskExchangeInfo;
import eu.knowledge.engine.rest.model.AskResult;
import eu.knowledge.engine.rest.model.KnowledgeInteractionWithId;
@@ -151,14 +150,16 @@ public void scAskPost(
LOG.debug("Bindings in result is {}", askResult.getBindings());
LOG.debug("KnowledgeGapsEnabled is {}", ki.getKnowledgeGapsEnabled());
-
- AskResult ar = new AskResult().bindingSet(this.bindingSetToList(askResult.getBindings())).exchangeInfo(infos);
- // distinguish between knowledge gaps enabled or not to produce an AskResult or an AskResultWithGaps
+
+ AskResult ar = new AskResult().bindingSet(this.bindingSetToList(askResult.getBindings()))
+ .exchangeInfo(infos);
+ // distinguish between knowledge gaps enabled or not to produce an AskResult or
+ // an AskResultWithGaps
if (ki.getKnowledgeGapsEnabled()) {
LOG.info("Knowledge gaps in result is {}", askResult.getKnowledgeGaps());
- ar.knowledgeGaps(this.knowledgeGapsToList(askResult.getKnowledgeGaps()));
+ ar.knowledgeGaps(this.knowledgeGapsToList(askResult.getKnowledgeGaps()));
}
- asyncResponse.resume(Response.status(Status.OK).entity(ar).build());
+ asyncResponse.resume(Response.status(Status.OK).entity(ar).build());
});
} catch (URISyntaxException | InterruptedException | ExecutionException e) {
@@ -173,6 +174,13 @@ public void scAskPost(
response.setMessageType("error");
response.setMessage(e.getMessage());
asyncResponse.resume(Response.status(Status.BAD_REQUEST).entity(response).build());
+ } catch (IllegalStateException e) {
+ // triggered when, for example, the SC was stopped before the KI is activated.
+ LOG.trace("{}", e);
+ var response = new ResponseMessage();
+ response.setMessageType("error");
+ response.setMessage(e.getMessage());
+ asyncResponse.resume(Response.status(Status.GONE).entity(response).build());
}
}
@@ -221,8 +229,7 @@ public void scPostPost(
@Parameter(description = "The Knowledge Base Id for which to execute the ask.", required = true) @HeaderParam("Knowledge-Base-Id") String knowledgeBaseId,
@Parameter(description = "The Post Knowledge Interaction Id to execute.", required = true) @HeaderParam("Knowledge-Interaction-Id") String knowledgeInteractionId,
@Parameter(description = "The keys bindings must be complete, and they must correspond to the binding keys that were defined in the knowledge interaction.", required = true) @NotNull @Valid JsonNode recipientAndBindingSet,
- @Suspended final AsyncResponse asyncResponse, @Context SecurityContext securityContext)
- throws NotFoundException {
+ @Suspended final AsyncResponse asyncResponse, @Context SecurityContext securityContext) {
LOG.debug("scPostPost called for KB {} and KI {} - {}", knowledgeBaseId, knowledgeInteractionId,
recipientAndBindingSet);
@@ -334,6 +341,13 @@ public void scPostPost(
response.setMessageType("error");
response.setMessage(e.getMessage());
asyncResponse.resume(Response.status(Status.BAD_REQUEST).entity(response).build());
+ } catch (IllegalStateException e) {
+ // triggered when, for example, the SC has stopped before the KI is activated.
+ LOG.trace("{}", e);
+ var response = new ResponseMessage();
+ response.setMessageType("error");
+ response.setMessage(e.getMessage());
+ asyncResponse.resume(Response.status(Status.GONE).entity(response).build());
}
}
}
diff --git a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/RestKnowledgeBase.java b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/RestKnowledgeBase.java
index be5955227..a78bddf2b 100644
--- a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/RestKnowledgeBase.java
+++ b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/RestKnowledgeBase.java
@@ -773,7 +773,7 @@ private void cancelAndClearAllHandleRequests() {
this.toBeProcessedHandleRequests.forEach(hr -> {
hr.getFuture().completeExceptionally(new CancellationException(cancelMessage));
});
- this.beingProcessedHandleRequests.forEach((id, hr) -> {
+ this.beingProcessedHandleRequests.forEach((_, hr) -> {
hr.getFuture().completeExceptionally(new CancellationException(cancelMessage));
});
diff --git a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/SmartConnectorLifeCycleApiServiceImpl.java b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/SmartConnectorLifeCycleApiServiceImpl.java
index 13f1747ca..6530b9f8b 100644
--- a/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/SmartConnectorLifeCycleApiServiceImpl.java
+++ b/smart-connector-rest-server/src/main/java/eu/knowledge/engine/rest/api/impl/SmartConnectorLifeCycleApiServiceImpl.java
@@ -1,15 +1,11 @@
package eu.knowledge.engine.rest.api.impl;
-import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.URL;
import java.util.HashSet;
import java.util.Set;
-import org.apache.jena.irix.IRIException;
-import org.apache.jena.irix.IRIProvider;
-import org.apache.jena.irix.IRIProviderJenaIRI;
+import org.apache.jena.irix.IRIs;
import org.apache.jena.reasoner.rulesys.Rule.ParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,8 +42,6 @@ public class SmartConnectorLifeCycleApiServiceImpl {
private RestKnowledgeBaseManager manager = RestKnowledgeBaseManager.newInstance();
- private final IRIProvider iriProvider = new IRIProviderJenaIRI();
-
@GET
@Produces({ "application/json; charset=UTF-8" })
@Operation(summary = "Either get all available Smart Connectors or a specific one if the Knowledge-Base-Id is provided.", description = "", tags = {
@@ -108,27 +102,17 @@ public void scPost(@Parameter(description = "", required = true) @NotNull @Valid
return;
}
- try {
- new URL(smartConnector.getKnowledgeBaseId()).toURI();
- } catch (MalformedURLException | URISyntaxException e) {
- var response = new ResponseMessage();
- response.setMessageType("error");
- response.setMessage("Knowledge base ID must be a valid URI.");
- asyncResponse.resume(Response.status(400).entity(response).build());
- return;
- }
-
URI kbId;
try {
- // Additional check to verify that it is a valid IRI according to Jena.
- // (java.net.URI is not strict enough.)
- iriProvider.check(smartConnector.getKnowledgeBaseId());
-
kbId = new URI(smartConnector.getKnowledgeBaseId());
- } catch (URISyntaxException | IRIException e) {
+
+ // additional check using Apache Jena API, because URI spec is not strict enough
+ if (!IRIs.check(smartConnector.getKnowledgeBaseId()))
+ throw new URISyntaxException(smartConnector.getKnowledgeBaseId(), "Not a valid RDF IRI");
+ } catch (URISyntaxException e) {
var response = new ResponseMessage();
response.setMessageType("error");
- response.setMessage("Knowledge base ID must be a valid IRI.");
+ response.setMessage("Knowledge base ID must be a valid RDF IRI. " + e.getMessage());
asyncResponse.resume(Response.status(400).entity(response).build());
return;
}
@@ -189,9 +173,7 @@ public void scDelete(
return;
}
- try {
- new URI(knowledgeBaseId);
- } catch (URISyntaxException e) {
+ if (!IRIs.check(knowledgeBaseId)) {
var response = new ResponseMessage();
response.setMessageType("error");
response.setMessage("Knowledge base not found, because its ID must be a valid URI.");
@@ -244,9 +226,7 @@ public Response scKnowledgePost(
return Response.status(Status.BAD_REQUEST).entity(response).build();
}
- try {
- new URI(knowledgeBaseId);
- } catch (URISyntaxException e) {
+ if (!IRIs.check(knowledgeBaseId)) {
var response = new ResponseMessage();
response.setMessageType("error");
response.setMessage("Knowledge base not found, because its knowledge base ID must be a valid URI.");
diff --git a/smart-connector-rest-server/src/main/resources/openapi-sc.yaml b/smart-connector-rest-server/src/main/resources/openapi-sc.yaml
index f2fc8c1a4..e4e1c1fc8 100644
--- a/smart-connector-rest-server/src/main/resources/openapi-sc.yaml
+++ b/smart-connector-rest-server/src/main/resources/openapi-sc.yaml
@@ -1,6 +1,6 @@
openapi: "3.0.0"
info:
- title: Knowledge Engine REST Developer API
+ title: Knowledge Base REST Developer API
description:
This API describes how Smart Connectors are instantiated, Knowledge
diff --git a/smart-connector/pom.xml b/smart-connector/pom.xml
index 9a20d277b..7a3433594 100644
--- a/smart-connector/pom.xml
+++ b/smart-connector/pom.xml
@@ -46,13 +46,13 @@
org.mockito
mockito-core
- 5.21.0
+ 5.23.0
test
org.mockito
mockito-junit-jupiter
- 5.21.0
+ 5.23.0
test
@@ -129,7 +129,7 @@
com.fasterxml.jackson.core
jackson-annotations
- 2.20
+ 2.21
com.fasterxml.jackson.datatype
@@ -215,7 +215,7 @@
- 2.2.42
+ 2.2.45
6.1.0
3.1
@@ -225,7 +225,7 @@
org.openapitools
openapi-generator-maven-plugin
- 7.18.0
+ 7.20.0
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/InteractionProcessorImpl.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/InteractionProcessorImpl.java
index 6e98061f1..c2e96aa65 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/InteractionProcessorImpl.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/InteractionProcessorImpl.java
@@ -175,7 +175,7 @@ private Set filterOtherKnowledgeBases(Set processAskFromMessageRouter(AskMessage a
AnswerMessage m = new AnswerMessage(anAskMsg.getToKnowledgeBase(), anAskMsg.getToKnowledgeInteraction(),
anAskMsg.getFromKnowledgeBase(), anAskMsg.getFromKnowledgeInteraction(), anAskMsg.getMessageId(),
"Received AskMessage wth unknown ToKnowledgeInteractionId");
- LOG.debug("Received AskMessage with unknown ToKnowledgeInteractionId: "
+ LOG.trace("Received AskMessage with unknown ToKnowledgeInteractionId: "
+ anAskMsg.getToKnowledgeInteraction().toString());
CompletableFuture f = new CompletableFuture<>();
f.complete(m);
@@ -243,7 +243,7 @@ public CompletableFuture processAskFromMessageRouter(AskMessage a
// TODO This should happen in the single thread for the knowledge base
if (answerKnowledgeInteraction.isMeta()) {
- LOG.debug("Contacting my KB to answer KI <{}>", answerKnowledgeInteractionId);
+ LOG.trace("Contacting my KB to answer KI <{}>", answerKnowledgeInteractionId);
} else {
LOG.info("Contacting my KB to answer KI <{}>", answerKnowledgeInteractionId);
}
@@ -255,7 +255,13 @@ public CompletableFuture processAskFromMessageRouter(AskMessage a
return future.handle((b, e) -> {
if (b != null && e == null) {
- LOG.debug("Received ANSWER from KB for KI <{}>: {}", answerKnowledgeInteractionId, b);
+
+ String logStatement = "Received {} binding(s) as answer from my KB for KI <{}>";
+ if (!answerKnowledgeInteraction.isMeta())
+ LOG.debug(logStatement, b.size(), answerKnowledgeInteractionId);
+ else
+ LOG.trace(logStatement, b.size(), answerKnowledgeInteractionId);
+
BindingSet translatedB = Util.translateFromApiBindingSet(b);
if (this.shouldValidateInputOutputBindings()) {
@@ -280,7 +286,7 @@ public CompletableFuture processAskFromMessageRouter(AskMessage a
}
}).exceptionally((e) -> {
LOG.error("An error occurred while answering a msg: ", e);
- LOG.debug("The error occured while answering this message: {}", anAskMsg);
+ LOG.trace("The error occured while answering this message: {}", anAskMsg);
return new AnswerMessage(anAskMsg.getToKnowledgeBase(), answerKnowledgeInteractionId,
anAskMsg.getFromKnowledgeBase(), anAskMsg.getFromKnowledgeInteraction(), anAskMsg.getMessageId(),
e.getMessage());
@@ -340,7 +346,7 @@ public CompletableFuture processPostFromMessageRouter(PostMessage
ReactMessage m = new ReactMessage(aPostMsg.getToKnowledgeBase(), aPostMsg.getToKnowledgeInteraction(),
aPostMsg.getFromKnowledgeBase(), aPostMsg.getFromKnowledgeInteraction(), aPostMsg.getMessageId(),
"Received PostMessage with unknown ToKnowledgeInteractionId");
- LOG.debug("Received PostMessage with unknown ToKnowledgeInteractionId: "
+ LOG.trace("Received PostMessage with unknown ToKnowledgeInteractionId: "
+ aPostMsg.getToKnowledgeInteraction().toString());
CompletableFuture f = new CompletableFuture<>();
f.complete(m);
@@ -358,7 +364,7 @@ public CompletableFuture processPostFromMessageRouter(PostMessage
// TODO This should happen in the single thread for the knowledge base
if (reactKnowledgeInteraction.isMeta()) {
- LOG.debug("Contacting my KB to react to KI <{}>", reactKnowledgeInteractionId);
+ LOG.trace("Contacting my KB to react to KI <{}>", reactKnowledgeInteractionId);
} else {
LOG.info("Contacting my KB to react to KI <{}>", reactKnowledgeInteractionId);
}
@@ -367,7 +373,12 @@ public CompletableFuture processPostFromMessageRouter(PostMessage
return future.handle((b, e) -> {
if (b != null && e == null) {
- LOG.debug("Received REACT from KB for KI <{}>: {}", reactKnowledgeInteraction, b);
+ String logStatement = "Received {} binding(s) as react from my KB for KI <{}>";
+ if (!reactKnowledgeInteraction.isMeta())
+ LOG.debug(logStatement, b.size(), reactKnowledgeInteractionId);
+ else
+ LOG.trace(logStatement, b.size(), reactKnowledgeInteractionId);
+
BindingSet translatedB = Util.translateFromApiBindingSet(b);
if (this.shouldValidateInputOutputBindings()) {
@@ -393,7 +404,7 @@ public CompletableFuture processPostFromMessageRouter(PostMessage
}
}).exceptionally((e) -> {
LOG.error("An error occurred while reacting to a message:", e);
- LOG.debug("The error occured while reacting to this message: {}", aPostMsg);
+ LOG.trace("The error occured while reacting to this message: {}", aPostMsg);
return new ReactMessage(aPostMsg.getToKnowledgeBase(), reactKnowledgeInteractionId,
aPostMsg.getFromKnowledgeBase(), aPostMsg.getFromKnowledgeInteraction(), aPostMsg.getMessageId(),
e.getMessage());
@@ -539,7 +550,7 @@ public int getReasonerLevel() {
private void readAdditionalDomainKnowledge(String pathString) {
Path p = FileSystems.getDefault().getPath(pathString);
- LOG.debug("Reading additional domain knowledge from path: " + p.toAbsolutePath());
+ LOG.trace("Reading additional domain knowledge from path: " + p.toAbsolutePath());
try (BufferedReader r = Files.newBufferedReader(p.toAbsolutePath(), StandardCharsets.UTF_8)) {
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MessageRouterImpl.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MessageRouterImpl.java
index f13bfef8f..f51e56e2d 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MessageRouterImpl.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MessageRouterImpl.java
@@ -102,7 +102,7 @@ public CompletableFuture sendAskMessage(AskMessage askMessage) th
LOG.error("KB '{}' did not respond within {}s to AskMessage '{}'.",
askMessage.getToKnowledgeBase(), this.getWaitTimeout(), askMessage.getMessageId());
else if (e instanceof CancellationException)
- LOG.debug("Waiting for AnswerMessage to AskMessage '{}' was cancelled due to a stopping SC.",
+ LOG.trace("Waiting for AnswerMessage to AskMessage '{}' was cancelled due to a stopping SC.",
askMessage.getMessageId());
else
LOG.error("A {} occurred while sending an AskMessage.", e.getClass().getSimpleName(), e);
@@ -130,7 +130,7 @@ else if (e instanceof CancellationException)
throw ioe;
}
- LOG.debug("Sent AskMessage: {}", askMessage);
+ LOG.trace("Sent AskMessage: {}", askMessage);
return future;
}
@@ -151,7 +151,7 @@ public CompletableFuture sendPostMessage(PostMessage postMessage)
LOG.warn("KB '{}' did not respond within {}s to PostMessage '{}'.",
postMessage.getToKnowledgeBase(), this.getWaitTimeout(), postMessage.getMessageId());
else if (e instanceof CancellationException)
- LOG.debug("Waiting for ReactMessage to PostMessage '{}' was cancelled due to a stopping SC.",
+ LOG.trace("Waiting for ReactMessage to PostMessage '{}' was cancelled due to a stopping SC.",
postMessage.getMessageId());
else
LOG.error("A {} occurred while sending an PostMessage.", e.getClass().getSimpleName(), e);
@@ -177,7 +177,7 @@ else if (e instanceof CancellationException)
// and re throw
throw ioe;
}
- LOG.debug("Sent PostMessage: {}", postMessage);
+ LOG.trace("Sent PostMessage: {}", postMessage);
return future;
}
@@ -201,7 +201,7 @@ public void handleAskMessage(AskMessage message) {
messageDispatcher.send(reply);
} catch (Throwable e) {
this.LOG.warn("Could not send reply to message " + message.getMessageId() + ": " + e.getMessage());
- this.LOG.debug("", e);
+ this.LOG.trace("", e);
}
}).handle((r, e) -> {
@@ -258,7 +258,7 @@ public void handleAnswerMessage(AnswerMessage answerMessage) {
+ ", but I don't remember sending a message with that ID. It might have taken more than {}s to respond.",
this.getWaitTimeout());
} else {
- LOG.debug("Received AnswerMessage: {}", answerMessage);
+ LOG.trace("Received AnswerMessage: {}", answerMessage);
future.complete(answerMessage);
}
}
@@ -277,7 +277,7 @@ public void handleReactMessage(ReactMessage reactMessage) {
} else {
assert reactMessage != null;
assert future != null;
- LOG.debug("Received ReactMessage: {}", reactMessage);
+ LOG.trace("Received ReactMessage: {}", reactMessage);
future.complete(reactMessage);
}
}
@@ -341,7 +341,7 @@ public void stop() {
if (future.cancel(true))
i++;
}
- LOG.debug("MessageRouterImpl stopped. Cancelled {} message(s).", i);
+ LOG.trace("MessageRouterImpl stopped. Cancelled {} message(s).", i);
}
}
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MetaKnowledgeBaseImpl.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MetaKnowledgeBaseImpl.java
index f446ecfbd..7a41691f6 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MetaKnowledgeBaseImpl.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/MetaKnowledgeBaseImpl.java
@@ -92,7 +92,7 @@ public MetaKnowledgeBaseImpl(LoggerProvider loggerProvider, MessageRouter aMessa
true, MatchStrategy.ENTRY_LEVEL);
this.knowledgeBaseStore
.register(
- this.metaAnswerKI, (anAKI,
+ this.metaAnswerKI, (_,
anAnswerExchangeInfo) -> Util.translateToApiBindingSet(this.fillMetaBindings(
Util.translateFromApiBindingSet(anAnswerExchangeInfo.getIncomingBindings()))),
true);
@@ -123,7 +123,7 @@ public MetaKnowledgeBaseImpl(LoggerProvider loggerProvider, MessageRouter aMessa
new CommunicativeAct(new HashSet<>(Arrays.asList(Vocab.NEW_KNOWLEDGE_PURPOSE)),
new HashSet<>(Arrays.asList(Vocab.INFORM_PURPOSE))),
this.metaGraphPattern, null, null, true, true, MatchStrategy.ENTRY_LEVEL);
- this.knowledgeBaseStore.register(this.metaReactNewKI, (aRKI, aReactExchangeInfo) -> {
+ this.knowledgeBaseStore.register(this.metaReactNewKI, (_, aReactExchangeInfo) -> {
var postingKi = aReactExchangeInfo.getPostingKnowledgeInteractionId();
var itShouldBeThis = this.knowledgeBaseStore.getMetaId(aReactExchangeInfo.getPostingKnowledgeBaseId(),
KnowledgeInteractionInfo.Type.POST, Vocab.NEW_KNOWLEDGE_PURPOSE);
@@ -144,7 +144,7 @@ public MetaKnowledgeBaseImpl(LoggerProvider loggerProvider, MessageRouter aMessa
new CommunicativeAct(new HashSet<>(Arrays.asList(Vocab.CHANGED_KNOWLEDGE_PURPOSE)),
new HashSet<>(Arrays.asList(Vocab.INFORM_PURPOSE))),
this.metaGraphPattern, null, null, true, true, MatchStrategy.ENTRY_LEVEL);
- this.knowledgeBaseStore.register(this.metaReactChangedKI, (aRKI, aReactExchangeInfo) -> {
+ this.knowledgeBaseStore.register(this.metaReactChangedKI, (_, aReactExchangeInfo) -> {
var postingKi = aReactExchangeInfo.getPostingKnowledgeInteractionId();
var itShouldBeThis = this.knowledgeBaseStore.getMetaId(aReactExchangeInfo.getPostingKnowledgeBaseId(),
KnowledgeInteractionInfo.Type.POST, Vocab.CHANGED_KNOWLEDGE_PURPOSE);
@@ -165,7 +165,7 @@ public MetaKnowledgeBaseImpl(LoggerProvider loggerProvider, MessageRouter aMessa
new CommunicativeAct(new HashSet<>(Arrays.asList(Vocab.REMOVED_KNOWLEDGE_PURPOSE)),
new HashSet<>(Arrays.asList(Vocab.INFORM_PURPOSE))),
this.metaGraphPattern, null, null, true, true, MatchStrategy.ENTRY_LEVEL);
- this.knowledgeBaseStore.register(this.metaReactRemovedKI, (aRKI, aReactExchangeInfo) -> {
+ this.knowledgeBaseStore.register(this.metaReactRemovedKI, (_, aReactExchangeInfo) -> {
var postingKi = aReactExchangeInfo.getPostingKnowledgeInteractionId();
var itShouldBeThis = this.knowledgeBaseStore.getMetaId(aReactExchangeInfo.getPostingKnowledgeBaseId(),
KnowledgeInteractionInfo.Type.POST, Vocab.REMOVED_KNOWLEDGE_PURPOSE);
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/OtherKnowledgeBaseStoreImpl.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/OtherKnowledgeBaseStoreImpl.java
index 08bff0b1f..d67b953a7 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/OtherKnowledgeBaseStoreImpl.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/OtherKnowledgeBaseStoreImpl.java
@@ -92,7 +92,7 @@ public CompletableFuture populate() {
@Override
public void addKnowledgeBase(OtherKnowledgeBase kb) {
if (this.otherKnowledgeBases.containsKey(kb.getId())) {
- LOG.warn("Tried to add a knowledge base {}, but it is already in my store! Skipped it.", kb.getId());
+ LOG.trace("Tried to add a knowledge base {}, but it is already in my store! Skipped it.", kb.getId());
return;
}
@@ -106,7 +106,7 @@ public void addKnowledgeBase(OtherKnowledgeBase kb) {
@Override
public void updateKnowledgeBase(OtherKnowledgeBase kb) {
if (!this.otherKnowledgeBases.containsKey(kb.getId())) {
- LOG.warn("Tried to update knowledge base {}, but it is not in my store! Skipped it.", kb.getId());
+ LOG.trace("Tried to update knowledge base {}, but it is not in my store! Skipped it.", kb.getId());
return;
}
@@ -120,7 +120,7 @@ public void updateKnowledgeBase(OtherKnowledgeBase kb) {
@Override
public void removeKnowledgeBase(OtherKnowledgeBase kb) {
if (!this.otherKnowledgeBases.containsKey(kb.getId())) {
- LOG.warn("Tried to remove knowledge base {}, but it isn't even in my store! Skipped it.", kb.getId());
+ LOG.trace("Tried to remove knowledge base {}, but it isn't even in my store! Skipped it.", kb.getId());
return;
}
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/ReasonerProcessor.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/ReasonerProcessor.java
index ed912ece4..907af21ce 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/ReasonerProcessor.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/ReasonerProcessor.java
@@ -6,6 +6,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -13,10 +14,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
-import org.apache.jena.graph.Node;
-import org.apache.jena.sparql.core.Var;
-import org.apache.jena.sparql.serializer.SerializationContext;
-import org.apache.jena.sparql.util.FmtUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;
@@ -30,6 +27,7 @@
import eu.knowledge.engine.reasoner.SinkBindingSetHandler;
import eu.knowledge.engine.reasoner.TaskBoard;
import eu.knowledge.engine.reasoner.TransformBindingSetHandler;
+import eu.knowledge.engine.reasoner.api.BindingSet;
import eu.knowledge.engine.reasoner.api.TripleNode;
import eu.knowledge.engine.reasoner.api.TriplePattern;
import eu.knowledge.engine.reasoner.rulenode.RuleNode;
@@ -38,8 +36,6 @@
import eu.knowledge.engine.smartconnector.api.AskExchangeInfo;
import eu.knowledge.engine.smartconnector.api.AskKnowledgeInteraction;
import eu.knowledge.engine.smartconnector.api.AskResult;
-import eu.knowledge.engine.reasoner.api.Binding;
-import eu.knowledge.engine.reasoner.api.BindingSet;
import eu.knowledge.engine.smartconnector.api.ExchangeInfo.Initiator;
import eu.knowledge.engine.smartconnector.api.ExchangeInfo.Status;
import eu.knowledge.engine.smartconnector.api.GraphPattern;
@@ -118,7 +114,7 @@ public ReasonerProcessor(Set knowledgeInteractions, Me
Rule aRule = new Rule(ruleName, new HashSet<>(Util.translateGraphPatternTo(gp)),
new AnswerBindingSetHandler(kii));
store.addRule(aRule);
- LOG.debug("Adding ANSWER to store: {}", aRule);
+ LOG.trace("Adding ANSWER to store: {}", aRule);
} else if (kii.getType().equals(Type.REACT)) {
ReactKnowledgeInteraction rki = (ReactKnowledgeInteraction) ki;
GraphPattern argGp = rki.getArgument();
@@ -134,13 +130,10 @@ public ReasonerProcessor(Set knowledgeInteractions, Me
aRule = new Rule(ruleName, Util.translateGraphPatternTo(argGp), resPattern,
new ReactBindingSetHandler(kii));
}
-
store.addRule(aRule);
- LOG.debug("Adding REACT to store: {}", aRule);
+ LOG.trace("Adding REACT to store: {}", aRule);
}
-
}
-
}
@Override
@@ -163,7 +156,7 @@ public void planAskInteraction(MyKnowledgeInteractionInfo aAKI) {
else
aStrategy = aki.getMatchStrategy();
- LOG.debug("Creating reasoner plan with strategy: {}", aStrategy);
+ LOG.trace("Creating reasoner plan with strategy: {}", aStrategy);
this.reasonerPlan = new ReasonerPlan(this.store, aRule, aStrategy.toConfig(true));
} else {
LOG.warn("Type should be Ask, not {}", this.myKnowledgeInteraction.getType());
@@ -199,6 +192,25 @@ public CompletableFuture executeAskInteraction(BindingSet someBinding
this.knowledgeGaps = bs.isEmpty() ? getKnowledgeGaps(this.reasonerPlan.getStartNode())
: new HashSet();
}
+
+ // extract succeeded nr of exchange infos and nr of failed exchange infos
+ List succeededKIs = new ArrayList(), failedKIs = new ArrayList();
+ for (AskExchangeInfo aei : this.askExchangeInfos) {
+ if (aei.getStatus().equals(Status.SUCCEEDED)) {
+ succeededKIs.add(aei.getKnowledgeInteractionId().toString());
+ } else if (aei.getStatus().equals(Status.FAILED)) {
+ failedKIs.add(aei.getKnowledgeInteractionId().toString());
+ }
+ }
+
+ String logStatement = "Finished ask for KI <{}> with {} result bindings involving {} KI(s) (of which {} failed: {})";
+ if (this.myKnowledgeInteraction.isMeta())
+ LOG.trace(logStatement, this.myKnowledgeInteraction.getId(), bs.size(),
+ succeededKIs.size() + failedKIs.size(), failedKIs.size(), failedKIs);
+ else
+ LOG.info(logStatement, this.myKnowledgeInteraction.getId(), bs.size(),
+ succeededKIs.size() + failedKIs.size(), failedKIs.size(), failedKIs);
+
return new AskResult(Util.translateToApiBindingSet(bs), this.askExchangeInfos, this.reasonerPlan,
this.knowledgeGaps);
});
@@ -211,9 +223,9 @@ private void continueReasoningBackward(BindingSet incomingBS) {
final String msg = "Executing (scheduled) tasks for the reasoner should not result in problems.";
taskboard = this.reasonerPlan.execute(incomingBS);
isComplete = !taskboard.hasTasks();
- LOG.debug("ask:\n{}", this.reasonerPlan);
- taskboard.executeScheduledTasks().thenAccept(Void -> {
- LOG.debug("All ask tasks finished.");
+ LOG.trace("Ask: {}", this.reasonerPlan);
+ taskboard.executeScheduledTasks().thenAccept(_ -> {
+ LOG.trace("All ask tasks finished.");
if (isComplete) {
BindingSet bs = this.reasonerPlan.getResults();
this.finalBindingSetFuture.complete(bs);
@@ -256,7 +268,7 @@ public void planPostInteraction(MyKnowledgeInteractionInfo aPKI) {
else
aStrategy = pki.getMatchStrategy();
- LOG.debug("Creating reasoner plan with strategy: {}", aStrategy);
+ LOG.trace("Creating reasoner plan with strategy: {}", aStrategy);
this.reasonerPlan = new ReasonerPlan(this.store, aRule, aStrategy.toConfig(false));
} else {
@@ -274,6 +286,25 @@ public CompletableFuture executePostInteraction(BindingSet someBindi
continueReasoningForward(someBindings, this.captureResultBindingSetHandler);
return this.finalBindingSetFuture.thenApply((bs) -> {
+
+ // extract succeeded nr of exchange infos and nr of failed exchange infos
+ List succeededKIs = new ArrayList<>(), failedKIs = new ArrayList<>();
+ for (PostExchangeInfo aei : this.postExchangeInfos) {
+ if (aei.getStatus().equals(Status.SUCCEEDED)) {
+ succeededKIs.add(aei.getKnowledgeInteractionId().toString());
+ } else if (aei.getStatus().equals(Status.FAILED)) {
+ failedKIs.add(aei.getKnowledgeInteractionId().toString());
+ }
+ }
+
+ String logMessage = "Finished post for KI <{}> with {} result bindings involving {} KI(s) (of which {} failed: {})";
+ if (this.myKnowledgeInteraction.isMeta())
+ LOG.trace(logMessage, this.myKnowledgeInteraction.getId(), bs.size(),
+ succeededKIs.size() + failedKIs.size(), failedKIs.size(), failedKIs);
+ else
+ LOG.info(logMessage, this.myKnowledgeInteraction.getId(), bs.size(),
+ succeededKIs.size() + failedKIs.size(), failedKIs.size(), failedKIs);
+
return new PostResult(Util.translateToApiBindingSet(bs), this.postExchangeInfos, this.reasonerPlan);
});
}
@@ -285,9 +316,9 @@ private void continueReasoningForward(BindingSet incomingBS, CaptureBindingSetHa
TaskBoard taskboard;
taskboard = this.reasonerPlan.execute(incomingBS);
isComplete = !taskboard.hasTasks();
- LOG.debug("post:\n{}", this.reasonerPlan);
- taskboard.executeScheduledTasks().thenAccept(Void -> {
- LOG.debug("All post tasks finished.");
+ LOG.trace("Post: {}", this.reasonerPlan);
+ taskboard.executeScheduledTasks().thenAccept(_ -> {
+ LOG.trace("All post tasks finished.");
if (isComplete) {
BindingSet resultBS = new BindingSet();
if (aBindingSetHandler != null && aBindingSetHandler.getBindingSet() != null) {
@@ -390,6 +421,14 @@ public CompletableFuture handle(BindingSet bs) {
this.kii.getId(), bs);
try {
+ String logMessage = "Contacting KI <{}> while executing <{}>";
+ if (!ReasonerProcessor.this.myKnowledgeInteraction.isMeta())
+ LOG.debug(logMessage, askMessage.getToKnowledgeInteraction(),
+ askMessage.getFromKnowledgeInteraction());
+ else
+ LOG.trace(logMessage, askMessage.getToKnowledgeInteraction(),
+ askMessage.getFromKnowledgeInteraction());
+
CompletableFuture sendAskMessage = ReasonerProcessor.this.messageRouter
.sendAskMessage(askMessage);
Instant aPreviousSend = Instant.now();
@@ -403,13 +442,13 @@ public CompletableFuture handle(BindingSet bs) {
askMessage.getMessageId().toString() });
LOG.warn(failedMessage);
- LOG.debug("", t);
+ LOG.trace("", t);
return ReasonerProcessor.this
.createFailedResponseMessageFromRequestMessage(askMessage,
failedMessage);
}).thenApply((answerMessage) -> {
assert answerMessage != null;
- LOG.debug("Received ANSWER message from KI '{}'", answerMessage.getFromKnowledgeInteraction());
+ LOG.trace("Received ANSWER message from KI '{}'", answerMessage.getFromKnowledgeInteraction());
BindingSet resultBindingSet = answerMessage.getBindings();
ReasonerProcessor.this.askExchangeInfos
@@ -482,6 +521,13 @@ public CompletableFuture handle(BindingSet bs) {
ReasonerProcessor.this.myKnowledgeInteraction.getId(), kii.getKnowledgeBaseId(), kii.getId(), bs);
try {
+ String logMessage = "Contacting KI <{}> while executing <{}>";
+ if (!ReasonerProcessor.this.myKnowledgeInteraction.isMeta())
+ LOG.debug(logMessage, postMessage.getToKnowledgeInteraction(),
+ postMessage.getFromKnowledgeInteraction());
+ else
+ LOG.trace(logMessage, postMessage.getToKnowledgeInteraction(),
+ postMessage.getFromKnowledgeInteraction());
CompletableFuture sendPostMessage = ReasonerProcessor.this.messageRouter
.sendPostMessage(postMessage);
Instant aPreviousSend = Instant.now();
@@ -492,7 +538,7 @@ public CompletableFuture handle(BindingSet bs) {
t.getMessage() != null ? t.getMessage() : t.getClass().getSimpleName(),
postMessage.getMessageId().toString() });
LOG.warn(failedMessage);
- LOG.debug("", t);
+ LOG.trace("", t);
return ReasonerProcessor.this
.createFailedResponseMessageFromRequestMessage(postMessage,
failedMessage);
@@ -549,6 +595,14 @@ public CompletableFuture handle(BindingSet bs) {
ReasonerProcessor.this.myKnowledgeInteraction.getId(), kii.getKnowledgeBaseId(), kii.getId(), bs);
try {
+ String logMessage = "Contacting KI <{}> while executing <{}>";
+ if (!ReasonerProcessor.this.myKnowledgeInteraction.isMeta())
+ LOG.debug(logMessage, postMessage.getToKnowledgeInteraction(),
+ postMessage.getFromKnowledgeInteraction());
+ else
+ LOG.trace(logMessage, postMessage.getToKnowledgeInteraction(),
+ postMessage.getFromKnowledgeInteraction());
+
CompletableFuture sendPostMessage = ReasonerProcessor.this.messageRouter
.sendPostMessage(postMessage);
Instant aPreviousSend = Instant.now();
@@ -559,7 +613,7 @@ public CompletableFuture handle(BindingSet bs) {
t.getMessage() != null ? t.getMessage() : t.getClass().getSimpleName(),
postMessage.getMessageId().toString() });
LOG.warn(failedMessage);
- LOG.debug("", t);
+ LOG.trace("", t);
return ReasonerProcessor.this
.createFailedResponseMessageFromRequestMessage(postMessage,
failedMessage);
@@ -619,17 +673,17 @@ public Set getKnowledgeGaps(RuleNode plan) {
for (Entry> entry : nodeCoverage.entrySet()) {
- LOG.debug("Entry key is {}", entry.getKey());
- LOG.debug("Entry value is {}", entry.getValue());
+ LOG.trace("Entry key is {}", entry.getKey());
+ LOG.trace("Entry value is {}", entry.getValue());
collectedOrGaps = new HashSet<>();
boolean foundNeighborWithoutGap = false;
for (RuleNode neighbor : entry.getValue()) {
- LOG.debug("Neighbor is {}", neighbor);
+ LOG.trace("Neighbor is {}", neighbor);
if (!neighbor.getRule().getAntecedent().isEmpty()) {
// make sure neighbor has no knowledge gaps
- LOG.debug("Neighbor has antecedents, so check if the neighbor has gaps");
+ LOG.trace("Neighbor has antecedents, so check if the neighbor has gaps");
// knowledge engine specific code. We ignore meta knowledge interactions when
// looking for knowledge gaps, because they are very generic and make finding
@@ -640,16 +694,16 @@ public Set getKnowledgeGaps(RuleNode plan) {
if (!isMeta && (someGaps = getKnowledgeGaps(neighbor)).isEmpty()) {
// found neighbor without knowledge gaps for the current triple, so current
// triple is covered.
- LOG.debug("Neighbor has no gaps");
+ LOG.trace("Neighbor has no gaps");
foundNeighborWithoutGap = true;
break;
}
- LOG.debug("Neighbor has someGaps {}", someGaps);
+ LOG.trace("Neighbor has someGaps {}", someGaps);
collectedOrGaps.addAll(someGaps);
} else
foundNeighborWithoutGap = true;
}
- LOG.debug("Found a neighbor without gaps is {}", foundNeighborWithoutGap);
+ LOG.trace("Found a neighbor without gaps is {}", foundNeighborWithoutGap);
if (foundNeighborWithoutGap)
continue;
@@ -661,11 +715,11 @@ public Set getKnowledgeGaps(RuleNode plan) {
kg.add(entry.getKey());
collectedOrGaps.add(kg);
}
- LOG.debug("CollectedOrGaps is {}", collectedOrGaps);
+ LOG.trace("CollectedOrGaps is {}", collectedOrGaps);
existingOrGaps = mergeGaps(existingOrGaps, collectedOrGaps);
}
- LOG.debug("Found existingOrGaps {}", existingOrGaps);
+ LOG.trace("Found existingOrGaps {}", existingOrGaps);
return existingOrGaps;
}
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorBuilder.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorBuilder.java
index d1b954825..46a271c71 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorBuilder.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorBuilder.java
@@ -16,7 +16,30 @@ public SmartConnector create() {
}
public static SmartConnectorBuilder newSmartConnector(KnowledgeBase knowledgeBase) {
+
+ checkNull(knowledgeBase);
+
return new SmartConnectorBuilder(knowledgeBase);
}
+ private static void checkNull(KnowledgeBase knowledgeBase) {
+ String message = "The KB ";
+ boolean allNonNull = true;
+ if (knowledgeBase.getKnowledgeBaseId() == null) {
+ allNonNull = false;
+ message += "id";
+ } else if (knowledgeBase.getKnowledgeBaseName() == null) {
+ allNonNull = false;
+ message += "name";
+ } else if (knowledgeBase.getKnowledgeBaseDescription() == null) {
+ allNonNull = false;
+ message += "description";
+ }
+
+ message += " should be non-null.";
+
+ if (!allNonNull)
+ throw new NullPointerException(message);
+ }
+
}
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorImpl.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorImpl.java
index e810b08e7..e9664538e 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorImpl.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/impl/SmartConnectorImpl.java
@@ -115,7 +115,7 @@ public URI getKnowledgeBaseId() {
public URI register(AskKnowledgeInteraction anAskKI) {
this.checkStopped();
URI kiId = this.knowledgeBaseStore.register(anAskKI, false);
- LOG.info("Registered Ask KI <{}>.", kiId);
+ LOG.trace("Registered Ask KI <{}>.", anAskKI);
return kiId;
}
@@ -157,7 +157,7 @@ public void unregister(AskKnowledgeInteraction anAskKI) {
public URI register(AnswerKnowledgeInteraction anAnswerKI, AnswerHandler anAnswerHandler) {
this.checkStopped();
URI kiId = this.knowledgeBaseStore.register(anAnswerKI, anAnswerHandler, false);
- LOG.info("Registered Answer KI <{}>.", kiId);
+ LOG.trace("Registered Answer KI <{}>.", anAnswerKI);
return kiId;
}
@@ -194,7 +194,7 @@ public void unregister(AnswerKnowledgeInteraction anAnswerKI) {
public URI register(PostKnowledgeInteraction aPostKI) {
this.checkStopped();
URI kiId = this.knowledgeBaseStore.register(aPostKI, false);
- LOG.info("Registered Post KI <{}>.", kiId);
+ LOG.trace("Registered Post KI <{}>.", aPostKI);
return kiId;
}
@@ -235,7 +235,7 @@ public void unregister(PostKnowledgeInteraction aPostKI) {
public URI register(ReactKnowledgeInteraction aReactKI, ReactHandler aReactHandler) {
this.checkStopped();
URI kiId = this.knowledgeBaseStore.register(aReactKI, aReactHandler, false);
- LOG.info("Registered React KI <{}>.", kiId);
+ LOG.trace("Registered React KI <{}>.", aReactKI);
return kiId;
}
@@ -461,7 +461,7 @@ public CompletableFuture stop() {
// this will trigger notifications to other Smart Connectors.
CompletableFuture future = this.knowledgeBaseStore.stop();
- return future.whenComplete((v, t) -> {
+ return future.whenComplete((_, t) -> {
if (t != null)
LOG.debug("An error occurred while notifying other SCs.", t);
@@ -481,19 +481,21 @@ private void checkStopped() {
}
void communicationReady() {
- Instant beforePopulate = Instant.now();
- LOG.info("Getting comms ready took {} ms", Duration.between(this.started, beforePopulate).toMillis());
+ Instant beforeComms = Instant.now();
+ LOG.trace("Getting comms ready took {} ms", Duration.between(this.started, beforeComms).toMillis());
Instant beforeConstructorFinished = Instant.now();
- this.constructorFinished.handle((r3, e3) -> {
- LOG.info("Constructor finished took {} ms",
+ this.constructorFinished.handle((_, _) -> {
+ LOG.trace("Constructor finished took {} ms",
Duration.between(beforeConstructorFinished, Instant.now()).toMillis());
// Populate the initial knowledge base store.
- this.otherKnowledgeBaseStore.populate().handle((r, e) -> {
- LOG.info("Populating took {} ms", Duration.between(beforePopulate, Instant.now()).toMillis());
- Instant beforeAnnounce = Instant.now();
+ Instant beforePopulate = Instant.now();
+ this.otherKnowledgeBaseStore.populate().handle((_, _) -> {
+ LOG.debug("Populating took {} ms", Duration.between(beforePopulate, Instant.now()).toMillis());
// Then tell the other knowledge bases about our existence.
- this.metaKnowledgeBase.postNewKnowledgeBase().handle((r2, e2) -> {
- LOG.info("Announcing took {} ms", Duration.between(beforeAnnounce, Instant.now()).toMillis());
+ this.metaKnowledgeBase.postNewKnowledgeBase().handle((_, _) -> {
+ LOG.info("SC communication ready took {} ms. Default reasoner level: {}",
+ Duration.between(this.started, Instant.now()).toMillis(),
+ this.interactionProcessor.getReasonerLevel());
// When that is done, and all peers have acknowledged our existence, we
// can proceed to inform the knowledge base that this smart connector is
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/KeRuntime.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/KeRuntime.java
index 69d72f4e7..3f42df16a 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/KeRuntime.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/KeRuntime.java
@@ -3,7 +3,6 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
@@ -47,18 +46,6 @@ public class KeRuntime {
Config config = ConfigProvider.getConfig();
ConfigValue exposedUrl = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_RUNTIME_EXPOSED_URL);
- ConfigValue hostname = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_RUNTIME_HOSTNAME);
-
- // Using MicroProfile Config's source ordinal to determine if default
- // configuration got overridden?
- if (exposedUrl.getSourceOrdinal() > 100 && hostname.getSourceOrdinal() > 100) {
- LOG.error("KE runtime must be configured with {} or {}, not both.",
- SmartConnectorConfig.CONF_KEY_KE_RUNTIME_EXPOSED_URL,
- SmartConnectorConfig.CONF_KEY_KE_RUNTIME_HOSTNAME);
- LOG.info("Using {} allows the use of a reverse proxy for TLS connections, which is recommended.",
- SmartConnectorConfig.CONF_KEY_KE_RUNTIME_EXPOSED_URL);
- System.exit(1);
- }
// execute some validation on the EXPOSED URL, because it can have severe
// consequences
@@ -71,9 +58,8 @@ public class KeRuntime {
System.exit(1);
}
try {
- new URL(url);
-
- } catch (MalformedURLException e) {
+ new URI(url).toURL();
+ } catch (URISyntaxException | MalformedURLException e) {
LOG.error("The '{}' environment variable with value '{}' contains a malformed URL '{}'.",
SmartConnectorConfig.CONF_KEY_KE_RUNTIME_EXPOSED_URL, url, e.getMessage());
System.exit(1);
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java
index 099fdb02e..9d5444f3d 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java
@@ -30,6 +30,7 @@
import eu.knowledge.engine.smartconnector.runtime.messaging.inter_ker.api.RFC3339DateFormat;
import eu.knowledge.engine.smartconnector.runtime.messaging.kd.model.KnowledgeEngineRuntimeConnectionDetails;
import static eu.knowledge.engine.smartconnector.runtime.messaging.Utils.stripUserInfoFromURI;
+
/**
* The {@link KnowledgeDirectoryConnection} is responsible for providing access
* to the Knowledge Directory, maintaining the connection and the renewing the
@@ -79,7 +80,8 @@ protected PasswordAuthentication getPasswordAuthentication() {
}
});
} else {
- throw new IllegalArgumentException("Found user information in KD URL, but it does not have two parts. Make sure you don't use a colon inside the parts.");
+ throw new IllegalArgumentException(
+ "Found user information in KD URL, but it does not have two parts. Make sure you don't use a colon inside the parts.");
}
} else {
this.kdUrl = kdUrl;
@@ -89,7 +91,7 @@ protected PasswordAuthentication getPasswordAuthentication() {
this.objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
- .setSerializationInclusion(JsonInclude.Include.NON_NULL).findAndRegisterModules()
+ .setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL).findAndRegisterModules()
.setDateFormat(new RFC3339DateFormat());
}
@@ -99,7 +101,7 @@ public void start() {
throw new IllegalStateException(
"Can only start KnowledgeDirectoryConnectionManager when the state is UNREGISTERED");
}
-
+
LOG.info("Starting connection with Knowledge Directory at " + kdUrl);
// Schedule automatic register/renew
scheduledFuture = KeRuntime.executorService().scheduleAtFixedRate(() -> {
@@ -196,14 +198,12 @@ private void tryRegister() {
ker.setId(this.myEdcProperties.participantId().toString());
ker.setEdcConnectorUrl(this.myEdcProperties.protocolUrl());
ker.setExposedUrl(this.myEdcProperties.dataPlanePublicUrl());
- }
- else {
+ } else {
ker.setExposedUrl(myExposedUrl);
}
try {
- HttpRequest registerRequest = HttpRequest
- .newBuilder(new URI(kdUrl + "/ker/"))
+ HttpRequest registerRequest = HttpRequest.newBuilder(new URI(kdUrl + "/ker/"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(ker))).build();
HttpResponse response = httpClient.send(registerRequest, BodyHandlers.ofString());
@@ -216,14 +216,12 @@ private void tryRegister() {
} else if (statusCode == 400) {
// Registration was not successful
this.currentState = State.INTERRUPTED;
- LOG.warn("Could not register at Knowledge Directory " + kdUrl + ", response was: "
- + response.body());
+ LOG.warn("Could not register at Knowledge Directory " + kdUrl + ", response was: " + response.body());
} else if (statusCode == 409) {
// Was already registered
myId = response.body();
this.currentState = State.REGISTERED;
- LOG.debug("Tried to register at Knowledge Directory " + kdUrl
- + ", but was already registered");
+ LOG.debug("Tried to register at Knowledge Directory " + kdUrl + ", but was already registered");
tryRenewLease();
} else {
LOG.error("Unexpected status code while trying to register at Knowledge Directory: {}", statusCode);
@@ -247,8 +245,7 @@ private void tryUnregister() {
}
try {
- HttpRequest registerRequest = HttpRequest
- .newBuilder(new URI(kdUrl + "/ker/" + urlEncode(myId)))
+ HttpRequest registerRequest = HttpRequest.newBuilder(new URI(kdUrl + "/ker/" + urlEncode(myId)))
.header("Content-Type", "application/json").DELETE().build();
HttpResponse response = httpClient.send(registerRequest, BodyHandlers.ofString());
int statusCode = response.statusCode();
@@ -259,8 +256,7 @@ private void tryUnregister() {
} else if (statusCode == 404) {
// Not found, so we're not registered anymore, also fine
this.currentState = State.STOPPED;
- LOG.info("Could not unregister at Knowledge Directory " + kdUrl + ", response was: "
- + response.body());
+ LOG.info("Could not unregister at Knowledge Directory " + kdUrl + ", response was: " + response.body());
} else {
LOG.warn("Unknown status code {} while unregistering the KER", statusCode);
}
@@ -278,8 +274,7 @@ private void tryRenewLease() {
}
LOG.debug("Attempting a renew of the lease at Knowledge Directory " + kdUrl);
try {
- HttpRequest registerRequest = HttpRequest
- .newBuilder(new URI(kdUrl + "/ker/" + urlEncode(myId) + "/renew"))
+ HttpRequest registerRequest = HttpRequest.newBuilder(new URI(kdUrl + "/ker/" + urlEncode(myId) + "/renew"))
.header("Content-Type", "application/json").POST(BodyPublishers.noBody()).build();
HttpResponse response = httpClient.send(registerRequest, BodyHandlers.ofString());
int statusCode = response.statusCode();
@@ -290,8 +285,8 @@ private void tryRenewLease() {
} else if (statusCode == 404) {
// Doesn't recognize this KER
this.currentState = State.INTERRUPTED;
- LOG.info("Could not renew lease at Knowledge Directory " + kdUrl
- + ", response was: " + response.body());
+ LOG.info(
+ "Could not renew lease at Knowledge Directory " + kdUrl + ", response was: " + response.body());
} else {
LOG.warn("Unknown status code {} while calling the renewing the lease on the Knowledge Direcotry",
statusCode);
diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/util/KnowledgeNetwork.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/util/KnowledgeNetwork.java
index d6367526d..9bf8faeef 100644
--- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/util/KnowledgeNetwork.java
+++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/util/KnowledgeNetwork.java
@@ -118,7 +118,7 @@ private void waitForUpToDate() {
allUpToDate &= kbUpToDate;
upToDate.put(kb, kbUpToDate);
if (kbUpToDate) {
- LOG.debug("Knowledge Base {} is up to date.", kb.getKnowledgeBaseName());
+ LOG.trace("Knowledge Base {} is up to date.", kb.getKnowledgeBaseName());
}
}
try {
@@ -128,7 +128,7 @@ private void waitForUpToDate() {
LOG.error("An error occured while waiting for up-to-date.", e);
}
}
- LOG.info("Everyone is up to date after {} rounds!", count);
+ LOG.trace("Everyone is up to date after {} rounds!", count);
}
private String getUpToDateInfo(Map upToDate) {
diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/KnowledgeBaseNullTest.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/KnowledgeBaseNullTest.java
new file mode 100644
index 000000000..383e995a5
--- /dev/null
+++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/KnowledgeBaseNullTest.java
@@ -0,0 +1,105 @@
+package eu.knowledge.engine.smartconnector.api;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.net.URI;
+
+import org.junit.jupiter.api.Test;
+
+import eu.knowledge.engine.smartconnector.impl.SmartConnectorBuilder;
+
+/**
+ * Giving null values for id, name or description is incorrect and this unit
+ * tests makes sure we throw a null pointer exception when constructing the SC.
+ */
+class KnowledgeBaseNullTest {
+
+ private MyKnowledgeBase kb = new MyKnowledgeBase("kb1");
+
+ private static class MyKnowledgeBase implements KnowledgeBase {
+
+ private String id;
+ private String name;
+ private String desc;
+ private boolean idIsNull = false;
+ private boolean nameIsNull = false;
+ private boolean descIsNull = false;
+
+ public MyKnowledgeBase(String aName) {
+ this.id = "https://www.example.org/" + aName;
+ this.name = aName;
+ this.desc = aName + " description";
+ }
+
+ @Override
+ public URI getKnowledgeBaseId() {
+ if (idIsNull)
+ return null;
+ else
+ return URI.create(this.id);
+ }
+
+ @Override
+ public String getKnowledgeBaseName() {
+ if (nameIsNull)
+ return null;
+ else
+ return this.name;
+ }
+
+ @Override
+ public String getKnowledgeBaseDescription() {
+ if (descIsNull)
+ return null;
+ else
+ return this.desc;
+ }
+
+ @Override
+ public void smartConnectorReady(SmartConnector aSC) {
+ }
+
+ @Override
+ public void smartConnectorConnectionLost(SmartConnector aSC) {
+ }
+
+ @Override
+ public void smartConnectorConnectionRestored(SmartConnector aSC) {
+ }
+
+ @Override
+ public void smartConnectorStopped(SmartConnector aSC) {
+ }
+
+ public void setNull(boolean anIdIsNull, boolean aNameIsNull, boolean aDescIsNull) {
+ this.idIsNull = anIdIsNull;
+ this.nameIsNull = aNameIsNull;
+ this.descIsNull = aDescIsNull;
+ }
+ }
+
+ @Test
+ void testNullId() {
+ kb.setNull(true, false, false);
+ assertThrows(NullPointerException.class, () -> {
+ SmartConnectorBuilder.newSmartConnector(kb).create();
+ });
+ }
+
+ @Test
+ void testNullName() {
+ kb.setNull(false, true, false);
+ assertThrows(NullPointerException.class, () -> {
+ SmartConnectorBuilder.newSmartConnector(kb).create();
+ });
+ }
+
+ @Test
+ void testNullDesc() {
+ kb.setNull(false, false, true);
+ assertThrows(NullPointerException.class, () -> {
+ SmartConnectorBuilder.newSmartConnector(kb).create();
+ });
+ }
+
+}
diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestIRI.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestIRI.java
deleted file mode 100644
index 4dd9d4f88..000000000
--- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/api/TestIRI.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package eu.knowledge.engine.smartconnector.api;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.apache.jena.iri.IRI;
-import org.apache.jena.iri.IRIFactory;
-import org.junit.jupiter.api.Test;
-
-class TestIRI {
-
- private String[] validUris = new String[] {
- //@formatter:off
- "https://asdlkasld.com",
- "mailto:hello",
- "https://hello",
- //@formatter:on
- };
-
- private String[] invalidUris = new String[] {
- //@formatter:off
- "",
- "https://",
- "strange characters and spaces | & ^",
- "/relative.nl"
- //@formatter:on
- };
-
- @Test
- void test() {
- for (String validUri : validUris) {
- System.out.println("valid uri: " + validUri);
- assertTrue(isValid(validUri));
- }
-
- for (String invalidUri : invalidUris) {
- System.out.println("invalid uri: " + invalidUri);
- assertFalse(isValid(invalidUri));
- }
-
- }
-
- @Test
- void testGraphPattern() {
- new GraphPattern("?siteList a .\n"
- + " ?siteList ?site .\n"
- + " ?site ?siteCode .\n"
- + " ?site ?appList .\n"
- + " ?appList a .\n"
- + " ?appList ?app . \n"
- + " ?app ?appCode .\n"
- + " ?app ?appDevType .\n"
- + " ?app ?appName .\n"
- + " ?app ?appState .");
- }
-
- public boolean isValid(String iri) {
- IRIFactory factory = IRIFactory.iriImplementation();
-
- try {
- IRI i = factory.construct(iri);
- if (i.isAbsolute()) {
- return true;
- } else {
- return false;
- }
- } catch (Exception e) {
- return false;
- }
- }
-
-}
diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/impl/TestBindingSetConversions.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/impl/TestBindingSetConversions.java
index a24e39fb4..fccb8f5b9 100644
--- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/impl/TestBindingSetConversions.java
+++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/impl/TestBindingSetConversions.java
@@ -23,7 +23,8 @@ void testTypedLiteral() {
String varStringVersion = "a";
Var varNodeVersion = Var.alloc(varStringVersion);
- Node literalNodeVersion = NodeFactory.createLiteral("true", XSDDatatype.XSDboolean);
+
+ Node literalNodeVersion = NodeFactory.createLiteral("true", null, XSDDatatype.XSDboolean);
var literalStringVersion = "\"true\"^^";
BindingSet bs = new BindingSet();
@@ -50,7 +51,7 @@ void testTypedLiteralString() {
String varStringVersion = "a";
Var varNodeVersion = Var.alloc(varStringVersion);
- Node literalNodeVersion = NodeFactory.createLiteral("bla", XSDDatatype.XSDstring);
+ Node literalNodeVersion = NodeFactory.createLiteral("bla", null, XSDDatatype.XSDstring);
var literalStringVersion = "\"bla\"^^";
var literalSimpleStringVersion = "\"bla\"";