Skip to content

Commit

Permalink
feat: introduces optional JSON-LD context for management API (#4470)
Browse files Browse the repository at this point in the history
* feat: introduces optional JSON-LD context for management API

* pr remarks

* chore: deps file
  • Loading branch information
wolf4ood authored Sep 16, 2024
1 parent 06cfb23 commit 7b3c28e
Show file tree
Hide file tree
Showing 23 changed files with 242 additions and 267 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/publish-context.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ on:
push:
branches: [ main ]
paths:
- 'extensions/common/api/management-api-json-ld-context/src/main/resources/document/**'
- 'extensions/common/json-ld/src/main/resources/document/**'

jobs:
build:
Expand All @@ -39,7 +39,7 @@ jobs:
- name: copy contexts into public folder
run: |
mkdir -p public/context
cp extensions/common/api/management-api-json-ld-context/src/main/resources/document/management-context-v1.jsonld public/context/
cp extensions/common/json-ld/src/main/resources/document/management-context-v1.jsonld public/context/
- name: deploy to gh-pages
uses: peaceiris/actions-gh-pages@v4
with:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class JsonLdConfiguration {

private boolean httpEnabled = false;
private boolean httpsEnabled = false;
private boolean avoidVocab = false;
private boolean checkPrefixes = true;

private JsonLdConfiguration() {
Expand All @@ -36,6 +37,10 @@ public boolean shouldCheckPrefixes() {
return checkPrefixes;
}

public boolean isAvoidVocab() {
return avoidVocab;
}

public static class Builder {

private final JsonLdConfiguration configuration = new JsonLdConfiguration();
Expand All @@ -54,6 +59,11 @@ public Builder httpsEnabled(boolean httpsEnabled) {
return this;
}

public Builder avoidVocab(boolean avoidVocab) {
configuration.avoidVocab = avoidVocab;
return this;
}

public Builder checkPrefixes(boolean checkPrefixes) {
configuration.checkPrefixes = checkPrefixes;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import static jakarta.json.Json.createBuilderFactory;
import static jakarta.json.Json.createObjectBuilder;
import static java.util.Optional.ofNullable;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;

/**
* Implementation of the {@link JsonLd} interface that uses the Titanium library for all JSON-LD operations.
Expand All @@ -66,6 +67,7 @@ public class TitaniumJsonLd implements JsonLd {
private final JsonObjectValidator validator;

private final boolean shouldCheckPrefixes;
private final boolean isVocabEnabled;

public TitaniumJsonLd(Monitor monitor) {
this(monitor, JsonLdConfiguration.Builder.newInstance().build());
Expand All @@ -75,6 +77,7 @@ public TitaniumJsonLd(Monitor monitor, JsonLdConfiguration configuration) {
this.monitor = monitor;
this.documentLoader = new CachedDocumentLoader(configuration, monitor);
this.shouldCheckPrefixes = configuration.shouldCheckPrefixes();
this.isVocabEnabled = configuration.isAvoidVocab();
this.validator = JsonObjectValidator.newValidator()
.verify((path) -> new MissingPrefixes(path, this::getAllPrefixes))
.build();
Expand Down Expand Up @@ -124,6 +127,10 @@ public Result<JsonObject> compact(JsonObject json, String scope) {

@Override
public void registerNamespace(String prefix, String contextIri, String scope) {
// skip the @vocab if it's not enabled
if (isVocabEnabled && VOCAB.equals(prefix)) {
return;
}
var namespaces = scopedNamespaces.computeIfAbsent(scope, k -> new LinkedHashMap<>());
namespaces.put(prefix, contextIri);
}
Expand All @@ -146,9 +153,9 @@ private JsonObject injectVocab(JsonObject json) {
if (json.get(JsonLdKeywords.CONTEXT) instanceof JsonObject) {
var contextObject = ofNullable(json.getJsonObject(JsonLdKeywords.CONTEXT)).orElseGet(() -> createObjectBuilder().build());
var contextBuilder = createObjectBuilder(contextObject);
if (!contextObject.containsKey(JsonLdKeywords.VOCAB)) {
if (!contextObject.containsKey(VOCAB)) {
var newContextObject = contextBuilder
.add(JsonLdKeywords.VOCAB, CoreConstants.EDC_NAMESPACE)
.add(VOCAB, CoreConstants.EDC_NAMESPACE)
.build();
jsonObjectBuilder.add(JsonLdKeywords.CONTEXT, newContextObject);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@

import static jakarta.json.Json.createArrayBuilder;
import static jakarta.json.Json.createObjectBuilder;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
import static org.mockito.Mockito.mock;

class TitaniumJsonLdTest {
Expand Down Expand Up @@ -147,6 +149,34 @@ void compact() {
});
}

@Test
void compact_withVocab() {
var expanded = Json.createObjectBuilder()
.add(EDC_NAMESPACE + "item", "test")
.build();
var jsonLd = defaultService();
jsonLd.registerNamespace(VOCAB, EDC_NAMESPACE);
var compacted = jsonLd.compact(expanded);

assertThat(compacted).isSucceeded().satisfies(c -> {
Assertions.assertThat(c.getString("item")).isEqualTo("test");
});
}

@Test
void compact_withVocabDisabled() {
var expanded = Json.createObjectBuilder()
.add(EDC_NAMESPACE + "item", "test")
.build();
var jsonLd = defaultService(JsonLdConfiguration.Builder.newInstance().avoidVocab(true).build());
jsonLd.registerNamespace(VOCAB, EDC_NAMESPACE);
var compacted = jsonLd.compact(expanded);

assertThat(compacted).isSucceeded().satisfies(c -> {
Assertions.assertThat(c.getString(EDC_NAMESPACE + "item")).isEqualTo("test");
});
}

@Test
void compact_withCustomPrefix() {
var ns = "https://test.org/schema/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import java.util.Map;

import static java.lang.String.format;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCAT_PREFIX;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCAT_SCHEMA;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCT_PREFIX;
Expand All @@ -61,6 +62,8 @@
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_PREFIX;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;
import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_SCOPE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX;
import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD;

/**
Expand Down Expand Up @@ -122,6 +125,9 @@ public void initialize(ServiceExtensionContext context) {
jsonLd.registerNamespace(DCT_PREFIX, DCT_SCHEMA, DSP_SCOPE);
jsonLd.registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, DSP_SCOPE);
jsonLd.registerNamespace(DSPACE_PREFIX, DSPACE_SCHEMA, DSP_SCOPE);
jsonLd.registerNamespace(VOCAB, EDC_NAMESPACE, DSP_SCOPE);
jsonLd.registerNamespace(EDC_PREFIX, EDC_NAMESPACE, DSP_SCOPE);


webService.registerResource(ApiContext.PROTOCOL, new ObjectMapperProvider(jsonLdMapper));
webService.registerResource(ApiContext.PROTOCOL, new JerseyJsonLdInterceptor(jsonLd, jsonLdMapper, DSP_SCOPE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

package org.eclipse.edc.protocol.dsp.http.api.configuration;

import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.eclipse.edc.spi.protocol.ProtocolWebhook;
import org.eclipse.edc.spi.system.Hostname;
Expand All @@ -36,8 +37,18 @@
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCAT_PREFIX;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCAT_SCHEMA;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCT_PREFIX;
import static org.eclipse.edc.jsonld.spi.Namespaces.DCT_SCHEMA;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_PREFIX;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;
import static org.eclipse.edc.protocol.dsp.http.api.configuration.DspApiConfigurationExtension.DSP_CALLBACK_ADDRESS;
import static org.eclipse.edc.protocol.dsp.http.api.configuration.DspApiConfigurationExtension.SETTINGS;
import static org.eclipse.edc.protocol.dsp.spi.type.DspConstants.DSP_SCOPE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
Expand All @@ -52,6 +63,8 @@ class DspApiConfigurationExtensionTest {
private final WebServer webServer = mock();
private final WebService webService = mock();
private final TypeManager typeManager = mock();
private final JsonLd jsonLd = mock();


@BeforeEach
void setUp(ServiceExtensionContext context) {
Expand All @@ -60,6 +73,7 @@ void setUp(ServiceExtensionContext context) {
context.registerService(WebServiceConfigurer.class, configurer);
context.registerService(TypeManager.class, typeManager);
context.registerService(Hostname.class, () -> "hostname");
context.registerService(JsonLd.class, jsonLd);
TypeTransformerRegistry typeTransformerRegistry = mock();
when(typeTransformerRegistry.forContext(any())).thenReturn(mock());
context.registerService(TypeTransformerRegistry.class, typeTransformerRegistry);
Expand Down Expand Up @@ -105,4 +119,16 @@ void initialize_shouldRegisterWebServiceProviders(DspApiConfigurationExtension e
verify(webService).registerResource(eq(ApiContext.PROTOCOL), isA(JerseyJsonLdInterceptor.class));
}

@Test
void initialize_shouldRegisterNamespaces(DspApiConfigurationExtension extension, ServiceExtensionContext context) {
extension.initialize(context);

verify(jsonLd).registerNamespace(DCAT_PREFIX, DCAT_SCHEMA, DSP_SCOPE);
verify(jsonLd).registerNamespace(DCT_PREFIX, DCT_SCHEMA, DSP_SCOPE);
verify(jsonLd).registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, DSP_SCOPE);
verify(jsonLd).registerNamespace(VOCAB, EDC_NAMESPACE, DSP_SCOPE);
verify(jsonLd).registerNamespace(EDC_PREFIX, EDC_NAMESPACE, DSP_SCOPE);
verify(jsonLd).registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, DSP_SCOPE);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,13 @@
import java.util.stream.Stream;

import static java.lang.String.format;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_PREFIX;
import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_SCHEMA;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_PREFIX;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX;
import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD;

/**
Expand All @@ -63,12 +66,10 @@ public class ControlApiConfigurationExtension implements ServiceExtension {

@Setting(value = "Configures endpoint for reaching the Control API. If it's missing it defaults to the hostname configuration.")
public static final String CONTROL_API_ENDPOINT = "edc.control.endpoint";

public static final String CONTROL_SCOPE = "CONTROL_API";
private static final String WEB_SERVICE_NAME = "Control API";

@SettingContext("Control API context setting key")
private static final String CONTROL_CONFIG_KEY = "web.http." + ApiContext.CONTROL;

public static final WebServiceSettings SETTINGS = WebServiceSettings.Builder.newInstance()
.apiConfigKey(CONTROL_CONFIG_KEY)
.contextAlias(ApiContext.CONTROL)
Expand All @@ -77,7 +78,6 @@ public class ControlApiConfigurationExtension implements ServiceExtension {
.useDefaultContext(true)
.name(WEB_SERVICE_NAME)
.build();
private static final String CONTROL_SCOPE = "CONTROL_API";
private static final String API_VERSION_JSON_FILE = "control-api-version.json";

@Inject
Expand Down Expand Up @@ -110,6 +110,8 @@ public void initialize(ServiceExtensionContext context) {
var jsonLdMapper = typeManager.getMapper(JSON_LD);
context.registerService(ControlApiUrl.class, controlApiUrl(context, controlApiConfiguration));

jsonLd.registerNamespace(EDC_PREFIX, EDC_NAMESPACE, CONTROL_SCOPE);
jsonLd.registerNamespace(VOCAB, EDC_NAMESPACE, CONTROL_SCOPE);
jsonLd.registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, CONTROL_SCOPE);
jsonLd.registerNamespace(DSPACE_PREFIX, DSPACE_SCHEMA, CONTROL_SCOPE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.eclipse.edc.api.auth.spi.AuthenticationRequestFilter;
import org.eclipse.edc.json.JacksonTypeManager;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.junit.extensions.DependencyInjectionExtension;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.system.Hostname;
Expand All @@ -33,6 +34,14 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.eclipse.edc.connector.api.control.configuration.ControlApiConfigurationExtension.CONTROL_API_ENDPOINT;
import static org.eclipse.edc.connector.api.control.configuration.ControlApiConfigurationExtension.CONTROL_SCOPE;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_PREFIX;
import static org.eclipse.edc.jsonld.spi.Namespaces.DSPACE_SCHEMA;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_PREFIX;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
Expand All @@ -45,6 +54,7 @@ public class ControlApiConfigurationExtensionTest {

private final WebServiceConfigurer configurator = mock();
private final WebService webService = mock();
private final JsonLd jsonLd = mock();

private final WebServiceConfiguration webServiceConfiguration = WebServiceConfiguration.Builder.newInstance()
.path("/path")
Expand All @@ -57,6 +67,7 @@ void setUp(ServiceExtensionContext context) {
context.registerService(Hostname.class, () -> "hostname");
context.registerService(WebService.class, webService);
context.registerService(TypeManager.class, new JacksonTypeManager());
context.registerService(JsonLd.class, jsonLd);

when(configurator.configure(any(), any(), any())).thenReturn(webServiceConfiguration);
}
Expand Down Expand Up @@ -98,4 +109,14 @@ void shouldRegisterAuthenticationFilter(ControlApiConfigurationExtension extensi

verify(webService).registerResource(any(), isA(AuthenticationRequestFilter.class));
}

@Test
void shouldRegisterNamespaces(ControlApiConfigurationExtension extension, ServiceExtensionContext context) {
extension.initialize(context);

jsonLd.registerNamespace(EDC_PREFIX, EDC_NAMESPACE, CONTROL_SCOPE);
jsonLd.registerNamespace(VOCAB, EDC_NAMESPACE, CONTROL_SCOPE);
jsonLd.registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, CONTROL_SCOPE);
jsonLd.registerNamespace(DSPACE_PREFIX, DSPACE_SCHEMA, CONTROL_SCOPE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,12 @@
import java.util.stream.Stream;

import static java.lang.String.format;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VOCAB;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_PREFIX;
import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_CONNECTOR_MANAGEMENT_CONTEXT;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX;
import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD;

/**
Expand All @@ -75,10 +79,10 @@ public class ManagementApiConfigurationExtension implements ServiceExtension {
public static final String API_VERSION_JSON_FILE = "management-api-version.json";
public static final String NAME = "Management API configuration";
public static final String WEB_SERVICE_NAME = "Management API";
public static final String MANAGEMENT_SCOPE = "MANAGEMENT_API";

@SettingContext("Management API context setting key")
private static final String MANAGEMENT_CONFIG_KEY = "web.http." + ApiContext.MANAGEMENT;

public static final WebServiceSettings SETTINGS = WebServiceSettings.Builder.newInstance()
.apiConfigKey(MANAGEMENT_CONFIG_KEY)
.contextAlias(ApiContext.MANAGEMENT)
Expand All @@ -87,11 +91,14 @@ public class ManagementApiConfigurationExtension implements ServiceExtension {
.useDefaultContext(true)
.name(WEB_SERVICE_NAME)
.build();
private static final String MANAGEMENT_SCOPE = "MANAGEMENT_API";

@Setting(value = "Configures endpoint for reaching the Management API.", defaultValue = "<hostname:management.port/management.path>")
private static final String MANAGEMENT_API_ENDPOINT = "edc.management.endpoint";

private static final boolean DEFAULT_MANAGEMENT_API_ENABLE_CONTEXT = false;

@Setting(value = "If set enable the usage of management api JSON-LD context.", defaultValue = "" + DEFAULT_MANAGEMENT_API_ENABLE_CONTEXT)
private static final String MANAGEMENT_API_ENABLE_CONTEXT = "edc.management.context.enabled";

@Inject
private WebService webService;
@Inject
Expand Down Expand Up @@ -129,7 +136,16 @@ public void initialize(ServiceExtensionContext context) {
var authenticationFilter = new AuthenticationRequestFilter(authenticationRegistry, "management-api");
webService.registerResource(ApiContext.MANAGEMENT, authenticationFilter);

jsonLd.registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, MANAGEMENT_SCOPE);
var isManagementContextEnabled = context.getSetting(MANAGEMENT_API_ENABLE_CONTEXT, DEFAULT_MANAGEMENT_API_ENABLE_CONTEXT);

if (isManagementContextEnabled) {
jsonLd.registerContext(EDC_CONNECTOR_MANAGEMENT_CONTEXT, MANAGEMENT_SCOPE);
} else {
jsonLd.registerNamespace(VOCAB, EDC_NAMESPACE, MANAGEMENT_SCOPE);
jsonLd.registerNamespace(EDC_PREFIX, EDC_NAMESPACE, MANAGEMENT_SCOPE);
jsonLd.registerNamespace(ODRL_PREFIX, ODRL_SCHEMA, MANAGEMENT_SCOPE);
}

var jsonLdMapper = typeManager.getMapper(JSON_LD);
webService.registerResource(ApiContext.MANAGEMENT, new ObjectMapperProvider(jsonLdMapper));
webService.registerResource(ApiContext.MANAGEMENT, new JerseyJsonLdInterceptor(jsonLd, jsonLdMapper, MANAGEMENT_SCOPE));
Expand Down
Loading

0 comments on commit 7b3c28e

Please sign in to comment.