Skip to content

Commit

Permalink
ci: finalize release 1.13.0 (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
jobulcke authored Jan 16, 2024
2 parents 677fe5f + 3d182af commit ff00225
Show file tree
Hide file tree
Showing 106 changed files with 878 additions and 467 deletions.
5 changes: 2 additions & 3 deletions docs/_ldio/ldio-adapters/ldio-json-to-json-ld.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ title: Json To JsonLd Transformer
# LDIO Json To JsonLd Transformer
***be.vlaanderen.informatievlaanderen.ldes.ldi.JsonToLdAdapter***

An LDIO wrapper component for the [LDI Json To JsonLd building block](../../core/ldi-adapters/json-to-json-ld)
An LDIO wrapper component for the [LDI Json To JsonLd building block](../../_core/ldi-adapters/json-to-json-ld)

## Config

| Property | Description | Required | Default | Example | Supported values |
|:-------------|:---------------------------------|:---------|:--------|:--------------------------|:--------------------|
| core-context | URI of a core json-ld context. | Yes | N/A | http://example.com/my-api | HTTP and HTTPS urls |
| ld-context | URI of a custom json-ld context. | No | N/A | http://example.com/my-api | HTTP and HTTPS urls |
| core-context | URI of a core json-ld context. | Yes | N/A | http://example.com/my-api | HTTP and HTTPS urls |
17 changes: 11 additions & 6 deletions docs/_ldio/ldio-inputs/ldio-http-in-poller.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ The LDIO Http In Poller is a basic Http Poller that will poll a target URL on a

## Config

| Property | Description | Required | Default | Example | Supported values |
|:------------------------------------|:----------------------------------------------------------------------------------------------|:---------|:----------|:----------------------------|:----------------------------------------------|
| url | Target URL to poll from. | Yes | N/A | http://example.com/my-api | HTTP and HTTPS urls (lists are supported) |
| interval | Polling interval declared in ISO 8601 format. | Yes | N/A | PT1S | ISO 8601 formatted String |
| continueOnFail | Indicated if continue if polling results in failure | No | true | true | true or false |
| Property | Description | Required | Default | Example | Supported values |
|:---------------|:--------------------------------------------------------------|:---------|:--------|:--------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------|
| url | Target URL to poll from. | Yes | N/A | http://example.com/my-api | HTTP and HTTPS urls (lists are supported) |
| cron | Cron expression to declare when the polling should take place | Yes[^1] | N/A | */10 * * * * * | [Spring Cron Expression](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/support/CronExpression.html) |
| interval | Polling interval declared in ISO 8601 format. | Yes[^1] | N/A | PT1S | ISO 8601 formatted String |
| continueOnFail | Indicated if continue if polling results in failure | No | true | true | true or false |

This component uses the "LDIO Http Requester" to make the HTTP request.
Refer to [LDIO Http Requester](../ldio-core) for the config.
Expand All @@ -35,4 +36,8 @@ config:
interval: PT3S
```
When using multiple endpoints, the other config (auth config, interval, etc.) applies to all endpoints.
When using multiple endpoints, the other config (auth config, interval, etc.) applies to all endpoints.
----
[^1]: Either choose the 'cron' option or the 'interval'. However, **the interval property will become deprecated**.
36 changes: 21 additions & 15 deletions docs/_ldio/ldio-inputs/ldio-ldes-client-connector.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
---
layout: default
parent: LDIO Inputs
title: LDES Client with Connector
layout: default
parent: LDIO Inputs
title: LDES Client with Connector
---

# LDIO Ldes Client Connector

***be.vlaanderen.informatievlaanderen.ldes.ldio.LdioLdesClientConnector***

An EDC (Eclipse dataspace Connector) LDIO wrapper component for the [LDI LDES Client building block](../../core/ldi-inputs/ldes-client)
An EDC (Eclipse dataspace Connector) LDIO wrapper component for
the [LDI LDES Client building block](../../core/ldi-inputs/ldes-client)

This component adds EDC support to [the ldio ldes client](./ldio-ldes-client.md). If you'd like to know how to configure the LDES Client,
This component adds EDC support to [the ldio ldes client](./ldio-ldes-client.md). If you'd like to know how to configure
the LDES Client,
we refer to [the ldio ldes client](./ldio-ldes-client.md).
The additional functionality provided by this component makes it possible to use the Ldes Client to consume an LDES through an EDC connector.
The additional functionality provided by this component makes it possible to use the Ldes Client to consume an LDES
through an EDC connector.
This component exposes two endpoints:

1. http://<host>:<port>/<pipelines.name>/transfer
The Ldio component will start the data transfer with the connector. You have to send the transfer request to
the LdioLdesClientConnector instead of the EDC consumer connector. The LDIO Ldes Client Connector will start the transfer
with the connector and also keep the transfer alive while consuming the LDES (e.g. request a new token when it expires).
the LdioLdesClientConnector instead of the EDC consumer connector. The LDIO Ldes Client Connector will start the
transfer
with the connector and also keep the transfer alive while consuming the LDES (e.g. request a new token when it
expires).
3. http://<host>:<port>/<pipelines.name>/token
This endpoint should never be called directly. This is the callback to be provided in the transfer request.
The EDC connector will use this callback endpoint to provide the LDES Client with a token.
Expand All @@ -32,18 +37,19 @@ This component exposes two endpoints:
| connector-transfer-url | The transfer url of the EDC connector which has to be called to start a transfer | Yes | N/A | http://consumer-connector:29193/management/v2/transferprocesses | HTTP and HTTPS urls |
| proxy-url-to-replace | Makes it possible to proxy a part of the url of the LDES**. Indicates which part of the url should be replaced. | No | empty string | http://ldes-behind-connectors.dev | string |
| proxy-url-replacement | Makes it possible to proxy a part of the url of the LDES**. Indicates the replacement url part. | No | memory | http://consumer-connector:29193 | string |

** The url mentioned here are the actual url's used by the LDES Server (hostname). These are included in the results bodies to indicate relations, etc. This is a temporary solution until the client and server support relative urls.


## Examples

```yaml
input:
name: be.vlaanderen.informatievlaanderen.ldes.ldio.LdioLdesClientConnector
config:
url: http://consumer-connector:29291/public
connector-transfer-url: http://consumer-connector:29193/management/v2/transferprocesses
proxy-url-to-replace: http://localhost:8081/devices
proxy-url-replacement: http://consumer-connector:29291/public
source-format: application/n-quads
name: be.vlaanderen.informatievlaanderen.ldes.ldio.LdioLdesClientConnector
config:
url: http://consumer-connector:29291/public
connector-transfer-url: http://consumer-connector:29193/management/v2/transferprocesses
proxy-url-to-replace: http://localhost:8081/devices
proxy-url-replacement: http://consumer-connector:29291/public
source-format: application/n-quads
```
2 changes: 1 addition & 1 deletion ldi-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>be.vlaanderen.informatievlaanderen.ldes</groupId>
<artifactId>linked-data-interactions</artifactId>
<version>1.12.0-SNAPSHOT</version>
<version>1.13.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion ldi-core/file-archiving/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>be.vlaanderen.informatievlaanderen.ldes.ldi</groupId>
<artifactId>ldi-core</artifactId>
<version>1.12.0-SNAPSHOT</version>
<version>1.13.0-SNAPSHOT</version>
</parent>

<artifactId>file-archiving</artifactId>
Expand Down
14 changes: 13 additions & 1 deletion ldi-core/geojson-to-wkt/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>be.vlaanderen.informatievlaanderen.ldes.ldi</groupId>
<artifactId>ldi-core</artifactId>
<version>1.12.0-SNAPSHOT</version>
<version>1.13.0-SNAPSHOT</version>
</parent>

<artifactId>geojson-to-wkt</artifactId>
Expand All @@ -16,6 +16,18 @@
<artifactId>jena-geosparql</artifactId>
<version>${jena.version}</version>
</dependency>
<dependency>
<groupId>org.apache.sis.non-free</groupId>
<artifactId>sis-embedded-data</artifactId>
<version>${sis-embedded-db.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>${xml-bind.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>

</project>
2 changes: 1 addition & 1 deletion ldi-core/json-to-ld-adapter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>be.vlaanderen.informatievlaanderen.ldes.ldi</groupId>
<artifactId>ldi-core</artifactId>
<version>1.12.0-SNAPSHOT</version>
<version>1.13.0-SNAPSHOT</version>
</parent>

<artifactId>json-to-ld-adapter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import be.vlaanderen.informatievlaanderen.ldes.ldi.exceptions.UnsupportedMimeTypeException;
import be.vlaanderen.informatievlaanderen.ldes.ldi.types.LdiAdapter;
import org.apache.http.entity.ContentType;
import org.apache.jena.atlas.json.JSON;
import org.apache.jena.atlas.json.JsonArray;
import org.apache.jena.atlas.json.JsonObject;
import org.apache.jena.atlas.json.JsonParseException;
import org.apache.jena.atlas.json.*;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
Expand All @@ -21,51 +18,22 @@ public class JsonToLdAdapter implements LdiAdapter {

private final Logger log = LoggerFactory.getLogger(JsonToLdAdapter.class);

private final String coreContext;
private final String ldContext;
private static final String MIMETYPE = "application/json";
private final String coreContext;
private final boolean forceContentType;

public JsonToLdAdapter(String coreContext) {
this(coreContext, null, false);
this(coreContext, false);
}

public JsonToLdAdapter(String coreContext, String ldContext, boolean forceContentType) {
public JsonToLdAdapter(String coreContext, boolean forceContentType) {
if (coreContext == null) {
throw new IllegalArgumentException("Core context can't be null");
}
this.coreContext = coreContext;
this.ldContext = ldContext;
this.forceContentType = forceContentType;
}

private void addContexts(JsonObject json) {
JsonArray contexts = new JsonArray();
contexts.add(coreContext);
if (ldContext != null) {
contexts.add(ldContext);
}
json.put("@context", contexts);
}

private Stream<Model> translateJsonToLD(String data) {
try {
JsonObject json = JSON.parse(data);
addContexts(json);
return Stream.of(json).map(this::toRDFModel);
} catch (JsonParseException e) {
throw new ParseToJsonException(e, data);
}
}

private Model toRDFModel(JsonObject json) {
Model model = ModelFactory.createDefaultModel();
RDFParser.fromString(json.toString())
.lang(Lang.JSONLD)
.parse(model);
return model;
}

@Override
public Stream<Model> apply(Content content) {
if (!validateMimeType(content.mimeType())) {
Expand All @@ -82,4 +50,44 @@ private boolean validateMimeType(String mimeType) {
return ContentType.parse(mimeType).getMimeType().equalsIgnoreCase(MIMETYPE);
}

private Stream<Model> translateJsonToLD(String data) {
try {
final var json = JSON.parseAny(data);
if (json.isObject()) {
return Stream.of(mapJsonObjectToModel(json));
}

if (json.isArray()) {
final JsonArray jsonArray = json.getAsArray();
return jsonArray.stream().map(this::mapJsonObjectToModel);
}

throw new IllegalArgumentException("Only objects and arrays can be transformed to RDF. " +
"The following json does not match this criteria: " + json);
} catch (JsonParseException e) {
throw new ParseToJsonException(e, data);
}
}

private Model mapJsonObjectToModel(JsonValue json) {
if (json.isObject()) {
final var jsonObject = json.getAsObject();
addContexts(jsonObject);
Model model = ModelFactory.createDefaultModel();
RDFParser.fromString(jsonObject.toString())
.lang(Lang.JSONLD)
.parse(model);
return model;
} else {
throw new IllegalArgumentException("Only objects can be transformed to RDF. " +
"The following json does not match this criteria: " + json);
}
}

private void addContexts(JsonObject json) {
JsonArray contexts = new JsonArray();
contexts.add(coreContext);
json.put("@context", contexts);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import be.vlaanderen.informatievlaanderen.ldes.ldi.exceptions.ParseToJsonException;
import be.vlaanderen.informatievlaanderen.ldes.ldi.exceptions.UnsupportedMimeTypeException;
import be.vlaanderen.informatievlaanderen.ldes.ldi.types.LdiAdapter;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFParser;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -15,23 +17,24 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Stream;

import com.github.tomakehurst.wiremock.junit5.WireMockTest;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.*;

@WireMockTest(httpPort = 10101)
class JsonToLdAdapterTest {

private static final String CORE_CONTEXT = "http://localhost:10101/core-context.json";
private static final String LOCAL_CONTEXT = "http://localhost:10101/context.json";
private static final String MIMETYPE = "application/json";

private JsonToLdAdapter translator;

@BeforeEach
void setUp() {
translator = new JsonToLdAdapter(CORE_CONTEXT, LOCAL_CONTEXT, false);
translator = new JsonToLdAdapter(CORE_CONTEXT, false);
}

@Test
Expand All @@ -44,12 +47,28 @@ void when_ValidJson_Then_ModelIsIsomorphic() throws IOException {
assertTrue(expected.isIsomorphicWith(actual));
}

@Test
void when_ValidJsonArray_Then_ModelsAreIsomorphic() throws IOException {
String data = Files.readString(Path.of("src/test/resources/example-array.json"));
Model expected_1 = readModelFromFile("src/test/resources/expected-ld-array-1.json");
Model expected_2 = readModelFromFile("src/test/resources/expected-ld-array-2.json");

List<Model> actual = translator.apply(new LdiAdapter.Content(data, MIMETYPE)).toList();

assertThat(actual)
.hasSize(2)
.areExactly(1,
new Condition<>(model -> model.isIsomorphicWith(expected_1), "is isomorphic with exampleID_1"))
.areExactly(1,
new Condition<>(model -> model.isIsomorphicWith(expected_2), "is isomorphic with exampleID_2"));
}

@Test
void noExceptionIsThrown_whenIncorrectMimeWithForceTrue() throws IOException {
String data = Files.readString(Path.of("src/test/resources/example.json"));
Model expected = readModelFromFile("src/test/resources/expected-ld.json");

translator = new JsonToLdAdapter(CORE_CONTEXT, LOCAL_CONTEXT, true);
translator = new JsonToLdAdapter(CORE_CONTEXT, true);
Model actual = translator.apply(new LdiAdapter.Content(data, "application/tom")).toList().get(0);

assertTrue(expected.isIsomorphicWith(actual));
Expand All @@ -67,6 +86,30 @@ void when_InValidJson_Then_ExceptionIsThrown() throws IOException {
+ data + "\nCause: " + "Illegal: [null]", e.getMessage());
}

@Test
void when_ValidJson_IsNotAnObject_OrArray_Then_ExceptionIsThrown() throws IOException {
String data = Files.readString(Path.of("src/test/resources/invalid-string.json"));
LdiAdapter.Content content = new LdiAdapter.Content(data, MIMETYPE);

Exception e = assertThrows(IllegalArgumentException.class,
() -> translator.apply(content));

assertEquals("Only objects and arrays can be transformed to RDF. " +
"The following json does not match this criteria: \"Valid json but not an object...\"", e.getMessage());
}

@Test
void when_JsonArrayContainsAnythingOtherThanObjects_Then_ExceptionIsThrown() throws IOException {
String data = Files.readString(Path.of("src/test/resources/invalid-array-containing-string.json"));
LdiAdapter.Content content = new LdiAdapter.Content(data, MIMETYPE);

final Stream<Model> result = translator.apply(content);
assertThatThrownBy(result::toList) // end operation to trigger stream
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Only objects can be transformed to RDF. " +
"The following json does not match this criteria: \"Valid json but not an object...\"");
}

@Test
void when_NoLocalContext_Then_AddOnlyCoreContext() throws IOException {
translator = new JsonToLdAdapter(CORE_CONTEXT);
Expand Down
16 changes: 16 additions & 0 deletions ldi-core/json-to-ld-adapter/src/test/resources/example-array.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
{
"id": "exampleID_1",
"type": "Model",
"example": {
"value": "value_1"
}
},
{
"id": "exampleID_2",
"type": "Model",
"example": {
"value": "value_2"
}
}
]
Loading

0 comments on commit ff00225

Please sign in to comment.