diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java index 77257b298f8..3dc2da93803 100644 --- a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/ControlPlaneServicesExtension.java @@ -41,6 +41,7 @@ import org.eclipse.edc.connector.controlplane.services.policydefinition.PolicyDefinitionServiceImpl; import org.eclipse.edc.connector.controlplane.services.protocol.ProtocolTokenValidatorImpl; import org.eclipse.edc.connector.controlplane.services.protocol.VersionProtocolServiceImpl; +import org.eclipse.edc.connector.controlplane.services.protocol.VersionServiceImpl; import org.eclipse.edc.connector.controlplane.services.query.QueryValidators; import org.eclipse.edc.connector.controlplane.services.secret.SecretEventListener; import org.eclipse.edc.connector.controlplane.services.secret.SecretServiceImpl; @@ -55,6 +56,7 @@ import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolTokenValidator; import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolVersionRegistry; import org.eclipse.edc.connector.controlplane.services.spi.protocol.VersionProtocolService; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.VersionService; import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessProtocolService; import org.eclipse.edc.connector.controlplane.services.spi.transferprocess.TransferProcessService; import org.eclipse.edc.connector.controlplane.services.transferprocess.TransferProcessProtocolServiceImpl; @@ -287,4 +289,9 @@ public VersionProtocolService versionProtocolService() { return new VersionProtocolServiceImpl(protocolVersionRegistry, protocolTokenValidator()); } + @Provider + public VersionService versionService() { + return new VersionServiceImpl(dispatcher); + } + } diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/protocol/VersionServiceImpl.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/protocol/VersionServiceImpl.java new file mode 100644 index 00000000000..ff54d09c8dd --- /dev/null +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/controlplane/services/protocol/VersionServiceImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.services.protocol; + +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequestMessage; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.VersionService; +import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; +import org.eclipse.edc.spi.response.StatusResult; + +import java.util.concurrent.CompletableFuture; + +public class VersionServiceImpl implements VersionService { + + private final RemoteMessageDispatcherRegistry dispatcher; + + public VersionServiceImpl(RemoteMessageDispatcherRegistry dispatcher) { + this.dispatcher = dispatcher; + } + + @Override + public CompletableFuture> requestVersions(ProtocolVersionRequest request) { + var message = ProtocolVersionRequestMessage.Builder.newInstance() + .protocol(request.getProtocol()) + .counterPartyId(request.getCounterPartyId()) + .counterPartyAddress(request.getCounterPartyAddress()) + .build(); + + return dispatcher.dispatch(byte[].class, message); + } +} diff --git a/data-protocols/dsp/build.gradle.kts b/data-protocols/dsp/build.gradle.kts index bc99aaab2a8..937bbe24916 100644 --- a/data-protocols/dsp/build.gradle.kts +++ b/data-protocols/dsp/build.gradle.kts @@ -24,5 +24,5 @@ dependencies { api(project(":data-protocols:dsp:dsp-http-spi")) api(project(":data-protocols:dsp:dsp-negotiation")) api(project(":data-protocols:dsp:dsp-transfer-process")) - api(project(":data-protocols:dsp:dsp-version:dsp-version-http-api")) + api(project(":data-protocols:dsp:dsp-version")) } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/DspCatalogHttpDispatcherExtension.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/DspCatalogHttpDispatcherExtension.java index 2c43c33477d..1d49f60f92f 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/DspCatalogHttpDispatcherExtension.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/DspCatalogHttpDispatcherExtension.java @@ -16,9 +16,9 @@ import org.eclipse.edc.connector.controlplane.catalog.spi.CatalogRequestMessage; import org.eclipse.edc.connector.controlplane.catalog.spi.DatasetRequestMessage; -import org.eclipse.edc.protocol.dsp.catalog.http.dispatcher.delegate.ByteArrayBodyExtractor; import org.eclipse.edc.protocol.dsp.http.dispatcher.GetDspHttpRequestFactory; import org.eclipse.edc.protocol.dsp.http.dispatcher.PostDspHttpRequestFactory; +import org.eclipse.edc.protocol.dsp.http.serialization.ByteArrayBodyExtractor; import org.eclipse.edc.protocol.dsp.http.spi.DspProtocolParser; import org.eclipse.edc.protocol.dsp.http.spi.dispatcher.DspHttpRemoteMessageDispatcher; import org.eclipse.edc.protocol.dsp.http.spi.serialization.JsonLdRemoteMessageSerializer; diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/DspHttpCoreExtension.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/DspHttpCoreExtension.java index 1839800311d..4a128f6e018 100644 --- a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/DspHttpCoreExtension.java +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/DspHttpCoreExtension.java @@ -22,6 +22,7 @@ import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiationTerminationMessage; import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractRequestMessage; import org.eclipse.edc.connector.controlplane.contract.spi.types.protocol.ContractRemoteMessage; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequestMessage; import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolVersionRegistry; import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferCompletionMessage; import org.eclipse.edc.connector.controlplane.transfer.spi.types.protocol.TransferRemoteMessage; @@ -136,6 +137,7 @@ public DspHttpRemoteMessageDispatcher dspHttpRemoteMessageDispatcher(ServiceExte registerNegotiationPolicyScopes(dispatcher); registerTransferProcessPolicyScopes(dispatcher); registerCatalogPolicyScopes(dispatcher); + registerVersionPolicyScopes(dispatcher); dispatcherRegistry.register(DATASPACE_PROTOCOL_HTTP, dispatcher); dispatcherRegistry.register(DATASPACE_PROTOCOL_HTTP_V_2024_1, dispatcher); return dispatcher; @@ -187,4 +189,8 @@ private void registerCatalogPolicyScopes(DspHttpRemoteMessageDispatcher dispatch dispatcher.registerPolicyScope(CatalogRequestMessage.class, CatalogRequestMessage::getPolicy, RequestCatalogPolicyContext::new); dispatcher.registerPolicyScope(DatasetRequestMessage.class, DatasetRequestMessage::getPolicy, RequestCatalogPolicyContext::new); } + + private void registerVersionPolicyScopes(DspHttpRemoteMessageDispatcher dispatcher) { + dispatcher.registerPolicyScope(ProtocolVersionRequestMessage.class, ProtocolVersionRequestMessage::getPolicy, RequestVersionPolicyContext::new); + } } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/delegate/ByteArrayBodyExtractor.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/serialization/ByteArrayBodyExtractor.java similarity index 94% rename from data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/delegate/ByteArrayBodyExtractor.java rename to data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/serialization/ByteArrayBodyExtractor.java index 913618e25d2..82de15c3b82 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/delegate/ByteArrayBodyExtractor.java +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/http/serialization/ByteArrayBodyExtractor.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.protocol.dsp.catalog.http.dispatcher.delegate; +package org.eclipse.edc.protocol.dsp.http.serialization; import okhttp3.ResponseBody; import org.eclipse.edc.protocol.dsp.http.spi.dispatcher.response.DspHttpResponseBodyExtractor; diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/delegate/ByteArrayBodyExtractorTest.java b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/http/serialization/ByteArrayBodyExtractorTest.java similarity index 96% rename from data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/delegate/ByteArrayBodyExtractorTest.java rename to data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/http/serialization/ByteArrayBodyExtractorTest.java index 8b72e284b3a..ee1f2ac93a1 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/http/dispatcher/delegate/ByteArrayBodyExtractorTest.java +++ b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/http/serialization/ByteArrayBodyExtractorTest.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.protocol.dsp.catalog.http.dispatcher.delegate; +package org.eclipse.edc.protocol.dsp.http.serialization; import okhttp3.ResponseBody; import org.eclipse.edc.spi.EdcException; diff --git a/data-protocols/dsp/dsp-version/build.gradle.kts b/data-protocols/dsp/dsp-version/build.gradle.kts new file mode 100644 index 00000000000..928fed8f8a9 --- /dev/null +++ b/data-protocols/dsp/dsp-version/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + + +plugins { + `java-library` +} + +dependencies { + api(project(":data-protocols:dsp:dsp-version:dsp-version-http-api")) + api(project(":data-protocols:dsp:dsp-version:dsp-version-http-dispatcher")) +} diff --git a/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/build.gradle.kts b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/build.gradle.kts new file mode 100644 index 00000000000..ae4a8c66561 --- /dev/null +++ b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/build.gradle.kts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +plugins { + `java-library` +} + +dependencies { + api(project(":data-protocols:dsp:dsp-http-core")) + api(project(":data-protocols:dsp:dsp-http-spi")) + api(project(":spi:control-plane:protocol-version-spi")) + + testImplementation(testFixtures(project(":data-protocols:dsp:dsp-http-spi"))) +} diff --git a/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/version/http/dispatcher/DspVersionHttpDispatcherExtension.java b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/version/http/dispatcher/DspVersionHttpDispatcherExtension.java new file mode 100644 index 00000000000..7b38156be27 --- /dev/null +++ b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/version/http/dispatcher/DspVersionHttpDispatcherExtension.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.protocol.dsp.version.http.dispatcher; + +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequestMessage; +import org.eclipse.edc.protocol.dsp.http.dispatcher.GetDspHttpRequestFactory; +import org.eclipse.edc.protocol.dsp.http.serialization.ByteArrayBodyExtractor; +import org.eclipse.edc.protocol.dsp.http.spi.DspProtocolParser; +import org.eclipse.edc.protocol.dsp.http.spi.dispatcher.DspHttpRemoteMessageDispatcher; +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + +import static org.eclipse.edc.protocol.dsp.version.http.dispatcher.VersionApiPaths.PATH; + +/** + * Creates and registers the HTTP dispatcher delegate for sending a version request as defined in + * the dataspace protocol specification. + */ +@Extension(value = DspVersionHttpDispatcherExtension.NAME) +public class DspVersionHttpDispatcherExtension implements ServiceExtension { + + public static final String NAME = "Dataspace Protocol Version HTTP Dispatcher Extension"; + + @Inject + private DspHttpRemoteMessageDispatcher messageDispatcher; + + @Inject + private DspProtocolParser dspProtocolParser; + + @Override + public String name() { + return NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + var byteArrayBodyExtractor = new ByteArrayBodyExtractor(); + + messageDispatcher.registerMessage( + ProtocolVersionRequestMessage.class, + new GetDspHttpRequestFactory<>(dspProtocolParser, m -> PATH), + byteArrayBodyExtractor + ); + } + +} diff --git a/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/version/http/dispatcher/VersionApiPaths.java b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/version/http/dispatcher/VersionApiPaths.java new file mode 100644 index 00000000000..13bc643c562 --- /dev/null +++ b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/version/http/dispatcher/VersionApiPaths.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.protocol.dsp.version.http.dispatcher; + +/** + * API paths for version requests as defined in the dataspace protocol specification. + */ +public interface VersionApiPaths { + + String PATH = "/.well-known/dspace-version"; + +} diff --git a/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 00000000000..203ef52a5a9 --- /dev/null +++ b/data-protocols/dsp/dsp-version/dsp-version-http-dispatcher/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# +# Contributors: +# Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation +# +# + +org.eclipse.edc.protocol.dsp.version.http.dispatcher.DspVersionHttpDispatcherExtension \ No newline at end of file diff --git a/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json b/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json index 9a07bec56af..0ae5090c203 100644 --- a/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json +++ b/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json @@ -14,7 +14,7 @@ { "version": "4.0.0-alpha", "urlPath": "/v4alpha", - "lastUpdated": "2024-11-21T14:24:00Z", + "lastUpdated": "2024-12-04T14:24:00Z", "maturity": "alpha" } ] diff --git a/extensions/control-plane/api/management-api/build.gradle.kts b/extensions/control-plane/api/management-api/build.gradle.kts index 2a8a818bbf3..7a96355cf8a 100644 --- a/extensions/control-plane/api/management-api/build.gradle.kts +++ b/extensions/control-plane/api/management-api/build.gradle.kts @@ -27,6 +27,7 @@ dependencies { api(project(":extensions:control-plane:api:management-api:edr-cache-api")) api(project(":extensions:control-plane:api:management-api:policy-definition-api")) api(project(":extensions:control-plane:api:management-api:transfer-process-api")) + api(project(":extensions:control-plane:api:management-api:protocol-version-api")) } diff --git a/extensions/control-plane/api/management-api/protocol-version-api/build.gradle.kts b/extensions/control-plane/api/management-api/protocol-version-api/build.gradle.kts new file mode 100644 index 00000000000..cfa81ec99dc --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/build.gradle.kts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ +plugins { + `java-library` + id(libs.plugins.swagger.get().pluginId) +} + +dependencies { + api(project(":spi:control-plane:control-plane-spi")) + + implementation(project(":core:common:lib:validator-lib")) + implementation(project(":extensions:common:api:api-core")) + implementation(project(":extensions:common:api:lib:management-api-lib")) + + implementation(libs.jakarta.rsApi) + + testImplementation(project(":core:common:junit")) + testImplementation(project(":core:common:lib:transform-lib")) + testImplementation(project(":core:control-plane:control-plane-core")) + testImplementation(project(":core:data-plane-selector:data-plane-selector-core")) + testImplementation(project(":extensions:common:http")) + testImplementation(project(":extensions:common:iam:iam-mock")) + testImplementation(testFixtures(project(":extensions:common:http:jersey-core"))) + testImplementation(libs.restAssured) +} + +edcBuild { + swagger { + apiGroup.set("management-api") + } +} + + diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiExtension.java b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiExtension.java new file mode 100644 index 00000000000..05c892f87c3 --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiExtension.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion; + +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.transform.JsonObjectToProtocolVersionRequestTransformer; +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha.ProtocolVersionApiV4AlphaController; +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.validation.ProtocolVersionRequestValidator; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.VersionService; +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.query.CriterionOperatorRegistry; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; +import org.eclipse.edc.web.spi.WebService; +import org.eclipse.edc.web.spi.configuration.ApiContext; + +import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_API_CONTEXT; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_TYPE; + +@Extension(value = ProtocolVersionApiExtension.NAME) +public class ProtocolVersionApiExtension implements ServiceExtension { + + public static final String NAME = "Management API: Protocol Version"; + + @Inject + private WebService webService; + + @Inject + private TypeTransformerRegistry transformerRegistry; + + @Inject + private VersionService service; + + @Inject + private JsonObjectValidatorRegistry validatorRegistry; + + @Inject + private CriterionOperatorRegistry criterionOperatorRegistry; + + @Override + public String name() { + return NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + + var managementApiTransformerRegistry = transformerRegistry.forContext(MANAGEMENT_API_CONTEXT); + managementApiTransformerRegistry.register(new JsonObjectToProtocolVersionRequestTransformer()); + + webService.registerResource(ApiContext.MANAGEMENT, new ProtocolVersionApiV4AlphaController(service, managementApiTransformerRegistry, validatorRegistry)); + validatorRegistry.register(PROTOCOL_VERSION_REQUEST_TYPE, ProtocolVersionRequestValidator.instance()); + + } +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/transform/JsonObjectToProtocolVersionRequestTransformer.java b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/transform/JsonObjectToProtocolVersionRequestTransformer.java new file mode 100644 index 00000000000..d0a06d4c4a2 --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/transform/JsonObjectToProtocolVersionRequestTransformer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.transform; + +import jakarta.json.JsonObject; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.jsonld.spi.transformer.AbstractJsonLdTransformer; +import org.eclipse.edc.transform.spi.TransformerContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.Builder; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_PROTOCOL; + +public class JsonObjectToProtocolVersionRequestTransformer extends AbstractJsonLdTransformer { + + public JsonObjectToProtocolVersionRequestTransformer() { + super(JsonObject.class, ProtocolVersionRequest.class); + } + + @Override + public @Nullable ProtocolVersionRequest transform(@NotNull JsonObject object, @NotNull TransformerContext context) { + var counterPartyAddress = transformString(object.get(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS), context); + var counterPartyId = transformString(object.get(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID), context); + var protocol = transformString(object.get(PROTOCOL_VERSION_REQUEST_PROTOCOL), context); + + var builder = Builder.newInstance() + .protocol(protocol) + .counterPartyAddress(counterPartyAddress) + .counterPartyId(counterPartyId); + + return builder.build(); + } + +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionApiV4AlphaController.java b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionApiV4AlphaController.java new file mode 100644 index 00000000000..0091e183e25 --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionApiV4AlphaController.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha; + +import jakarta.json.JsonObject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.VersionService; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.response.StatusResult; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; +import org.eclipse.edc.web.spi.exception.BadGatewayException; +import org.eclipse.edc.web.spi.exception.InvalidRequestException; +import org.eclipse.edc.web.spi.exception.ValidationFailureException; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_TYPE; + +@Consumes(APPLICATION_JSON) +@Produces(APPLICATION_JSON) +@Path("/v4alpha/protocol-versions") +public class ProtocolVersionApiV4AlphaController implements ProtocolVersionApiV4alpha { + private final VersionService service; + private final TypeTransformerRegistry transformerRegistry; + private final JsonObjectValidatorRegistry validatorRegistry; + + public ProtocolVersionApiV4AlphaController(VersionService service, TypeTransformerRegistry transformerRegistry, JsonObjectValidatorRegistry validatorRegistry) { + this.service = service; + this.transformerRegistry = transformerRegistry; + this.validatorRegistry = validatorRegistry; + } + + @POST + @Path("/request") + @Override + public void requestProtocolVersionV4alpha(JsonObject requestBody, @Suspended AsyncResponse response) { + validatorRegistry.validate(PROTOCOL_VERSION_REQUEST_TYPE, requestBody).orElseThrow(ValidationFailureException::new); + + var request = transformerRegistry.transform(requestBody, ProtocolVersionRequest.class) + .orElseThrow(InvalidRequestException::new); + + service.requestVersions(request) + .whenComplete((result, throwable) -> { + try { + response.resume(toResponse(result, throwable)); + } catch (Throwable mapped) { + response.resume(mapped); + } + }); + } + + private byte[] toResponse(StatusResult result, Throwable throwable) throws Throwable { + if (throwable == null) { + if (result.succeeded()) { + return result.getContent(); + } else { + throw new BadGatewayException(result.getFailureDetail()); + } + } else { + if (throwable instanceof EdcException || throwable.getCause() instanceof EdcException) { + throw new BadGatewayException(throwable.getMessage()); + } else { + throw throwable; + } + } + } + +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionApiV4alpha.java b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionApiV4alpha.java new file mode 100644 index 00000000000..ed2f8cba29b --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionApiV4alpha.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.json.JsonObject; +import jakarta.ws.rs.container.AsyncResponse; +import jakarta.ws.rs.container.Suspended; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; +import static org.eclipse.edc.connector.controlplane.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; + +@OpenAPIDefinition(info = @Info(version = "v4alpha")) +@Tag(name = "Protocol Version v4alpha") +public interface ProtocolVersionApiV4alpha { + + @Operation( + requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = ProtocolVersionRequestSchema.class))), + responses = { @ApiResponse( + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ProtocolVersionSchema.class) + ), + description = "Gets supported protocol versions of a single connector") } + ) + void requestProtocolVersionV4alpha(JsonObject request, @Suspended AsyncResponse response); + + @Schema(name = "CatalogRequest", example = ProtocolVersionRequestSchema.PROTOCOL_VERSION_REQUEST_EXAMPLE) + record ProtocolVersionRequestSchema( + @Schema(name = CONTEXT, requiredMode = REQUIRED) + Object context, + @Schema(name = TYPE, example = CATALOG_REQUEST_TYPE) + String type, + @Schema(requiredMode = REQUIRED) + String counterPartyAddress, + @Schema(requiredMode = REQUIRED) + String counterPartyId, + @Schema(requiredMode = REQUIRED) + String protocol) { + + public static final String PROTOCOL_VERSION_REQUEST_EXAMPLE = """ + { + "@context": { "@vocab": "https://w3id.org/edc/v0.0.1/ns/" }, + "@type": "ProtocolVersionRequest", + "counterPartyAddress": "http://provider-address", + "counterPartyId": "providerId", + "protocol": "dataspace-protocol-http" + } + """; + } + + @Schema(name = "Protocol Version", description = "Protocol Version", example = ProtocolVersionSchema.PROTOCOL_VERSION_EXAMPLE) + record ProtocolVersionSchema( + ) { + public static final String PROTOCOL_VERSION_EXAMPLE = """ + { + "protocolVersions": [ + { + "version": "2024/1", + "path": "/2024/1" + }, + { + "version": "v0.8", + "path": "/" + } + ] + } + """; + } + +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/validation/ProtocolVersionRequestValidator.java b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/validation/ProtocolVersionRequestValidator.java new file mode 100644 index 00000000000..0ea2803499a --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/main/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/validation/ProtocolVersionRequestValidator.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.validation; + +import jakarta.json.JsonObject; +import org.eclipse.edc.validator.jsonobject.JsonObjectValidator; +import org.eclipse.edc.validator.jsonobject.validators.MandatoryValue; +import org.eclipse.edc.validator.spi.Validator; + +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_PROTOCOL; + +public class ProtocolVersionRequestValidator { + + public static Validator instance() { + return JsonObjectValidator.newValidator() + .verify(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS, MandatoryValue::new) + .verify(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID, MandatoryValue::new) + .verify(PROTOCOL_VERSION_REQUEST_PROTOCOL, MandatoryValue::new) + .build(); + } + +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/control-plane/api/management-api/protocol-version-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 00000000000..2234e9ee4b2 --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# +# Contributors: +# Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation +# +# + +org.eclipse.edc.connector.controlplane.api.management.protocolversion.ProtocolVersionApiExtension diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiExtensionTest.java b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiExtensionTest.java new file mode 100644 index 00000000000..f377ff8a222 --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiExtensionTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion; + +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.transform.JsonObjectToProtocolVersionRequestTransformer; +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha.ProtocolVersionApiV4AlphaController; +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; +import org.eclipse.edc.web.spi.WebService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.eclipse.edc.api.management.ManagementApi.MANAGEMENT_API_CONTEXT; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_TYPE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(DependencyInjectionExtension.class) +class ProtocolVersionApiExtensionTest { + + private final JsonObjectValidatorRegistry validatorRegistry = mock(); + private final WebService webService = mock(WebService.class); + private final TypeTransformerRegistry transformerRegistry = mock(TypeTransformerRegistry.class); + private final TypeTransformerRegistry managementApiTransformer = mock(TypeTransformerRegistry.class); + + @BeforeEach + void setUp(ServiceExtensionContext context) { + context.registerService(JsonObjectValidatorRegistry.class, validatorRegistry); + context.registerService(WebService.class, webService); + context.registerService(TypeTransformerRegistry.class, transformerRegistry); + + when(transformerRegistry.forContext(MANAGEMENT_API_CONTEXT)).thenReturn(managementApiTransformer); + } + + @Test + void initiate_shouldRegisterValidators(ProtocolVersionApiExtension extension, ServiceExtensionContext context) { + extension.initialize(context); + + verify(validatorRegistry).register(eq(PROTOCOL_VERSION_REQUEST_TYPE), any()); + } + + @Test + void initiate_shouldRegisterControllers(ProtocolVersionApiExtension extension, ServiceExtensionContext context) { + extension.initialize(context); + + verify(webService).registerResource(any(), isA(ProtocolVersionApiV4AlphaController.class)); + } + + + @Test + void initiate_shouldRegisterTransformers(ProtocolVersionApiExtension extension, ServiceExtensionContext context) { + extension.initialize(context); + + verify(managementApiTransformer).register(isA(JsonObjectToProtocolVersionRequestTransformer.class)); + } +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiTest.java b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiTest.java new file mode 100644 index 00000000000..343907c862b --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/ProtocolVersionApiTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.json.JsonObject; +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.transform.JsonObjectToProtocolVersionRequestTransformer; +import org.eclipse.edc.connector.controlplane.api.management.protocolversion.validation.ProtocolVersionRequestValidator; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.jsonld.JsonLdExtension; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.eclipse.edc.transform.TypeTransformerRegistryImpl; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha.ProtocolVersionApiV4alpha.ProtocolVersionRequestSchema.PROTOCOL_VERSION_REQUEST_EXAMPLE; +import static org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha.ProtocolVersionApiV4alpha.ProtocolVersionSchema.PROTOCOL_VERSION_EXAMPLE; +import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; +import static org.eclipse.edc.junit.extensions.TestServiceExtensionContext.testServiceExtensionContext; + +class ProtocolVersionApiTest { + + private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); + private final TypeTransformerRegistry transformer = new TypeTransformerRegistryImpl(); + private final JsonLd jsonLd = new JsonLdExtension().createJsonLdService(testServiceExtensionContext()); + + @BeforeEach + void setUp() { + transformer.register(new JsonObjectToProtocolVersionRequestTransformer()); + } + + @Test + void protocolVersionsRequestExample() throws JsonProcessingException { + var validator = ProtocolVersionRequestValidator.instance(); + + var jsonObject = objectMapper.readValue(PROTOCOL_VERSION_REQUEST_EXAMPLE, JsonObject.class); + assertThat(jsonObject).isNotNull(); + + var expanded = jsonLd.expand(jsonObject); + assertThat(expanded).isSucceeded() + .satisfies(exp -> assertThat(validator.validate(exp)).isSucceeded()) + .extracting(e -> transformer.transform(e, ProtocolVersionRequest.class)) + .satisfies(transformResult -> assertThat(transformResult).isSucceeded() + .satisfies(transformed -> { + assertThat(transformed.getProtocol()).isNotBlank(); + assertThat(transformed.getCounterPartyAddress()).isNotBlank(); + assertThat(transformed.getCounterPartyId()).isNotBlank(); + })); + } + + @Test + void protocolVersionsResponseExample() throws JsonProcessingException { + var jsonObject = objectMapper.readValue(PROTOCOL_VERSION_EXAMPLE, JsonObject.class); + + assertThat(jsonObject.getJsonArray("protocolVersions")) + .isNotNull() + .extracting(List::size) + .isEqualTo(2); + + } + +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/transform/JsonObjectToProtocolVersionRequestTransformerTest.java b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/transform/JsonObjectToProtocolVersionRequestTransformerTest.java new file mode 100644 index 00000000000..3e2dade9d8b --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/transform/JsonObjectToProtocolVersionRequestTransformerTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.transform; + +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.transform.spi.TransformerContext; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_PROTOCOL; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.mockito.Mockito.mock; + +class JsonObjectToProtocolVersionRequestTransformerTest { + + private final TransformerContext context = mock(); + private final JsonObjectToProtocolVersionRequestTransformer transformer = new JsonObjectToProtocolVersionRequestTransformer(); + + @Test + void types() { + assertThat(transformer.getInputType()).isEqualTo(JsonObject.class); + assertThat(transformer.getOutputType()).isEqualTo(ProtocolVersionRequest.class); + } + + @Test + void transform() { + var json = Json.createObjectBuilder() + .add(TYPE, ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_TYPE) + .add(PROTOCOL_VERSION_REQUEST_PROTOCOL, "protocol") + .add(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID, "counterPartyId") + .add(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS, "http://provider/url") + .build(); + + var result = transformer.transform(json, context); + + assertThat(result).isNotNull(); + assertThat(result.getProtocol()).isEqualTo("protocol"); + assertThat(result.getCounterPartyAddress()).isEqualTo("http://provider/url"); + assertThat(result.getCounterPartyId()).isEqualTo("counterPartyId"); + } + +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionV4AlphaApiControllerTest.java b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionV4AlphaApiControllerTest.java new file mode 100644 index 00000000000..a2650a3f02b --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/v4alpha/ProtocolVersionV4AlphaApiControllerTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.v4alpha; + +import jakarta.json.Json; +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.VersionService; +import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.response.StatusResult; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; +import org.eclipse.edc.validator.spi.ValidationResult; +import org.eclipse.edc.validator.spi.Violation; +import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.given; +import static io.restassured.http.ContentType.JSON; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.CompletableFuture.failedFuture; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.Builder; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_PROTOCOL; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_TYPE; +import static org.eclipse.edc.spi.response.ResponseStatus.FATAL_ERROR; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +@ApiTest +public class ProtocolVersionV4AlphaApiControllerTest extends RestControllerTestBase { + + protected final VersionService service = mock(); + protected final TypeTransformerRegistry transformerRegistry = mock(); + protected final JsonObjectValidatorRegistry validatorRegistry = mock(); + + @Test + void requestVersions() { + var request = Builder.newInstance().counterPartyAddress("http://url").build(); + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(ProtocolVersionRequest.class))).thenReturn(Result.success(request)); + when(service.requestVersions(any())).thenReturn(completedFuture(StatusResult.success("{}".getBytes()))); + var requestBody = Json.createObjectBuilder().add(PROTOCOL_VERSION_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v4alpha/protocol-versions/request") + .then() + .statusCode(200) + .contentType(JSON); + verify(transformerRegistry).transform(any(), eq(ProtocolVersionRequest.class)); + } + + @Test + void requestVersions_shouldReturnBadRequest_whenValidationFails() { + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.failure(Violation.violation("error", "path"))); + var requestBody = Json.createObjectBuilder().add(PROTOCOL_VERSION_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v4alpha/protocol-versions/request") + .then() + .statusCode(400); + verify(validatorRegistry).validate(eq(PROTOCOL_VERSION_REQUEST_TYPE), any()); + verifyNoInteractions(transformerRegistry, service); + } + + @Test + void requestVersions_shouldReturnBadRequest_whenTransformFails() { + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(ProtocolVersionRequest.class))).thenReturn(Result.failure("error")); + var requestBody = Json.createObjectBuilder().add(PROTOCOL_VERSION_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("v4alpha/protocol-versions/request") + .then() + .statusCode(400); + verifyNoInteractions(service); + } + + @Test + void requestVersions_shouldReturnBadGateway_whenServiceFails() { + var request = Builder.newInstance().counterPartyAddress("http://url").build(); + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(ProtocolVersionRequest.class))).thenReturn(Result.success(request)); + when(service.requestVersions(any())).thenReturn(completedFuture(StatusResult.failure(FATAL_ERROR, "error"))); + + var requestBody = Json.createObjectBuilder().add(PROTOCOL_VERSION_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("v4alpha/protocol-versions/request") + .then() + .statusCode(502); + } + + @Test + void requestVersions_shouldReturnBadGateway_whenServiceThrowsException() { + var request = Builder.newInstance().counterPartyAddress("http://url").build(); + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(ProtocolVersionRequest.class))).thenReturn(Result.success(request)); + when(service.requestVersions(any())).thenReturn(failedFuture(new EdcException("error"))); + var requestBody = Json.createObjectBuilder().add(PROTOCOL_VERSION_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("v4alpha/protocol-versions/request") + .then() + .statusCode(502); + } + + @Override + protected Object controller() { + return new ProtocolVersionApiV4AlphaController(service, transformerRegistry, validatorRegistry); + } +} diff --git a/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/validation/ProtocolVersionRequestValidatorTest.java b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/validation/ProtocolVersionRequestValidatorTest.java new file mode 100644 index 00000000000..bdd954de548 --- /dev/null +++ b/extensions/control-plane/api/management-api/protocol-version-api/src/test/java/org/eclipse/edc/connector/controlplane/api/management/protocolversion/validation/ProtocolVersionRequestValidatorTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.api.management.protocolversion.validation; + +import jakarta.json.Json; +import jakarta.json.JsonArrayBuilder; +import jakarta.json.JsonObject; +import org.eclipse.edc.validator.spi.ValidationFailure; +import org.eclipse.edc.validator.spi.Validator; +import org.eclipse.edc.validator.spi.Violation; +import org.junit.jupiter.api.Test; + +import static jakarta.json.Json.createArrayBuilder; +import static jakarta.json.Json.createObjectBuilder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.InstanceOfAssertFactories.list; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID; +import static org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest.PROTOCOL_VERSION_REQUEST_PROTOCOL; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VALUE; +import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; + +class ProtocolVersionRequestValidatorTest { + + private final Validator validator = ProtocolVersionRequestValidator.instance(); + + @Test + void shouldSucceed_whenInputIsValid() { + var input = Json.createObjectBuilder() + .add(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS, value("http://any")) + .add(PROTOCOL_VERSION_REQUEST_PROTOCOL, value("protocol")) + .add(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID, value("counterPartyId")) + .build(); + + var result = validator.validate(input); + + assertThat(result).isSucceeded(); + } + + @Test + void shouldFail_whenMandatoryFieldsAreMissing() { + var input = Json.createObjectBuilder().build(); + + var result = validator.validate(input); + + assertThat(result).isFailed().extracting(ValidationFailure::getViolations).asInstanceOf(list(Violation.class)) + .hasSize(3) + .anySatisfy(v -> assertThat(v.path()).isEqualTo(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS)) + .anySatisfy(v -> assertThat(v.path()).isEqualTo(PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID)) + .anySatisfy(v -> assertThat(v.path()).isEqualTo(PROTOCOL_VERSION_REQUEST_PROTOCOL)); + } + + private JsonArrayBuilder value(String value) { + return createArrayBuilder().add(createObjectBuilder().add(VALUE, value)); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index f8e81ba97d8..814a17efa3c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -104,6 +104,7 @@ include(":data-protocols:dsp:dsp-transfer-process:dsp-transfer-process-transform include(":data-protocols:dsp:dsp-transfer-process:lib:dsp-transfer-process-validation-lib") include(":data-protocols:dsp:dsp-transfer-process:lib:dsp-transfer-process-transform-lib") include(":data-protocols:dsp:dsp-version:dsp-version-http-api") +include(":data-protocols:dsp:dsp-version:dsp-version-http-dispatcher") // modules for technology- or cloud-provider extensions -------------------------------------------- include(":extensions:common:api:api-core") @@ -184,6 +185,7 @@ include(":extensions:control-plane:api:management-api:management-api-test-fixtur include(":extensions:control-plane:api:management-api:policy-definition-api") include(":extensions:control-plane:api:management-api:transfer-process-api") include(":extensions:control-plane:api:management-api:edr-cache-api") +include(":extensions:control-plane:api:management-api:protocol-version-api") include(":extensions:control-plane:transfer:transfer-data-plane-signaling") include(":extensions:control-plane:transfer:transfer-pull-http-receiver") include(":extensions:control-plane:transfer:transfer-pull-http-dynamic-receiver") @@ -266,6 +268,8 @@ include(":spi:control-plane:policy-spi") include(":spi:control-plane:transfer-spi") include(":spi:control-plane:secrets-spi") include(":spi:control-plane:control-plane-api-client-spi") +include(":spi:control-plane:protocol-version-spi") + include(":spi:data-plane:data-plane-spi") include(":spi:data-plane:data-plane-http-spi") @@ -305,4 +309,4 @@ include(":dist:bom:dataplane-feature-sql-bom") include(":dist:bom:sts-feature-bom") -include(":version-catalog") +include(":version-catalog") \ No newline at end of file diff --git a/spi/control-plane/control-plane-spi/build.gradle.kts b/spi/control-plane/control-plane-spi/build.gradle.kts index 1a2b66aeb44..0509100b33a 100644 --- a/spi/control-plane/control-plane-spi/build.gradle.kts +++ b/spi/control-plane/control-plane-spi/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { api(project(":spi:control-plane:catalog-spi")) api(project(":spi:control-plane:contract-spi")) api(project(":spi:control-plane:transfer-spi")) + api(project(":spi:control-plane:protocol-version-spi")) } diff --git a/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/controlplane/services/spi/protocol/VersionService.java b/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/controlplane/services/spi/protocol/VersionService.java new file mode 100644 index 00000000000..0f0b8b7eebb --- /dev/null +++ b/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/controlplane/services/spi/protocol/VersionService.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.services.spi.protocol; + +import org.eclipse.edc.connector.controlplane.protocolversion.spi.ProtocolVersionRequest; +import org.eclipse.edc.spi.response.StatusResult; + +import java.util.concurrent.CompletableFuture; + +/** + * Service to request versions from a counter-party. + */ +public interface VersionService { + + /** + * Request versions from the counter-party. + * + * @param request the protocol version request {@link ProtocolVersionRequest}. + * @return the supported versions. + */ + CompletableFuture> requestVersions(ProtocolVersionRequest request); + +} diff --git a/spi/control-plane/protocol-version-spi/build.gradle.kts b/spi/control-plane/protocol-version-spi/build.gradle.kts new file mode 100644 index 00000000000..4c1ccbcf320 --- /dev/null +++ b/spi/control-plane/protocol-version-spi/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +plugins { + `java-library` +} + + +dependencies { + api(project(":spi:common:core-spi")) + + testImplementation(project(":core:common:lib:json-lib")) + +} + + diff --git a/spi/control-plane/protocol-version-spi/src/main/java/org/eclipse/edc/connector/controlplane/protocolversion/spi/ProtocolVersionRequest.java b/spi/control-plane/protocol-version-spi/src/main/java/org/eclipse/edc/connector/controlplane/protocolversion/spi/ProtocolVersionRequest.java new file mode 100644 index 00000000000..847ce07bcef --- /dev/null +++ b/spi/control-plane/protocol-version-spi/src/main/java/org/eclipse/edc/connector/controlplane/protocolversion/spi/ProtocolVersionRequest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.protocolversion.spi; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; + +public class ProtocolVersionRequest { + + public static final String PROTOCOL_VERSION_REQUEST_TYPE = EDC_NAMESPACE + "ProtocolVersionRequest"; + public static final String PROTOCOL_VERSION_REQUEST_PROTOCOL = EDC_NAMESPACE + "protocol"; + public static final String PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ADDRESS = EDC_NAMESPACE + "counterPartyAddress"; + public static final String PROTOCOL_VERSION_REQUEST_COUNTER_PARTY_ID = EDC_NAMESPACE + "counterPartyId"; + + private String counterPartyAddress; + private String counterPartyId; + private String protocol; + + public String getCounterPartyAddress() { + return counterPartyAddress; + } + + public String getCounterPartyId() { + return counterPartyId; + } + + public String getProtocol() { + return protocol; + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private final ProtocolVersionRequest instance; + + private Builder() { + instance = new ProtocolVersionRequest(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder counterPartyAddress(String counterPartyAddress) { + instance.counterPartyAddress = counterPartyAddress; + return this; + } + + public Builder counterPartyId(String counterPartyId) { + instance.counterPartyId = counterPartyId; + return this; + } + + public Builder protocol(String protocol) { + instance.protocol = protocol; + return this; + } + + public ProtocolVersionRequest build() { + return instance; + } + } +} diff --git a/spi/control-plane/protocol-version-spi/src/main/java/org/eclipse/edc/connector/controlplane/protocolversion/spi/ProtocolVersionRequestMessage.java b/spi/control-plane/protocol-version-spi/src/main/java/org/eclipse/edc/connector/controlplane/protocolversion/spi/ProtocolVersionRequestMessage.java new file mode 100644 index 00000000000..f904386a123 --- /dev/null +++ b/spi/control-plane/protocol-version-spi/src/main/java/org/eclipse/edc/connector/controlplane/protocolversion/spi/ProtocolVersionRequestMessage.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.connector.controlplane.protocolversion.spi; + +import com.fasterxml.jackson.annotation.JsonCreator; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; + +import java.util.Objects; + +public class ProtocolVersionRequestMessage implements RemoteMessage { + + private final Policy policy; + + private String protocol = "unknown"; + private String counterPartyAddress; + private String counterPartyId; + + private ProtocolVersionRequestMessage() { + // at this time, this is just a placeholder. + policy = Policy.Builder.newInstance().build(); + } + + @Override + public String getProtocol() { + return protocol; + } + + @Override + public String getCounterPartyAddress() { + return counterPartyAddress; + } + + @Override + public String getCounterPartyId() { + return counterPartyId; + } + + public Policy getPolicy() { + return policy; + } + + public static class Builder { + private final ProtocolVersionRequestMessage message; + + private Builder() { + message = new ProtocolVersionRequestMessage(); + } + + @JsonCreator + public static ProtocolVersionRequestMessage.Builder newInstance() { + return new ProtocolVersionRequestMessage.Builder(); + } + + public ProtocolVersionRequestMessage.Builder protocol(String protocol) { + this.message.protocol = protocol; + return this; + } + + public ProtocolVersionRequestMessage.Builder counterPartyAddress(String callbackAddress) { + this.message.counterPartyAddress = callbackAddress; + return this; + } + + public ProtocolVersionRequestMessage.Builder counterPartyId(String counterPartyId) { + this.message.counterPartyId = counterPartyId; + return this; + } + + public ProtocolVersionRequestMessage build() { + Objects.requireNonNull(message.protocol, "protocol"); + + return message; + } + + } +} diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/ProtocolVersionApiEndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/ProtocolVersionApiEndToEndTest.java new file mode 100644 index 00000000000..3fc4083e462 --- /dev/null +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/ProtocolVersionApiEndToEndTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ + +package org.eclipse.edc.test.e2e.managementapi; + +import jakarta.json.JsonObject; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolVersion; +import org.eclipse.edc.connector.controlplane.services.spi.protocol.ProtocolVersionRegistry; +import org.eclipse.edc.junit.annotations.EndToEndTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.stream.Collectors; + +import static io.restassured.http.ContentType.JSON; +import static jakarta.json.Json.createObjectBuilder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.constants.CoreConstants.EDC_PREFIX; +import static org.hamcrest.Matchers.greaterThan; + +public class ProtocolVersionApiEndToEndTest { + + abstract static class Tests { + + @Test + void requestProtocolVersions(ManagementEndToEndTestContext context, ProtocolVersionRegistry registry) { + + var supportedVersions = registry.getAll().protocolVersions() + .stream().collect(Collectors.toMap(ProtocolVersion::version, ProtocolVersion::path)); + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "ProtocolVersionRequest") + .add("counterPartyAddress", context.providerProtocolUrl()) + .add("counterPartyId", "providerId") + .add("protocol", "dataspace-protocol-http") + .build(); + + var response = context.baseRequest() + .contentType(JSON) + .body(requestBody) + .post("/v4alpha/protocol-versions/request") + .then() + .log().ifValidationFails() + .statusCode(200) + .contentType(JSON) + .body("protocolVersions.size()", greaterThan(0)) + .extract().body().as(JsonObject.class); + + response.getJsonArray("protocolVersions").forEach(it -> { + var protocolVersion = it.asJsonObject(); + var version = protocolVersion.getString("version"); + var path = protocolVersion.getString("path"); + assertThat(supportedVersions.get(version)).isEqualTo(path); + }); + } + + } + + @Nested + @EndToEndTest + @ExtendWith(ManagementEndToEndExtension.InMemory.class) + class InMemory extends Tests { + } + +}