From a717da3dd6c195995d63f1c660f13dfbed467618 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Mon, 31 Jul 2023 10:17:39 +0200 Subject: [PATCH 1/4] feat: add catalog/dataset/request endpoint on management api --- .../service/catalog/CatalogServiceImpl.java | 14 ++- .../catalog/CatalogServiceImplTest.java | 17 ++- .../catalog/dispatcher/CatalogApiPaths.java | 3 +- .../DspCatalogHttpDispatcherExtension.java | 2 + .../delegate/CatalogRequestHttpDelegate.java | 2 +- .../CatalogRequestHttpRawDelegate.java | 2 +- .../DatasetRequestHttpRawDelegate.java | 84 ++++++++++++++ .../DatasetRequestHttpRawDelegateTest.java | 88 ++++++++++++++ .../protocol/dsp/DspHttpCoreExtension.java | 2 + .../dispatcher/DspHttpDispatcherDelegate.java | 2 +- .../ContractAgreementMessageHttpDelegate.java | 2 +- ...eementVerificationMessageHttpDelegate.java | 2 +- ...ctNegotiationEventMessageHttpDelegate.java | 2 +- ...tiationTerminationMessageHttpDelegate.java | 2 +- .../ContractOfferMessageHttpDelegate.java | 2 +- .../ContractRequestMessageHttpDelegate.java | 4 +- .../delegate/TransferCompletionDelegate.java | 2 +- .../delegate/TransferRequestDelegate.java | 2 +- .../delegate/TransferStartDelegate.java | 2 +- .../delegate/TransferTerminationDelegate.java | 2 +- .../api/management/catalog/CatalogApi.java | 89 +++++++++++++++ .../catalog/CatalogApiController.java | 56 ++++++--- .../catalog/CatalogApiExtension.java | 5 + ...JsonObjectToDatasetRequestTransformer.java | 47 ++++++++ .../validation/DatasetRequestValidator.java | 35 ++++++ .../catalog/CatalogApiControllerTest.java | 107 +++++++++++++++++- .../catalog/CatalogApiExtensionTest.java | 4 +- .../management/catalog/CatalogApiTest.java | 38 +++++++ ...ObjectToDatasetRequestTransformerTest.java | 65 +++++++++++ .../DatasetRequestValidatorTest.java | 68 +++++++++++ .../edc/catalog/spi/DatasetRequest.java | 79 +++++++++++++ .../catalog/spi/DatasetRequestMessage.java | 103 +++++++++++++++++ .../connector/spi/catalog/CatalogService.java | 12 +- .../managementapi/CatalogApiEndToEndTest.java | 28 ++++- 34 files changed, 934 insertions(+), 40 deletions(-) create mode 100644 data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java create mode 100644 data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java create mode 100644 extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformer.java create mode 100644 extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidator.java create mode 100644 extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformerTest.java create mode 100644 extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidatorTest.java create mode 100644 spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequest.java create mode 100644 spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequestMessage.java diff --git a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImpl.java b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImpl.java index 1d11c06b1a2..34cae60f902 100644 --- a/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImpl.java +++ b/core/control-plane/control-plane-aggregate-services/src/main/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImpl.java @@ -16,6 +16,7 @@ package org.eclipse.edc.connector.service.catalog; import org.eclipse.edc.catalog.spi.CatalogRequestMessage; +import org.eclipse.edc.catalog.spi.DatasetRequestMessage; import org.eclipse.edc.connector.spi.catalog.CatalogService; import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; import org.eclipse.edc.spi.query.QuerySpec; @@ -32,7 +33,7 @@ public CatalogServiceImpl(RemoteMessageDispatcherRegistry dispatcher) { } @Override - public CompletableFuture> request(String providerUrl, String protocol, QuerySpec querySpec) { + public CompletableFuture> requestCatalog(String providerUrl, String protocol, QuerySpec querySpec) { var request = CatalogRequestMessage.Builder.newInstance() .protocol(protocol) .counterPartyAddress(providerUrl) @@ -41,4 +42,15 @@ public CompletableFuture> request(String providerUrl, Strin return dispatcher.dispatch(byte[].class, request); } + + @Override + public CompletableFuture> requestDataset(String id, String counterPartyAddress, String protocol) { + var request = DatasetRequestMessage.Builder.newInstance() + .datasetId(id) + .protocol(protocol) + .counterPartyAddress(counterPartyAddress) + .build(); + + return dispatcher.dispatch(byte[].class, request); + } } diff --git a/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImplTest.java b/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImplTest.java index 610b493c92f..4f9e220f305 100644 --- a/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImplTest.java +++ b/core/control-plane/control-plane-aggregate-services/src/test/java/org/eclipse/edc/connector/service/catalog/CatalogServiceImplTest.java @@ -15,6 +15,7 @@ package org.eclipse.edc.connector.service.catalog; import org.eclipse.edc.catalog.spi.CatalogRequestMessage; +import org.eclipse.edc.catalog.spi.DatasetRequestMessage; import org.eclipse.edc.connector.spi.catalog.CatalogService; import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; import org.eclipse.edc.spi.query.QuerySpec; @@ -38,14 +39,26 @@ class CatalogServiceImplTest { private final CatalogService service = new CatalogServiceImpl(dispatcher); @Test - void request_shouldDispatchRequestAndReturnResult() { + void requestCatalog_shouldDispatchRequestAndReturnResult() { when(dispatcher.dispatch(eq(byte[].class), any())).thenReturn(completedFuture(StatusResult.success("content".getBytes()))); - var result = service.request("http://provider/url", "protocol", QuerySpec.none()); + var result = service.requestCatalog("http://provider/url", "protocol", QuerySpec.none()); assertThat(result).succeedsWithin(5, SECONDS).satisfies(statusResult -> { assertThat(statusResult).isSucceeded().isEqualTo("content".getBytes()); }); verify(dispatcher).dispatch(eq(byte[].class), isA(CatalogRequestMessage.class)); } + + @Test + void requestDataset_shouldDispatchRequestAndReturnResult() { + when(dispatcher.dispatch(eq(byte[].class), any())).thenReturn(completedFuture(StatusResult.success("content".getBytes()))); + + var result = service.requestDataset("datasetId", "http://provider/url", "protocol"); + + assertThat(result).succeedsWithin(5, SECONDS).satisfies(statusResult -> { + assertThat(statusResult).isSucceeded().isEqualTo("content".getBytes()); + }); + verify(dispatcher).dispatch(eq(byte[].class), isA(DatasetRequestMessage.class)); + } } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/CatalogApiPaths.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/CatalogApiPaths.java index dc591c509db..a2fb444a8a6 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/CatalogApiPaths.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/CatalogApiPaths.java @@ -21,5 +21,6 @@ public interface CatalogApiPaths { String BASE_PATH = "/catalog"; String CATALOG_REQUEST = "/request"; - + String DATASET_REQUEST = "/datasets"; + } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java index ab07577ced0..a20979baf8b 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java @@ -17,6 +17,7 @@ import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate.CatalogRequestHttpDelegate; import org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate.CatalogRequestHttpRawDelegate; +import org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate.DatasetRequestHttpRawDelegate; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRemoteMessageDispatcher; import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.runtime.metamodel.annotation.Extension; @@ -58,6 +59,7 @@ public void initialize(ServiceExtensionContext context) { var mapper = typeManager.getMapper(JSON_LD); messageDispatcher.registerDelegate(new CatalogRequestHttpDelegate(remoteMessageSerializer, mapper, transformerRegistry, jsonLdService)); messageDispatcher.registerDelegate(new CatalogRequestHttpRawDelegate(remoteMessageSerializer)); + messageDispatcher.registerDelegate(new DatasetRequestHttpRawDelegate(remoteMessageSerializer)); } } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java index b8f82ca826d..ebd7aac3d13 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java @@ -65,7 +65,7 @@ public Class getMessageType() { */ @Override public Request buildRequest(CatalogRequestMessage message) { - return buildRequest(message, BASE_PATH + CATALOG_REQUEST); + return buildPostRequest(message, BASE_PATH + CATALOG_REQUEST); } /** diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java index 89b65190b8a..36dd63f342d 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java @@ -53,7 +53,7 @@ public Class getMessageType() { */ @Override public Request buildRequest(CatalogRequestMessage message) { - return buildRequest(message, BASE_PATH + CATALOG_REQUEST); + return buildPostRequest(message, BASE_PATH + CATALOG_REQUEST); } /** diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java new file mode 100644 index 00000000000..4b6c048dd5a --- /dev/null +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 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.catalog.dispatcher.delegate; + +import jakarta.json.JsonObject; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; +import org.eclipse.edc.catalog.spi.DatasetRequestMessage; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; +import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; +import org.eclipse.edc.spi.EdcException; + +import java.io.IOException; +import java.util.function.Function; + +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.DATASET_REQUEST; + +/** + * Delegate for dispatching catalog requests as defined in the + * dataspace protocol specification + */ +public class DatasetRequestHttpRawDelegate extends DspHttpDispatcherDelegate { + + public DatasetRequestHttpRawDelegate(JsonLdRemoteMessageSerializer serializer) { + super(serializer); + } + + @Override + public Class getMessageType() { + return DatasetRequestMessage.class; + } + + /** + * Sends a catalog request. The request body is constructed as defined in the dataspace protocol + * implementation. The request is sent to the remote component using the path from the + * specification. + * + * @param message the message + * @return the built okhttp request + */ + @Override + public Request buildRequest(DatasetRequestMessage message) { + var url = HttpUrl.get(message.getCounterPartyAddress() + BASE_PATH + DATASET_REQUEST + "/" + message.getDatasetId()); + + return new Request.Builder() + .url(url) + .get() + .build(); + } + + /** + * Parses the response to a byte[]. It cannot return a {@link java.io.InputStream} because the response gets closed + * by the {@link org.eclipse.edc.spi.http.EdcHttpClient} + * + * @return a function that transforms the response body to a {@link JsonObject}. + */ + @Override + public Function parseResponse() { + return response -> { + try { + return response.body().bytes(); + + } catch (NullPointerException e) { + throw new EdcException("Failed to read response body, as body was null.", e); + } catch (IOException e) { + throw new EdcException("Failed to read response body", e); + } + }; + } +} diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java new file mode 100644 index 00000000000..ff67e219f6f --- /dev/null +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 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.catalog.dispatcher.delegate; + +import okhttp3.ResponseBody; +import org.eclipse.edc.catalog.spi.DatasetRequestMessage; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; +import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.DATASET_REQUEST; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class DatasetRequestHttpRawDelegateTest extends DspHttpDispatcherDelegateTestBase { + + private DatasetRequestHttpRawDelegate delegate; + + @BeforeEach + void setUp() { + delegate = new DatasetRequestHttpRawDelegate(serializer); + } + + @Test + void getMessageType_returnDatasetRequest() { + assertThat(delegate.getMessageType()).isEqualTo(DatasetRequestMessage.class); + } + + @Test + void buildRequest_returnRequest() { + var message = message(); + + var httpRequest = delegate().buildRequest(message); + + assertThat(httpRequest.method()).isEqualTo("GET"); + assertThat(httpRequest.url().url()).hasToString(message.getCounterPartyAddress() + BASE_PATH + DATASET_REQUEST + "/" + message.getDatasetId()); + } + + @Test + void parseResponse_returnDataset() throws IOException { + var responseBody = mock(ResponseBody.class); + var response = dummyResponseBuilder(200).body(responseBody).build(); + var bytes = "test".getBytes(); + + when(responseBody.bytes()).thenReturn(bytes); + when(responseBody.byteStream()).thenReturn(new ByteArrayInputStream(bytes)); + + var result = delegate.parseResponse().apply(response); + + assertThat(result).isEqualTo(bytes); + } + + @Test + void parseResponse_responseBodyNull_throwException() { + testParseResponse_shouldThrowException_whenResponseBodyNull(); + } + + @Override + protected DspHttpDispatcherDelegate delegate() { + return delegate; + } + + private DatasetRequestMessage message() { + return DatasetRequestMessage.Builder.newInstance() + .datasetId("dataset-id") + .counterPartyAddress("http://connector") + .protocol("protocol") + .build(); + } +} diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtension.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtension.java index 220b92bdaad..59bfe1acc44 100644 --- a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtension.java +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtension.java @@ -15,6 +15,7 @@ package org.eclipse.edc.protocol.dsp; import org.eclipse.edc.catalog.spi.CatalogRequestMessage; +import org.eclipse.edc.catalog.spi.DatasetRequestMessage; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementMessage; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementVerificationMessage; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractNegotiationEventMessage; @@ -137,6 +138,7 @@ private void registerTransferProcessPolicyScopes(DspHttpRemoteMessageDispatcher private void registerCatalogPolicyScopes(DspHttpRemoteMessageDispatcher dispatcher) { dispatcher.registerPolicyScope(CatalogRequestMessage.class, CATALOGING_REQUEST_SCOPE, CatalogRequestMessage::getPolicy); + dispatcher.registerPolicyScope(DatasetRequestMessage.class, CATALOGING_REQUEST_SCOPE, DatasetRequestMessage::getPolicy); } } diff --git a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java index c6975fad56a..32e7ae0f6ac 100644 --- a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java +++ b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java @@ -93,7 +93,7 @@ public Function> handleResponse() { */ protected abstract Function parseResponse(); - protected Request buildRequest(M message, String path) { + protected Request buildPostRequest(M message, String path) { var body = serializer.serialize(message); var requestBody = RequestBody.create(body, MediaType.get(APPLICATION_JSON)); diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java index f9b23283656..db553cb263a 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java @@ -48,7 +48,7 @@ public Class getMessageType() { */ @Override public Request buildRequest(ContractAgreementMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java index b5411b0d6b0..c82d816e0dc 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java @@ -50,7 +50,7 @@ public Class getMessageType() { */ @Override public Request buildRequest(ContractAgreementVerificationMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT + VERIFICATION); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT + VERIFICATION); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java index 920fae52a8c..a0e3c63853f 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java @@ -49,7 +49,7 @@ public Class getMessageType() { */ @Override public Request buildRequest(ContractNegotiationEventMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + EVENT); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + EVENT); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java index aaef7f43887..148cd3c7a02 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java @@ -49,7 +49,7 @@ public Class getMessageType() { */ @Override public Request buildRequest(ContractNegotiationTerminationMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + TERMINATION); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + TERMINATION); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java index 76684f2ac5f..ea88a0369ab 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java @@ -41,7 +41,7 @@ public Class getMessageType() { @Override public Request buildRequest(ContractOfferMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_OFFER); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_OFFER); } @Override diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java index 53d77707ae3..10e83018eee 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java @@ -61,9 +61,9 @@ public Class getMessageType() { @Override public Request buildRequest(ContractRequestMessage message) { if (message.getType() == ContractRequestMessage.Type.INITIAL) { - return buildRequest(message, BASE_PATH + INITIAL_CONTRACT_REQUEST); + return buildPostRequest(message, BASE_PATH + INITIAL_CONTRACT_REQUEST); } else { - return buildRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_REQUEST); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_REQUEST); } } diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java index acb58a98612..09dcdfab3b8 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java @@ -39,7 +39,7 @@ public Class getMessageType() { @Override public Request buildRequest(TransferCompletionMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_COMPLETION); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_COMPLETION); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java index 8a097bd8257..157e257cc28 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java @@ -39,7 +39,7 @@ public Class getMessageType() { @Override public Request buildRequest(TransferRequestMessage message) { - return buildRequest(message, BASE_PATH + TRANSFER_INITIAL_REQUEST); + return buildPostRequest(message, BASE_PATH + TRANSFER_INITIAL_REQUEST); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java index 2e7d3a17367..ab5a1320228 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java @@ -39,7 +39,7 @@ public Class getMessageType() { @Override public Request buildRequest(TransferStartMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_START); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_START); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java index a7d13c148b8..14f69b197b8 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java @@ -39,7 +39,7 @@ public Class getMessageType() { @Override public Request buildRequest(TransferTerminationMessage message) { - return buildRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_TERMINATION); + return buildPostRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_TERMINATION); } @Override diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java index ffe649b73f2..062a7621516 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java @@ -44,6 +44,17 @@ public interface CatalogApi { ) void requestCatalog(JsonObject request, @Suspended AsyncResponse response); + @Operation( + requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = DatasetRequestSchema.class))), + responses = { @ApiResponse( + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = DatasetSchema.class) + ), + description = "Gets single dataset from a connector") } + ) + void getDataset(JsonObject request, @Suspended AsyncResponse response); + @Schema(name = "CatalogRequest", example = CatalogRequestSchema.CATALOG_REQUEST_EXAMPLE) record CatalogRequestSchema( @Schema(name = TYPE, example = CATALOG_REQUEST_TYPE) @@ -68,6 +79,24 @@ record CatalogRequestSchema( """; } + @Schema(name = "DatasetRequest", example = DatasetRequestSchema.DATASET_REQUEST_EXAMPLE) + record DatasetRequestSchema( + @Schema(name = TYPE, example = CATALOG_REQUEST_TYPE) + String providerUrl, + String protocol, + ApiCoreSchema.QuerySpecSchema querySpec) { + + public static final String DATASET_REQUEST_EXAMPLE = """ + { + "@context": { "edc": "https://w3id.org/edc/v0.0.1/ns/" }, + "@type": "DatasetRequest", + "@id": "dataset-id", + "counterPartyAddress": "http://counter-party-address", + "protocol": "dataspace-protocol-http" + } + """; + } + @Schema(name = "Catalog", description = "DCAT catalog", example = CatalogSchema.CATALOG_EXAMPLE) record CatalogSchema( ) { @@ -138,4 +167,64 @@ record CatalogSchema( } """; } + + @Schema(name = "Dataset", description = "DCAT dataset", example = DatasetSchema.DATASET_EXAMPLE) + record DatasetSchema( + ) { + public static final String DATASET_EXAMPLE = """ + { + "@id": "bcca61be-e82e-4da6-bfec-9716a56cef35", + "@type": "dcat:Dataset", + "odrl:hasPolicy": { + "@id": "OGU0ZTMzMGMtODQ2ZS00ZWMxLThmOGQtNWQxNWM0NmI2NmY4:YmNjYTYxYmUtZTgyZS00ZGE2LWJmZWMtOTcxNmE1NmNlZjM1:NDY2ZTZhMmEtNjQ1Yy00ZGQ0LWFlZDktMjdjNGJkZTU4MDNj", + "@type": "odrl:Set", + "odrl:permission": { + "odrl:target": "bcca61be-e82e-4da6-bfec-9716a56cef35", + "odrl:action": { + "odrl:type": "http://www.w3.org/ns/odrl/2/use" + }, + "odrl:constraint": { + "odrl:and": [ + { + "odrl:leftOperand": "https://w3id.org/edc/v0.0.1/ns/inForceDate", + "odrl:operator": { + "@id": "odrl:gteq" + }, + "odrl:rightOperand": "2023-07-07T07:19:58.585601395Z" + }, + { + "odrl:leftOperand": "https://w3id.org/edc/v0.0.1/ns/inForceDate", + "odrl:operator": { + "@id": "odrl:lteq" + }, + "odrl:rightOperand": "2023-07-12T07:19:58.585601395Z" + } + ] + } + }, + "odrl:prohibition": [], + "odrl:obligation": [], + "odrl:target": "bcca61be-e82e-4da6-bfec-9716a56cef35" + }, + "dcat:distribution": [ + { + "@type": "dcat:Distribution", + "dct:format": { + "@id": "HttpData" + }, + "dcat:accessService": "5e839777-d93e-4785-8972-1005f51cf367" + } + ], + "edc:description": "description", + "edc:id": "bcca61be-e82e-4da6-bfec-9716a56cef35", + "@context": { + "dct": "https://purl.org/dc/terms/", + "edc": "https://w3id.org/edc/v0.0.1/ns/", + "dcat": "https://www.w3.org/ns/dcat/", + "odrl": "http://www.w3.org/ns/odrl/2/", + "dspace": "https://w3id.org/dspace/v0.8/" + } + } + """; + } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java index 57d48d4e2e7..3bbbdac8a9d 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java @@ -22,8 +22,10 @@ import jakarta.ws.rs.container.AsyncResponse; import jakarta.ws.rs.container.Suspended; import org.eclipse.edc.catalog.spi.CatalogRequest; +import org.eclipse.edc.catalog.spi.DatasetRequest; import org.eclipse.edc.connector.spi.catalog.CatalogService; 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; @@ -32,6 +34,7 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_TYPE; @Path("/v2/catalog") @Consumes(APPLICATION_JSON) @@ -58,22 +61,49 @@ public void requestCatalog(JsonObject requestBody, @Suspended AsyncResponse resp var request = transformerRegistry.transform(requestBody, CatalogRequest.class) .orElseThrow(InvalidRequestException::new); - service.request(request.getProviderUrl(), request.getProtocol(), request.getQuerySpec()) + service.requestCatalog(request.getProviderUrl(), request.getProtocol(), request.getQuerySpec()) .whenComplete((result, throwable) -> { - if (throwable == null) { - if (result.succeeded()) { - response.resume(result.getContent()); - } else { - response.resume(new BadGatewayException(result.getFailureDetail())); - } - } else { - if (throwable instanceof EdcException || throwable.getCause() instanceof EdcException) { - response.resume(new BadGatewayException(throwable.getMessage())); - } else { - response.resume(throwable); - } + try { + response.resume(toResponse(result, throwable)); + } catch (Throwable mapped) { + response.resume(mapped); } }); } + @Override + @POST + @Path("dataset/request") + public void getDataset(JsonObject requestBody, @Suspended AsyncResponse response) { + validatorRegistry.validate(DATASET_REQUEST_TYPE, requestBody).orElseThrow(ValidationFailureException::new); + + var request = transformerRegistry.transform(requestBody, DatasetRequest.class) + .orElseThrow(InvalidRequestException::new); + + service.requestDataset(request.getId(), request.getCounterPartyAddress(), request.getProtocol()) + .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/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java index 916e4aa94a7..da4a0bbb3f9 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java @@ -15,8 +15,11 @@ package org.eclipse.edc.connector.api.management.catalog; import org.eclipse.edc.catalog.spi.CatalogRequest; +import org.eclipse.edc.catalog.spi.DatasetRequest; import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToCatalogRequestTransformer; +import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToDatasetRequestTransformer; import org.eclipse.edc.connector.api.management.catalog.validation.CatalogRequestValidator; +import org.eclipse.edc.connector.api.management.catalog.validation.DatasetRequestValidator; import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; import org.eclipse.edc.connector.api.management.configuration.transform.ManagementApiTypeTransformerRegistry; import org.eclipse.edc.connector.spi.catalog.CatalogService; @@ -55,9 +58,11 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { transformerRegistry.register(new JsonObjectToCatalogRequestTransformer()); + transformerRegistry.register(new JsonObjectToDatasetRequestTransformer()); webService.registerResource(config.getContextAlias(), new CatalogApiController(service, transformerRegistry, validatorRegistry)); validatorRegistry.register(CatalogRequest.CATALOG_REQUEST_TYPE, CatalogRequestValidator.instance()); + validatorRegistry.register(DatasetRequest.DATASET_REQUEST_TYPE, DatasetRequestValidator.instance()); } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformer.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformer.java new file mode 100644 index 00000000000..9d754ba9d7c --- /dev/null +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 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.api.management.catalog.transform; + +import jakarta.json.JsonObject; +import org.eclipse.edc.catalog.spi.DatasetRequest; +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.catalog.spi.DatasetRequest.DATASET_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_PROTOCOL; + +public class JsonObjectToDatasetRequestTransformer extends AbstractJsonLdTransformer { + + public JsonObjectToDatasetRequestTransformer() { + super(JsonObject.class, DatasetRequest.class); + } + + @Override + public @Nullable DatasetRequest transform(@NotNull JsonObject object, @NotNull TransformerContext context) { + var builder = DatasetRequest.Builder.newInstance() + .id(nodeId(object)); + + visitProperties(object, key -> switch (key) { + case DATASET_REQUEST_PROTOCOL -> v -> builder.protocol(transformString(v, context)); + case DATASET_REQUEST_COUNTER_PARTY_ADDRESS -> v -> builder.counterPartyAddress(transformString(v, context)); + default -> doNothing(); + }); + + return builder.build(); + } + +} diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidator.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidator.java new file mode 100644 index 00000000000..1b6b066db83 --- /dev/null +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidator.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 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.api.management.catalog.validation; + +import jakarta.json.JsonObject; +import org.eclipse.edc.validator.jsonobject.JsonObjectValidator; +import org.eclipse.edc.validator.jsonobject.validators.MandatoryIdNotBlank; +import org.eclipse.edc.validator.jsonobject.validators.MandatoryValue; +import org.eclipse.edc.validator.spi.Validator; + +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_PROTOCOL; + +public class DatasetRequestValidator { + + public static Validator instance() { + return JsonObjectValidator.newValidator() + .verifyId(MandatoryIdNotBlank::new) + .verify(DATASET_REQUEST_PROTOCOL, MandatoryValue::new) + .verify(DATASET_REQUEST_COUNTER_PARTY_ADDRESS, MandatoryValue::new) + .build(); + } +} diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java index bbbe73405a2..b3c4cf075a3 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java @@ -16,6 +16,7 @@ import jakarta.json.Json; import org.eclipse.edc.catalog.spi.CatalogRequest; +import org.eclipse.edc.catalog.spi.DatasetRequest; import org.eclipse.edc.connector.spi.catalog.CatalogService; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.spi.EdcException; @@ -28,10 +29,14 @@ import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; import org.junit.jupiter.api.Test; +import java.util.concurrent.CompletableFuture; + 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.catalog.spi.DatasetRequest.DATASET_REQUEST_PROTOCOL; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_TYPE; import static org.eclipse.edc.spi.response.ResponseStatus.FATAL_ERROR; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -57,7 +62,7 @@ void requestCatalog() { var request = CatalogRequest.Builder.newInstance().providerUrl("http://url").build(); when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.success(request)); - when(service.request(any(), any(), any())).thenReturn(completedFuture(StatusResult.success("{}".getBytes()))); + when(service.requestCatalog(any(), any(), any())).thenReturn(completedFuture(StatusResult.success("{}".getBytes()))); var requestBody = Json.createObjectBuilder().add(CatalogRequest.CATALOG_REQUEST_PROTOCOL, "any").build(); given() @@ -72,7 +77,7 @@ void requestCatalog() { } @Test - void catalogRequest_shouldReturnBadRequest_whenValidationFails() { + void requestCatalog_shouldReturnBadRequest_whenValidationFails() { when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.failure(Violation.violation("error", "path"))); var requestBody = Json.createObjectBuilder().add(CatalogRequest.CATALOG_REQUEST_PROTOCOL, "any").build(); @@ -88,7 +93,7 @@ void catalogRequest_shouldReturnBadRequest_whenValidationFails() { } @Test - void catalogRequest_shouldReturnBadRequest_whenTransformFails() { + void requestCatalog_shouldReturnBadRequest_whenTransformFails() { when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.failure("error")); var requestBody = Json.createObjectBuilder().add(CatalogRequest.CATALOG_REQUEST_PROTOCOL, "any").build(); @@ -108,7 +113,7 @@ void requestCatalog_shouldReturnBadGateway_whenServiceFails() { var request = CatalogRequest.Builder.newInstance().providerUrl("http://url").build(); when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.success(request)); - when(service.request(any(), any(), any())).thenReturn(completedFuture(StatusResult.failure(FATAL_ERROR, "error"))); + when(service.requestCatalog(any(), any(), any())).thenReturn(completedFuture(StatusResult.failure(FATAL_ERROR, "error"))); var requestBody = Json.createObjectBuilder().add(CatalogRequest.CATALOG_REQUEST_PROTOCOL, "any").build(); @@ -126,7 +131,7 @@ void requestCatalog_shouldReturnBadGateway_whenServiceThrowsException() { var request = CatalogRequest.Builder.newInstance().providerUrl("http://url").build(); when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.success(request)); - when(service.request(any(), any(), any())).thenReturn(failedFuture(new EdcException("error"))); + when(service.requestCatalog(any(), any(), any())).thenReturn(failedFuture(new EdcException("error"))); var requestBody = Json.createObjectBuilder().add(CatalogRequest.CATALOG_REQUEST_PROTOCOL, "any").build(); given() @@ -138,4 +143,96 @@ void requestCatalog_shouldReturnBadGateway_whenServiceThrowsException() { .statusCode(502); } + @Test + void requestDataset_shouldCallService() { + var request = DatasetRequest.Builder.newInstance() + .id("dataset-id") + .protocol("protocol") + .counterPartyAddress("http://provider-url") + .build(); + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), any())).thenReturn(Result.success(request)); + when(service.requestDataset(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(StatusResult.success("{}".getBytes()))); + var requestBody = Json.createObjectBuilder().add(DATASET_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v2/catalog/dataset/request") + .then() + .statusCode(200); + + verify(validatorRegistry).validate(eq(DATASET_REQUEST_TYPE), any()); + verify(transformerRegistry).transform(any(), eq(DatasetRequest.class)); + verify(service).requestDataset("dataset-id", "http://provider-url", "protocol"); + } + + @Test + void requestDataset_shouldReturnBadRequest_whenValidationFails() { + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.failure(Violation.violation("error", "path"))); + var requestBody = Json.createObjectBuilder().add(DATASET_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v2/catalog/dataset/request") + .then() + .statusCode(400); + verify(validatorRegistry).validate(eq(DATASET_REQUEST_TYPE), any()); + verifyNoInteractions(transformerRegistry, service); + } + + @Test + void requestDataset_shouldReturnBadRequest_whenTransformFails() { + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(DatasetRequest.class))).thenReturn(Result.failure("error")); + var requestBody = Json.createObjectBuilder().add(DATASET_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v2/catalog/dataset/request") + .then() + .statusCode(400); + verifyNoInteractions(service); + } + + @Test + void requestDataset_shouldReturnBadGateway_whenServiceFails() { + var request = DatasetRequest.Builder.newInstance().counterPartyAddress("http://url").build(); + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(DatasetRequest.class))).thenReturn(Result.success(request)); + when(service.requestDataset(any(), any(), any())).thenReturn(completedFuture(StatusResult.failure(FATAL_ERROR, "error"))); + + var requestBody = Json.createObjectBuilder().add(DATASET_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v2/catalog/dataset/request") + .then() + .statusCode(502); + } + + @Test + void requestDataset_shouldReturnBadGateway_whenServiceThrowsException() { + var request = DatasetRequest.Builder.newInstance().counterPartyAddress("http://url").build(); + when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); + when(transformerRegistry.transform(any(), eq(DatasetRequest.class))).thenReturn(Result.success(request)); + when(service.requestDataset(any(), any(), any())).thenReturn(failedFuture(new EdcException("error"))); + var requestBody = Json.createObjectBuilder().add(DATASET_REQUEST_PROTOCOL, "any").build(); + + given() + .port(port) + .contentType(JSON) + .body(requestBody) + .post("/v2/catalog/dataset/request") + .then() + .statusCode(502); + } + } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtensionTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtensionTest.java index 765a8c893b1..1f2cb4d96aa 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtensionTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtensionTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_TYPE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -38,9 +39,10 @@ void setUp(ServiceExtensionContext context) { } @Test - void initiate_shouldRegisterValidator(CatalogApiExtension extension, ServiceExtensionContext context) { + void initiate_shouldRegisterValidators(CatalogApiExtension extension, ServiceExtensionContext context) { extension.initialize(context); verify(validatorRegistry).register(eq(CATALOG_REQUEST_TYPE), any()); + verify(validatorRegistry).register(eq(DATASET_REQUEST_TYPE), any()); } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java index 1c6ee33de58..29bd0d42eb8 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java @@ -18,8 +18,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.json.JsonObject; import org.eclipse.edc.catalog.spi.CatalogRequest; +import org.eclipse.edc.catalog.spi.DatasetRequest; import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToCatalogRequestTransformer; +import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToDatasetRequestTransformer; import org.eclipse.edc.connector.api.management.catalog.validation.CatalogRequestValidator; +import org.eclipse.edc.connector.api.management.catalog.validation.DatasetRequestValidator; import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl; import org.eclipse.edc.core.transform.transformer.to.JsonObjectToQuerySpecTransformer; import org.eclipse.edc.jsonld.JsonLdExtension; @@ -32,10 +35,14 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.eclipse.edc.connector.api.management.catalog.CatalogApi.CatalogRequestSchema.CATALOG_REQUEST_EXAMPLE; import static org.eclipse.edc.connector.api.management.catalog.CatalogApi.CatalogSchema.CATALOG_EXAMPLE; +import static org.eclipse.edc.connector.api.management.catalog.CatalogApi.DatasetRequestSchema.DATASET_REQUEST_EXAMPLE; +import static org.eclipse.edc.connector.api.management.catalog.CatalogApi.DatasetSchema.DATASET_EXAMPLE; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_CATALOG_TYPE; import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_ATTRIBUTE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_TYPE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.eclipse.edc.junit.extensions.TestServiceExtensionContext.testServiceExtensionContext; @@ -48,6 +55,7 @@ class CatalogApiTest { @BeforeEach void setUp() { transformer.register(new JsonObjectToCatalogRequestTransformer()); + transformer.register(new JsonObjectToDatasetRequestTransformer()); transformer.register(new JsonObjectToQuerySpecTransformer()); } @@ -70,6 +78,24 @@ void catalogRequestExample() throws JsonProcessingException { })); } + @Test + void datasetRequestExample() throws JsonProcessingException { + var validator = DatasetRequestValidator.instance(); + + var jsonObject = objectMapper.readValue(DATASET_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, DatasetRequest.class)) + .satisfies(transformResult -> assertThat(transformResult).isSucceeded() + .satisfies(transformed -> { + assertThat(transformed.getProtocol()).isNotBlank(); + assertThat(transformed.getCounterPartyAddress()).isNotBlank(); + })); + } + @Test void catalogExample() throws JsonProcessingException { var jsonObject = objectMapper.readValue(CATALOG_EXAMPLE, JsonObject.class); @@ -81,4 +107,16 @@ void catalogExample() throws JsonProcessingException { assertThat(content.getJsonArray(DCAT_DATASET_ATTRIBUTE).size()).isGreaterThan(0); }); } + + @Test + void datasetExample() throws JsonProcessingException { + var jsonObject = objectMapper.readValue(DATASET_EXAMPLE, JsonObject.class); + var expanded = jsonLd.expand(jsonObject); + + assertThat(expanded).isSucceeded().satisfies(content -> { + assertThat(content.getString(ID)).isNotBlank(); + assertThat(content.getJsonArray(TYPE).getString(0)).isEqualTo(DCAT_DATASET_TYPE); + assertThat(content.getJsonArray(ODRL_POLICY_ATTRIBUTE).size()).isGreaterThan(0); + }); + } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformerTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformerTest.java new file mode 100644 index 00000000000..9b9178c5369 --- /dev/null +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToDatasetRequestTransformerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 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.api.management.catalog.transform; + +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.eclipse.edc.catalog.spi.DatasetRequest; +import org.eclipse.edc.spi.query.QuerySpec; +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.catalog.spi.DatasetRequest.DATASET_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_PROTOCOL; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_TYPE; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class JsonObjectToDatasetRequestTransformerTest { + + private final JsonObjectToDatasetRequestTransformer transformer = new JsonObjectToDatasetRequestTransformer(); + private final TransformerContext context = mock(TransformerContext.class); + + @Test + void types() { + assertThat(transformer.getInputType()).isEqualTo(JsonObject.class); + assertThat(transformer.getOutputType()).isEqualTo(DatasetRequest.class); + } + + @Test + void transform() { + var querySpec = QuerySpec.Builder.newInstance().build(); + when(context.transform(any(), eq(QuerySpec.class))).thenReturn(querySpec); + var json = Json.createObjectBuilder() + .add(TYPE, DATASET_REQUEST_TYPE) + .add(ID, "id") + .add(DATASET_REQUEST_PROTOCOL, "protocol") + .add(DATASET_REQUEST_COUNTER_PARTY_ADDRESS, "http://provider/url") + .build(); + + var result = transformer.transform(json, context); + + assertThat(result).isNotNull(); + assertThat(result.getId()).isEqualTo("id"); + assertThat(result.getProtocol()).isEqualTo("protocol"); + assertThat(result.getCounterPartyAddress()).isEqualTo("http://provider/url"); + } + +} diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidatorTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidatorTest.java new file mode 100644 index 00000000000..ddb90fbc6af --- /dev/null +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/DatasetRequestValidatorTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 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.api.management.catalog.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.catalog.spi.DatasetRequest.DATASET_REQUEST_COUNTER_PARTY_ADDRESS; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_PROTOCOL; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VALUE; +import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; + +class DatasetRequestValidatorTest { + + private final Validator validator = DatasetRequestValidator.instance(); + + @Test + void shouldSucceed_whenInputIsValid() { + var input = Json.createObjectBuilder() + .add(ID, "id") + .add(DATASET_REQUEST_COUNTER_PARTY_ADDRESS, value("http://any")) + .add(DATASET_REQUEST_PROTOCOL, value("protocol")) + .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(ID)) + .anySatisfy(v -> assertThat(v.path()).isEqualTo(DATASET_REQUEST_COUNTER_PARTY_ADDRESS)) + .anySatisfy(v -> assertThat(v.path()).isEqualTo(DATASET_REQUEST_PROTOCOL)); + } + + private JsonArrayBuilder value(String value) { + return createArrayBuilder().add(createObjectBuilder().add(VALUE, value)); + } +} diff --git a/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequest.java b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequest.java new file mode 100644 index 00000000000..b58e011f72f --- /dev/null +++ b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 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.catalog.spi; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; + +public class DatasetRequest { + + public static final String DATASET_REQUEST_TYPE = EDC_NAMESPACE + "DatasetRequest"; + public static final String DATASET_REQUEST_PROTOCOL = EDC_NAMESPACE + "protocol"; + public static final String DATASET_REQUEST_COUNTER_PARTY_ADDRESS = EDC_NAMESPACE + "counterPartyAddress"; + + private String id; + private String counterPartyAddress; + private String protocol; + + private DatasetRequest() { + } + + public String getId() { + return id; + } + + public String getCounterPartyAddress() { + return counterPartyAddress; + } + + public String getProtocol() { + return protocol; + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private final DatasetRequest instance; + + private Builder() { + instance = new DatasetRequest(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder id(String id) { + instance.id = id; + return this; + } + + public Builder counterPartyAddress(String counterPartyAddress) { + instance.counterPartyAddress = counterPartyAddress; + return this; + } + + public Builder protocol(String protocol) { + instance.protocol = protocol; + return this; + } + + public DatasetRequest build() { + return instance; + } + } +} diff --git a/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequestMessage.java b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequestMessage.java new file mode 100644 index 00000000000..a86dc4b5e5f --- /dev/null +++ b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/DatasetRequestMessage.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2022 Microsoft Corporation + * + * 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: + * Microsoft Corporation - Initial implementation + * + */ + +package org.eclipse.edc.catalog.spi; + +import com.fasterxml.jackson.annotation.JsonCreator; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +/** + * A request for a participant's {@link Dataset}. + */ +public class DatasetRequestMessage implements RemoteMessage { + + private String datasetId; + private String protocol; + private String counterPartyAddress; + private final Policy policy; + + private DatasetRequestMessage() { + // at this time, this is just a placeholder. + policy = Policy.Builder.newInstance().build(); + } + + public String getDatasetId() { + return datasetId; + } + + @NotNull + @Override + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + @NotNull + @Override + public String getCounterPartyAddress() { + return counterPartyAddress; + } + + /** + * Returns the {@link Policy} associated with the Dataset Request. Currently, this is an empty policy and serves as + * placeholder. + * + * @return the stub {@link Policy}. + */ + public Policy getPolicy() { + return policy; + } + + public static class Builder { + private final DatasetRequestMessage message; + + private Builder() { + message = new DatasetRequestMessage(); + } + + @JsonCreator + public static DatasetRequestMessage.Builder newInstance() { + return new DatasetRequestMessage.Builder(); + } + + public Builder datasetId(String datasetId) { + this.message.datasetId = datasetId; + return this; + } + + public DatasetRequestMessage.Builder protocol(String protocol) { + this.message.protocol = protocol; + return this; + } + + public DatasetRequestMessage.Builder counterPartyAddress(String callbackAddress) { + this.message.counterPartyAddress = callbackAddress; + return this; + } + + public DatasetRequestMessage build() { + Objects.requireNonNull(message.protocol, "protocol"); + + return message; + } + + } +} diff --git a/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/spi/catalog/CatalogService.java b/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/spi/catalog/CatalogService.java index e6124d6e798..05106ce7212 100644 --- a/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/spi/catalog/CatalogService.java +++ b/spi/control-plane/control-plane-spi/src/main/java/org/eclipse/edc/connector/spi/catalog/CatalogService.java @@ -29,5 +29,15 @@ public interface CatalogService { * @param querySpec the {@link QuerySpec} object. * @return the provider's catalog */ - CompletableFuture> request(String providerUrl, String protocol, QuerySpec querySpec); + CompletableFuture> requestCatalog(String providerUrl, String protocol, QuerySpec querySpec); + + /** + * Return the dataset + * + * @param id the dataset id. + * @param counterPartyAddress the url of the provider. + * @param protocol the protocol. + * @return the provider dataset. + */ + CompletableFuture> requestDataset(String id, String counterPartyAddress, String protocol); } diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java index 8fa9017d5e7..ffb2fdd3097 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java @@ -31,6 +31,7 @@ import static jakarta.json.Json.createArrayBuilder; import static jakarta.json.Json.createObjectBuilder; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX; @@ -43,7 +44,7 @@ public class CatalogApiEndToEndTest extends BaseManagementApiEndToEndTest { private final String providerUrl = "http://localhost:" + PROTOCOL_PORT + "/protocol"; @Test - void shouldReturnCatalog_withoutQuerySpec() { + void requestCatalog_shouldReturnCatalog_withoutQuerySpec() { var requestBody = createObjectBuilder() .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) .add(TYPE, "CatalogRequest") @@ -62,7 +63,7 @@ void shouldReturnCatalog_withoutQuerySpec() { } @Test - void shouldReturnCatalog_withQuerySpec() { + void requestCatalog_shouldReturnCatalog_withQuerySpec() { var assetIndex = controlPlane.getContext().getService(AssetIndex.class); var policyDefinitionStore = controlPlane.getContext().getService(PolicyDefinitionStore.class); var contractDefinitionStore = controlPlane.getContext().getService(ContractDefinitionStore.class); @@ -118,6 +119,29 @@ void shouldReturnCatalog_withQuerySpec() { .body("'dcat:dataset'.'edc:id'", is("id-2")); } + @Test + void getDataset_shouldReturnDataset() { + var assetIndex = controlPlane.getContext().getService(AssetIndex.class); + assetIndex.create(createAsset("asset-id").build()); + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "DatasetRequest") + .add(ID, "asset-id") + .add("counterPartyAddress", providerUrl) + .add("protocol", "dataspace-protocol-http") + .build(); + + baseRequest() + .contentType(JSON) + .body(requestBody) + .post("/v2/catalog/dataset/request") + .then() + .statusCode(200) + .contentType(JSON) + .body(ID, is("asset-id")) + .body(TYPE, is("dcat:Dataset")); + } + private Asset.Builder createAsset(String id) { return Asset.Builder.newInstance() .dataAddress(DataAddress.Builder.newInstance().type("test-type").build()) From e0412d307f8a6ac9f5bf599a0208f882a62b5048 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Mon, 31 Jul 2023 12:10:31 +0200 Subject: [PATCH 2/4] replace providerUrl with counterPartyAddress in CatalogRequest --- .../api/management/catalog/CatalogApi.java | 9 ++++- .../catalog/CatalogApiController.java | 2 +- .../catalog/CatalogApiExtension.java | 2 +- ...JsonObjectToCatalogRequestTransformer.java | 34 +++++++++++------ .../validation/CatalogRequestValidator.java | 23 +++++++++++- .../catalog/CatalogApiControllerTest.java | 6 +-- .../management/catalog/CatalogApiTest.java | 5 ++- ...ObjectToCatalogRequestTransformerTest.java | 32 ++++++++++++++-- .../CatalogRequestValidatorTest.java | 17 ++++++++- .../edc/catalog/spi/CatalogRequest.java | 13 ++++--- .../edc/test/system/utils/Participant.java | 37 +++++++++++++++---- .../test/e2e/AbstractEndToEndTransfer.java | 2 +- .../managementapi/CatalogApiEndToEndTest.java | 4 +- 13 files changed, 143 insertions(+), 43 deletions(-) diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java index 062a7621516..93a4fd4a2a9 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApi.java @@ -58,7 +58,11 @@ public interface CatalogApi { @Schema(name = "CatalogRequest", example = CatalogRequestSchema.CATALOG_REQUEST_EXAMPLE) record CatalogRequestSchema( @Schema(name = TYPE, example = CATALOG_REQUEST_TYPE) + String type, + @Deprecated(since = "0.2.0") + @Schema(deprecated = true, description = "please use counterPartyAddress instead") String providerUrl, + String counterPartyAddress, String protocol, ApiCoreSchema.QuerySpecSchema querySpec) { @@ -66,7 +70,7 @@ record CatalogRequestSchema( { "@context": { "edc": "https://w3id.org/edc/v0.0.1/ns/" }, "@type": "CatalogRequest", - "providerUrl": "http://provider-address", + "counterPartyAddress": "http://provider-address", "protocol": "dataspace-protocol-http", "querySpec": { "offset": 0, @@ -82,7 +86,8 @@ record CatalogRequestSchema( @Schema(name = "DatasetRequest", example = DatasetRequestSchema.DATASET_REQUEST_EXAMPLE) record DatasetRequestSchema( @Schema(name = TYPE, example = CATALOG_REQUEST_TYPE) - String providerUrl, + String type, + String counterPartyAddress, String protocol, ApiCoreSchema.QuerySpecSchema querySpec) { diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java index 3bbbdac8a9d..b60c63cf048 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiController.java @@ -61,7 +61,7 @@ public void requestCatalog(JsonObject requestBody, @Suspended AsyncResponse resp var request = transformerRegistry.transform(requestBody, CatalogRequest.class) .orElseThrow(InvalidRequestException::new); - service.requestCatalog(request.getProviderUrl(), request.getProtocol(), request.getQuerySpec()) + service.requestCatalog(request.getCounterPartyAddress(), request.getProtocol(), request.getQuerySpec()) .whenComplete((result, throwable) -> { try { response.resume(toResponse(result, throwable)); diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java index da4a0bbb3f9..9de57111b22 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java @@ -57,7 +57,7 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { - transformerRegistry.register(new JsonObjectToCatalogRequestTransformer()); + transformerRegistry.register(new JsonObjectToCatalogRequestTransformer(context.getMonitor())); transformerRegistry.register(new JsonObjectToDatasetRequestTransformer()); webService.registerResource(config.getContextAlias(), new CatalogApiController(service, transformerRegistry, validatorRegistry)); diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java index 6b7484e3d4d..afe62f289c4 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java @@ -17,33 +17,45 @@ import jakarta.json.JsonObject; import org.eclipse.edc.catalog.spi.CatalogRequest; import org.eclipse.edc.jsonld.spi.transformer.AbstractJsonLdTransformer; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.transform.spi.TransformerContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Optional; + +import static java.lang.String.format; +import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_COUNTER_PARTY_ADDRESS; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROTOCOL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROVIDER_URL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_QUERY_SPEC; +import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE; public class JsonObjectToCatalogRequestTransformer extends AbstractJsonLdTransformer { - public JsonObjectToCatalogRequestTransformer() { + private final Monitor monitor; + + public JsonObjectToCatalogRequestTransformer(Monitor monitor) { super(JsonObject.class, CatalogRequest.class); + this.monitor = monitor; } @Override public @Nullable CatalogRequest transform(@NotNull JsonObject object, @NotNull TransformerContext context) { - var builder = CatalogRequest.Builder.newInstance(); - - visitProperties(object, key -> switch (key) { - case CATALOG_REQUEST_PROTOCOL -> v -> builder.protocol(transformString(v, context)); - case CATALOG_REQUEST_PROVIDER_URL -> v -> builder.providerUrl(transformString(v, context)); - case CATALOG_REQUEST_QUERY_SPEC -> v -> builder.querySpec(transformObject(v, QuerySpec.class, context)); - default -> doNothing(); - }); - - return builder.build(); + var counterPartyAddress = Optional.of(object) + .map(it -> it.get(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS)) + .orElseGet(() -> { + monitor.warning(format("The attribute %s has been deprecated in type %s, please use %s", + CATALOG_REQUEST_PROVIDER_URL, CATALOG_REQUEST_TYPE, CATALOG_REQUEST_COUNTER_PARTY_ADDRESS)); + return object.get(CATALOG_REQUEST_PROVIDER_URL); + }); + + return CatalogRequest.Builder.newInstance() + .protocol(transformString(object.get(CATALOG_REQUEST_PROTOCOL), context)) + .querySpec(transformObject(object.get(CATALOG_REQUEST_QUERY_SPEC), QuerySpec.class, context)) + .counterPartyAddress(transformString(counterPartyAddress, context)) + .build(); } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidator.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidator.java index 3f5454ff7e3..10fb031a505 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidator.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidator.java @@ -16,10 +16,13 @@ import jakarta.json.JsonObject; import org.eclipse.edc.api.validation.QuerySpecValidator; +import org.eclipse.edc.validator.jsonobject.JsonLdPath; import org.eclipse.edc.validator.jsonobject.JsonObjectValidator; import org.eclipse.edc.validator.jsonobject.validators.MandatoryValue; +import org.eclipse.edc.validator.spi.ValidationResult; import org.eclipse.edc.validator.spi.Validator; +import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_COUNTER_PARTY_ADDRESS; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROTOCOL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROVIDER_URL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_QUERY_SPEC; @@ -28,9 +31,27 @@ public class CatalogRequestValidator { public static Validator instance() { return JsonObjectValidator.newValidator() - .verify(CATALOG_REQUEST_PROVIDER_URL, MandatoryValue::new) + .verify(MandatoryCounterPartyAddressOrProviderUrl::new) .verify(CATALOG_REQUEST_PROTOCOL, MandatoryValue::new) .verifyObject(CATALOG_REQUEST_QUERY_SPEC, QuerySpecValidator::instance) .build(); } + + private record MandatoryCounterPartyAddressOrProviderUrl(JsonLdPath path) implements Validator { + + @Override + public ValidationResult validate(JsonObject input) { + var counterPartyAddress = new MandatoryValue(path.append(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS)); + var providerUrl = new MandatoryValue(path.append(CATALOG_REQUEST_PROVIDER_URL)); + + var validateCounterParty = counterPartyAddress.validate(input); + var validateProviderUrl = providerUrl.validate(input); + + if (validateCounterParty.succeeded() || validateProviderUrl.succeeded()) { + return ValidationResult.success(); + } else { + return validateCounterParty; + } + } + } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java index b3c4cf075a3..0b48f03e19f 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiControllerTest.java @@ -59,7 +59,7 @@ protected Object controller() { @Test void requestCatalog() { - var request = CatalogRequest.Builder.newInstance().providerUrl("http://url").build(); + var request = CatalogRequest.Builder.newInstance().counterPartyAddress("http://url").build(); when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.success(request)); when(service.requestCatalog(any(), any(), any())).thenReturn(completedFuture(StatusResult.success("{}".getBytes()))); @@ -110,7 +110,7 @@ void requestCatalog_shouldReturnBadRequest_whenTransformFails() { @Test void requestCatalog_shouldReturnBadGateway_whenServiceFails() { - var request = CatalogRequest.Builder.newInstance().providerUrl("http://url").build(); + var request = CatalogRequest.Builder.newInstance().counterPartyAddress("http://url").build(); when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.success(request)); when(service.requestCatalog(any(), any(), any())).thenReturn(completedFuture(StatusResult.failure(FATAL_ERROR, "error"))); @@ -128,7 +128,7 @@ void requestCatalog_shouldReturnBadGateway_whenServiceFails() { @Test void requestCatalog_shouldReturnBadGateway_whenServiceThrowsException() { - var request = CatalogRequest.Builder.newInstance().providerUrl("http://url").build(); + var request = CatalogRequest.Builder.newInstance().counterPartyAddress("http://url").build(); when(validatorRegistry.validate(any(), any())).thenReturn(ValidationResult.success()); when(transformerRegistry.transform(any(), eq(CatalogRequest.class))).thenReturn(Result.success(request)); when(service.requestCatalog(any(), any(), any())).thenReturn(failedFuture(new EdcException("error"))); diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java index 29bd0d42eb8..a98d7108a61 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiTest.java @@ -45,6 +45,7 @@ import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.eclipse.edc.junit.extensions.TestServiceExtensionContext.testServiceExtensionContext; +import static org.mockito.Mockito.mock; class CatalogApiTest { @@ -54,7 +55,7 @@ class CatalogApiTest { @BeforeEach void setUp() { - transformer.register(new JsonObjectToCatalogRequestTransformer()); + transformer.register(new JsonObjectToCatalogRequestTransformer(mock())); transformer.register(new JsonObjectToDatasetRequestTransformer()); transformer.register(new JsonObjectToQuerySpecTransformer()); } @@ -73,7 +74,7 @@ void catalogRequestExample() throws JsonProcessingException { .satisfies(transformResult -> assertThat(transformResult).isSucceeded() .satisfies(transformed -> { assertThat(transformed.getProtocol()).isNotBlank(); - assertThat(transformed.getProviderUrl()).isNotBlank(); + assertThat(transformed.getCounterPartyAddress()).isNotBlank(); assertThat(transformed.getQuerySpec()).isNotNull(); })); } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java index 3c06ce5b4fa..27664a67ee7 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java @@ -17,17 +17,20 @@ import jakarta.json.Json; import jakarta.json.JsonObject; import org.eclipse.edc.catalog.spi.CatalogRequest; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.query.QuerySpec; 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.catalog.spi.CatalogRequest.CATALOG_REQUEST_COUNTER_PARTY_ADDRESS; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROTOCOL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROVIDER_URL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_QUERY_SPEC; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -35,8 +38,9 @@ class JsonObjectToCatalogRequestTransformerTest { - private final JsonObjectToCatalogRequestTransformer transformer = new JsonObjectToCatalogRequestTransformer(); - private final TransformerContext context = mock(TransformerContext.class); + private final TransformerContext context = mock(); + private final Monitor monitor = mock(); + private final JsonObjectToCatalogRequestTransformer transformer = new JsonObjectToCatalogRequestTransformer(monitor); @Test void types() { @@ -46,6 +50,27 @@ void types() { @Test void transform() { + var querySpec = QuerySpec.Builder.newInstance().build(); + var querySpecJson = Json.createObjectBuilder().build(); + when(context.transform(any(), eq(QuerySpec.class))).thenReturn(querySpec); + var json = Json.createObjectBuilder() + .add(TYPE, CATALOG_REQUEST_TYPE) + .add(CATALOG_REQUEST_PROTOCOL, "protocol") + .add(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS, "http://provider/url") + .add(CATALOG_REQUEST_QUERY_SPEC, querySpecJson) + .build(); + + var result = transformer.transform(json, context); + + assertThat(result).isNotNull(); + assertThat(result.getProtocol()).isEqualTo("protocol"); + assertThat(result.getCounterPartyAddress()).isEqualTo("http://provider/url"); + assertThat(result.getQuerySpec()).isEqualTo(querySpec); + verify(context).transform(querySpecJson, QuerySpec.class); + } + + @Test + void transform_shouldUseProviderId_whenCounterPartyAddressIsMissing() { var querySpec = QuerySpec.Builder.newInstance().build(); var querySpecJson = Json.createObjectBuilder().build(); when(context.transform(any(), eq(QuerySpec.class))).thenReturn(querySpec); @@ -60,9 +85,10 @@ void transform() { assertThat(result).isNotNull(); assertThat(result.getProtocol()).isEqualTo("protocol"); - assertThat(result.getProviderUrl()).isEqualTo("http://provider/url"); + assertThat(result.getCounterPartyAddress()).isEqualTo("http://provider/url"); assertThat(result.getQuerySpec()).isEqualTo(querySpec); verify(context).transform(querySpecJson, QuerySpec.class); + verify(monitor).warning(anyString()); } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidatorTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidatorTest.java index 46b903c6060..cbeba1f0fd5 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidatorTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/validation/CatalogRequestValidatorTest.java @@ -26,6 +26,7 @@ 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.catalog.spi.CatalogRequest.CATALOG_REQUEST_COUNTER_PARTY_ADDRESS; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROTOCOL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_PROVIDER_URL; import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_QUERY_SPEC; @@ -39,6 +40,18 @@ class CatalogRequestValidatorTest { @Test void shouldSucceed_whenInputIsValid() { + var input = Json.createObjectBuilder() + .add(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS, value("http://any")) + .add(CATALOG_REQUEST_PROTOCOL, value("protocol")) + .build(); + + var result = validator.validate(input); + + assertThat(result).isSucceeded(); + } + + @Test + void shouldSucceed_whenDeprecatedProviderUrlIsUsed() { var input = Json.createObjectBuilder() .add(CATALOG_REQUEST_PROVIDER_URL, value("http://any")) .add(CATALOG_REQUEST_PROTOCOL, value("protocol")) @@ -57,14 +70,14 @@ void shouldFail_whenMandatoryFieldsAreMissing() { assertThat(result).isFailed().extracting(ValidationFailure::getViolations).asInstanceOf(list(Violation.class)) .hasSize(2) - .anySatisfy(v -> assertThat(v.path()).isEqualTo(CATALOG_REQUEST_PROVIDER_URL)) + .anySatisfy(v -> assertThat(v.path()).isEqualTo(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS)) .anySatisfy(v -> assertThat(v.path()).isEqualTo(CATALOG_REQUEST_PROTOCOL)); } @Test void shouldFail_whenOptionalQuerySpecIsInvalid() { var input = Json.createObjectBuilder() - .add(CATALOG_REQUEST_PROVIDER_URL, value("http://any")) + .add(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS, value("http://any")) .add(CATALOG_REQUEST_PROTOCOL, value("protocol")) .add(CATALOG_REQUEST_QUERY_SPEC, createArrayBuilder().add(createObjectBuilder() .add(EDC_QUERY_SPEC_SORT_FIELD, value(" ")))) diff --git a/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java index 2e789466fa7..963ca140527 100644 --- a/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java +++ b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java @@ -25,18 +25,20 @@ public class CatalogRequest { public static final String CATALOG_REQUEST_TYPE = EDC_NAMESPACE + "CatalogRequest"; public static final String CATALOG_REQUEST_PROTOCOL = EDC_NAMESPACE + "protocol"; + public static final String CATALOG_REQUEST_COUNTER_PARTY_ADDRESS = EDC_NAMESPACE + "counterPartyAddress"; + @Deprecated(since = "0.2.0") public static final String CATALOG_REQUEST_PROVIDER_URL = EDC_NAMESPACE + "providerUrl"; public static final String CATALOG_REQUEST_QUERY_SPEC = EDC_NAMESPACE + "querySpec"; private QuerySpec querySpec; - private String providerUrl; + private String counterPartyAddress; private String protocol; private CatalogRequest() { } - public String getProviderUrl() { - return providerUrl; + public String getCounterPartyAddress() { + return counterPartyAddress; } public QuerySpec getQuerySpec() { @@ -65,8 +67,8 @@ public Builder querySpec(QuerySpec querySpec) { return this; } - public Builder providerUrl(String providerUrl) { - instance.providerUrl = providerUrl; + public Builder counterPartyAddress(String counterPartyAddress) { + instance.counterPartyAddress = counterPartyAddress; return this; } @@ -76,7 +78,6 @@ public Builder protocol(String protocol) { } public CatalogRequest build() { - requireNonNull(instance.providerUrl, "providerUrl"); return instance; } } diff --git a/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java b/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java index 931e59f1407..dd93ec5451b 100644 --- a/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java +++ b/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java @@ -19,7 +19,6 @@ import jakarta.json.Json; import jakarta.json.JsonArray; import jakarta.json.JsonObject; -import jakarta.json.JsonValue; import org.eclipse.edc.connector.contract.spi.ContractId; import org.eclipse.edc.jsonld.TitaniumJsonLd; import org.eclipse.edc.jsonld.spi.JsonLd; @@ -168,7 +167,7 @@ public JsonArray getCatalogDatasets(Participant provider) { var requestBody = createObjectBuilder() .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) .add(TYPE, "CatalogRequest") - .add("providerUrl", provider.protocolEndpoint.url.toString()) + .add("counterPartyAddress", provider.protocolEndpoint.url.toString()) .add("protocol", DSP_PROTOCOL) .build(); @@ -204,12 +203,34 @@ public JsonArray getCatalogDatasets(Participant provider) { * @return dataset. */ public JsonObject getDatasetForAsset(Participant provider, String assetId) { - var datasets = getCatalogDatasets(provider); - return datasets.stream() - .map(JsonValue::asJsonObject) - .filter(it -> assetId.equals(extractContractDefinitionId(it).assetIdPart())) - .findFirst() - .orElseThrow(() -> new EdcException(format("No dataset for asset %s in the catalog", assetId))); + var datasetReference = new AtomicReference(); + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "DatasetRequest") + .add(ID, assetId) + .add("counterPartyAddress", provider.protocolEndpoint.url.toString()) + .add("protocol", DSP_PROTOCOL) + .build(); + + await().atMost(TIMEOUT).untilAsserted(() -> { + var response = managementEndpoint.baseRequest() + .contentType(JSON) + .when() + .body(requestBody) + .post("/v2/catalog/request") + .then() + .log().all() + .statusCode(200) + .extract().body().asString(); + + var compacted = objectMapper.readValue(response, JsonObject.class); + + var dataset = jsonLd.expand(compacted).orElseThrow(f -> new EdcException(f.getFailureDetail())); + + datasetReference.set(dataset); + }); + + return datasetReference.get(); } /** diff --git a/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/edc/test/e2e/AbstractEndToEndTransfer.java b/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/edc/test/e2e/AbstractEndToEndTransfer.java index 605c67e447d..30e7c716786 100644 --- a/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/edc/test/e2e/AbstractEndToEndTransfer.java +++ b/system-tests/e2e-transfer-test/runner/src/test/java/org/eclipse/edc/test/e2e/AbstractEndToEndTransfer.java @@ -57,7 +57,7 @@ public abstract class AbstractEndToEndTransfer { .build(); @Test - void httpPullDataTransfer() { + void httpPull_dataTransfer() { registerDataPlanes(); var assetId = UUID.randomUUID().toString(); createResourcesOnProvider(assetId, noConstraintPolicy(), httpDataAddressProperties()); diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java index ffb2fdd3097..0676d3c91b5 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java @@ -48,7 +48,7 @@ void requestCatalog_shouldReturnCatalog_withoutQuerySpec() { var requestBody = createObjectBuilder() .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) .add(TYPE, "CatalogRequest") - .add("providerUrl", providerUrl) + .add("counterPartyAddress", providerUrl) .add("protocol", "dataspace-protocol-http") .build(); @@ -103,7 +103,7 @@ void requestCatalog_shouldReturnCatalog_withQuerySpec() { var requestBody = createObjectBuilder() .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) .add(TYPE, "CatalogRequest") - .add("providerUrl", providerUrl) + .add("counterPartyAddress", providerUrl) .add("protocol", "dataspace-protocol-http") .add("querySpec", querySpec) .build(); From 2568aafe9ae80d325af64d71c6b9ed39cf16ac9f Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Mon, 31 Jul 2023 14:49:21 +0200 Subject: [PATCH 3/4] extract RequestProvider --- .../DspCatalogHttpDispatcherExtension.java | 32 ++-- .../delegate/CatalogRequestHttpDelegate.java | 105 ------------ .../CatalogRequestHttpRawDelegate.java | 27 +--- .../DatasetRequestHttpRawDelegate.java | 33 +--- .../CatalogRequestHttpRawDelegateTest.java | 27 +--- ...CatalogRequestMessageHttpDelegateTest.java | 153 ------------------ .../DatasetRequestHttpRawDelegateTest.java | 19 +-- .../DspHttpRemoteMessageDispatcherImpl.java | 21 +-- .../dispatcher/GetDspHttpRequestFactory.java | 39 +++++ .../dispatcher/PostDspHttpRequestFactory.java | 51 ++++++ .../dsp/DspHttpCoreExtensionTest.java | 66 ++------ .../eclipse/edc/protocol/dsp/TestMessage.java | 29 ++++ ...spHttpRemoteMessageDispatcherImplTest.java | 42 +++-- .../GetDspHttpRequestFactoryTest.java | 41 +++++ .../PostDspHttpRequestFactoryTest.java | 55 +++++++ .../dispatcher/DspHttpDispatcherDelegate.java | 41 +---- .../DspHttpRemoteMessageDispatcher.java | 10 +- .../spi/dispatcher/DspHttpRequestFactory.java | 35 ++++ .../spi/dispatcher/RequestPathProvider.java | 34 ++++ .../DspHttpDispatcherDelegateTest.java | 12 +- .../DspHttpDispatcherDelegateTestBase.java | 35 ---- ...DspNegotiationHttpDispatcherExtension.java | 57 ++++++- .../ContractAgreementMessageHttpDelegate.java | 23 +-- ...eementVerificationMessageHttpDelegate.java | 25 +-- ...ctNegotiationEventMessageHttpDelegate.java | 24 +-- ...tiationTerminationMessageHttpDelegate.java | 24 +-- .../ContractOfferMessageHttpDelegate.java | 18 +-- .../ContractRequestMessageHttpDelegate.java | 28 +--- ...tractAgreementMessageHttpDelegateTest.java | 60 ------- ...ntVerificationMessageHttpDelegateTest.java | 32 ---- ...gotiationEventMessageHttpDelegateTest.java | 32 ---- ...ionTerminationMessageHttpDelegateTest.java | 32 ---- .../ContractOfferMessageHttpDelegateTest.java | 44 +---- ...ontractRequestMessageHttpDelegateTest.java | 75 --------- .../build.gradle.kts | 3 +- ...DspTransferProcessDispatcherExtension.java | 35 +++- .../delegate/TransferCompletionDelegate.java | 16 +- .../delegate/TransferRequestDelegate.java | 16 +- .../delegate/TransferStartDelegate.java | 16 +- .../delegate/TransferTerminationDelegate.java | 16 +- .../TransferCompletionDelegateTest.java | 30 ---- .../delegate/TransferRequestDelegateTest.java | 45 ------ .../delegate/TransferStartDelegateTest.java | 30 ---- .../TransferTerminationDelegateTest.java | 30 ---- .../catalog/CatalogApiExtension.java | 9 +- ...JsonObjectToCatalogRequestTransformer.java | 7 +- ...ObjectToCatalogRequestTransformerTest.java | 16 ++ .../edc/catalog/spi/CatalogRequest.java | 1 - .../edc/test/system/utils/Participant.java | 2 +- .../managementapi/CatalogApiEndToEndTest.java | 1 + 50 files changed, 482 insertions(+), 1172 deletions(-) delete mode 100644 data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java delete mode 100644 data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestMessageHttpDelegateTest.java create mode 100644 data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java create mode 100644 data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java create mode 100644 data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/TestMessage.java create mode 100644 data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactoryTest.java create mode 100644 data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactoryTest.java create mode 100644 data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRequestFactory.java create mode 100644 data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/RequestPathProvider.java diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java index a20979baf8b..e0282861f53 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/DspCatalogHttpDispatcherExtension.java @@ -14,20 +14,22 @@ package org.eclipse.edc.protocol.dsp.catalog.dispatcher; -import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate.CatalogRequestHttpDelegate; +import org.eclipse.edc.catalog.spi.CatalogRequestMessage; +import org.eclipse.edc.catalog.spi.DatasetRequestMessage; import org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate.CatalogRequestHttpRawDelegate; import org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate.DatasetRequestHttpRawDelegate; +import org.eclipse.edc.protocol.dsp.dispatcher.GetDspHttpRequestFactory; +import org.eclipse.edc.protocol.dsp.dispatcher.PostDspHttpRequestFactory; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRemoteMessageDispatcher; import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; 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 org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.edc.transform.spi.TypeTransformerRegistry; -import static org.eclipse.edc.spi.CoreConstants.JSON_LD; +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.CATALOG_REQUEST; +import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.DATASET_REQUEST; /** * Creates and registers the HTTP dispatcher delegate for sending a catalog request as defined in @@ -42,12 +44,6 @@ public class DspCatalogHttpDispatcherExtension implements ServiceExtension { private DspHttpRemoteMessageDispatcher messageDispatcher; @Inject private JsonLdRemoteMessageSerializer remoteMessageSerializer; - @Inject - private TypeManager typeManager; - @Inject - private TypeTransformerRegistry transformerRegistry; - @Inject - private JsonLd jsonLdService; @Override public String name() { @@ -56,10 +52,16 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { - var mapper = typeManager.getMapper(JSON_LD); - messageDispatcher.registerDelegate(new CatalogRequestHttpDelegate(remoteMessageSerializer, mapper, transformerRegistry, jsonLdService)); - messageDispatcher.registerDelegate(new CatalogRequestHttpRawDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new DatasetRequestHttpRawDelegate(remoteMessageSerializer)); + messageDispatcher.registerMessage( + CatalogRequestMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + CATALOG_REQUEST), + new CatalogRequestHttpRawDelegate() + ); + messageDispatcher.registerMessage( + DatasetRequestMessage.class, + new GetDspHttpRequestFactory<>(m -> BASE_PATH + DATASET_REQUEST + "/" + m.getDatasetId()), + new DatasetRequestHttpRawDelegate() + ); } } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java deleted file mode 100644 index ebd7aac3d13..00000000000 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpDelegate.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2023 Fraunhofer Institute for Software and Systems Engineering - * - * 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: - * Fraunhofer Institute for Software and Systems Engineering - initial API and implementation - * - */ - -package org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate; - -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.json.JsonObject; -import okhttp3.Request; -import okhttp3.Response; -import org.eclipse.edc.catalog.spi.Catalog; -import org.eclipse.edc.catalog.spi.CatalogRequestMessage; -import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.transform.spi.TypeTransformerRegistry; - -import java.io.IOException; -import java.util.function.Function; - -import static java.lang.String.format; -import static java.lang.String.join; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.CATALOG_REQUEST; - -/** - * Delegate for dispatching catalog requests as defined in the dataspace protocol specification. - */ -public class CatalogRequestHttpDelegate extends DspHttpDispatcherDelegate { - - private final ObjectMapper mapper; - private final TypeTransformerRegistry transformerRegistry; - private final JsonLd jsonLdService; - - public CatalogRequestHttpDelegate(JsonLdRemoteMessageSerializer serializer, ObjectMapper mapper, TypeTransformerRegistry transformerRegistry, JsonLd jsonLdService) { - super(serializer); - this.mapper = mapper; - this.transformerRegistry = transformerRegistry; - this.jsonLdService = jsonLdService; - } - - @Override - public Class getMessageType() { - return CatalogRequestMessage.class; - } - - /** - * Sends a catalog request. The request body is constructed as defined in the dataspace protocol - * implementation. The request is sent to the remote component using the path from the - * specification. - * - * @param message the message - * @return the built okhttp request - */ - @Override - public Request buildRequest(CatalogRequestMessage message) { - return buildPostRequest(message, BASE_PATH + CATALOG_REQUEST); - } - - /** - * Parses the response to a catalog request. The JSON-LD structure from the response body is - * expanded and then transformed to an EDC catalog. - * - * @return a function that transforms the response body to a catalog. - */ - @Override - public Function parseResponse() { - return response -> { - try { - var jsonObject = mapper.readValue(response.body().bytes(), JsonObject.class); - var expansion = jsonLdService.expand(jsonObject); - - if (expansion.succeeded()) { - var result = transformerRegistry.transform(expansion.getContent(), Catalog.class); - if (result.succeeded()) { - return result.getContent(); - } else { - throw new EdcException(format("Failed to read response body: %s", join(", ", result.getFailureMessages()))); - } - } else { - throw new EdcException(expansion.getFailureDetail()); - } - - } catch (NullPointerException e) { - throw new EdcException("Failed to read response body, as body was null."); - } catch (IndexOutOfBoundsException e) { - throw new EdcException("Failed to expand JSON-LD in response body.", e); - } catch (IOException e) { - throw new EdcException("Failed to read response body.", e); - } - }; - } - -} diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java index 36dd63f342d..ab216918957 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegate.java @@ -15,45 +15,22 @@ package org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate; import jakarta.json.JsonObject; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.catalog.spi.CatalogRequestMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.spi.EdcException; import java.io.IOException; import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.CATALOG_REQUEST; - /** * Delegate for dispatching catalog requests as defined in the * dataspace protocol specification */ public class CatalogRequestHttpRawDelegate extends DspHttpDispatcherDelegate { - public CatalogRequestHttpRawDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return CatalogRequestMessage.class; - } - - /** - * Sends a catalog request. The request body is constructed as defined in the dataspace protocol - * implementation. The request is sent to the remote component using the path from the - * specification. - * - * @param message the message - * @return the built okhttp request - */ - @Override - public Request buildRequest(CatalogRequestMessage message) { - return buildPostRequest(message, BASE_PATH + CATALOG_REQUEST); + public CatalogRequestHttpRawDelegate() { + super(); } /** diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java index 4b6c048dd5a..4da7c169964 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegate.java @@ -15,51 +15,22 @@ package org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate; import jakarta.json.JsonObject; -import okhttp3.HttpUrl; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.catalog.spi.DatasetRequestMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.spi.EdcException; import java.io.IOException; import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.DATASET_REQUEST; - /** * Delegate for dispatching catalog requests as defined in the * dataspace protocol specification */ public class DatasetRequestHttpRawDelegate extends DspHttpDispatcherDelegate { - public DatasetRequestHttpRawDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return DatasetRequestMessage.class; - } - - /** - * Sends a catalog request. The request body is constructed as defined in the dataspace protocol - * implementation. The request is sent to the remote component using the path from the - * specification. - * - * @param message the message - * @return the built okhttp request - */ - @Override - public Request buildRequest(DatasetRequestMessage message) { - var url = HttpUrl.get(message.getCounterPartyAddress() + BASE_PATH + DATASET_REQUEST + "/" + message.getDatasetId()); - - return new Request.Builder() - .url(url) - .get() - .build(); + public DatasetRequestHttpRawDelegate() { + super(); } /** diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegateTest.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegateTest.java index 568ecb0731f..f3fdfdf3522 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegateTest.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestHttpRawDelegateTest.java @@ -18,7 +18,6 @@ import org.eclipse.edc.catalog.spi.CatalogRequestMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; -import org.eclipse.edc.spi.query.QuerySpec; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,8 +25,6 @@ import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.CATALOG_REQUEST; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -37,22 +34,7 @@ class CatalogRequestHttpRawDelegateTest extends DspHttpDispatcherDelegateTestBas @BeforeEach void setUp() { - delegate = new CatalogRequestHttpRawDelegate(serializer); - } - - @Test - void getMessageType_returnCatalogRequest() { - assertThat(delegate.getMessageType()).isEqualTo(CatalogRequestMessage.class); - } - - @Test - void buildRequest_returnRequest() throws IOException { - testBuildRequest_shouldReturnRequest(message(), BASE_PATH + CATALOG_REQUEST); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); + delegate = new CatalogRequestHttpRawDelegate(); } @Test @@ -79,11 +61,4 @@ void parseResponse_responseBodyNull_throwException() { return delegate; } - private CatalogRequestMessage message() { - return CatalogRequestMessage.Builder.newInstance() - .counterPartyAddress("http://connector") - .protocol("protocol") - .querySpec(QuerySpec.max()) - .build(); - } } diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestMessageHttpDelegateTest.java deleted file mode 100644 index 59b2e883792..00000000000 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/CatalogRequestMessageHttpDelegateTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2023 Fraunhofer Institute for Software and Systems Engineering - * - * 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: - * Fraunhofer Institute for Software and Systems Engineering - initial API and implementation - * - */ - -package org.eclipse.edc.protocol.dsp.catalog.dispatcher.delegate; - -import jakarta.json.Json; -import jakarta.json.JsonObject; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.eclipse.edc.catalog.spi.Catalog; -import org.eclipse.edc.catalog.spi.CatalogRequestMessage; -import org.eclipse.edc.jsonld.TitaniumJsonLd; -import org.eclipse.edc.jsonld.spi.JsonLd; -import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; -import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.result.Result; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.CATALOG_REQUEST; -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.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -class CatalogRequestMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { - - private final JsonLd jsonLdService = new TitaniumJsonLd(mock(Monitor.class)); - private CatalogRequestHttpDelegate delegate; - - @BeforeEach - void setUp() { - delegate = new CatalogRequestHttpDelegate(serializer, mapper, registry, jsonLdService); - } - - @Test - void getMessageType_returnCatalogRequest() { - assertThat(delegate.getMessageType()).isEqualTo(CatalogRequestMessage.class); - } - - @Test - void buildRequest_returnRequest() throws IOException { - testBuildRequest_shouldReturnRequest(message(), BASE_PATH + CATALOG_REQUEST); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - - @Test - void parseResponse_returnCatalog() throws IOException { - var jsonObject = getJsonObject(); - var catalog = Catalog.Builder.newInstance().build(); - var response = mock(Response.class); - var responseBody = mock(ResponseBody.class); - var bytes = "test".getBytes(); - - when(response.body()).thenReturn(responseBody); - when(responseBody.bytes()).thenReturn(bytes); - when(mapper.readValue(bytes, JsonObject.class)).thenReturn(jsonObject); - when(registry.transform(any(JsonObject.class), eq(Catalog.class))).thenReturn(Result.success(catalog)); - - var result = delegate.parseResponse().apply(response); - - assertThat(result).isEqualTo(catalog); - verify(mapper, times(1)).readValue(bytes, JsonObject.class); - verify(registry, times(1)).transform(isA(JsonObject.class), eq(Catalog.class)); - } - - @Test - void parseResponse_transformationFails_throwException() throws IOException { - var jsonObject = getJsonObject(); - var response = mock(Response.class); - var responseBody = mock(ResponseBody.class); - - when(response.body()).thenReturn(responseBody); - when(responseBody.bytes()).thenReturn("test".getBytes()); - when(mapper.readValue(any(byte[].class), eq(JsonObject.class))).thenReturn(jsonObject); - when(registry.transform(any(JsonObject.class), eq(Catalog.class))).thenReturn(Result.failure("error")); - - assertThatThrownBy(() -> delegate.parseResponse().apply(response)).isInstanceOf(EdcException.class); - } - - @Test - void parseResponse_readingResponseBodyFails_throwException() throws IOException { - testParseResponse_shouldThrowException_whenReadingResponseBodyFails(); - } - - @Test - void parseResponse_responseBodyNull_throwException() { - testParseResponse_shouldThrowException_whenResponseBodyNull(); - } - - @Test - void parseResponse_expandingJsonLdFails_throwException() throws IOException { - // JSON is missing @context -> expanding returns empty JsonArray - var jsonObject = Json.createObjectBuilder() - .add("key", "value") - .build(); - var response = mock(Response.class); - var responseBody = mock(ResponseBody.class); - - when(response.body()).thenReturn(responseBody); - when(responseBody.bytes()).thenReturn("test".getBytes()); - when(mapper.readValue(any(byte[].class), eq(JsonObject.class))).thenReturn(jsonObject); - - assertThatThrownBy(() -> delegate.parseResponse().apply(response)).isInstanceOf(EdcException.class); - } - - @Override - protected DspHttpDispatcherDelegate delegate() { - return delegate; - } - - private JsonObject getJsonObject() { - return Json.createObjectBuilder() - .add(CONTEXT, Json.createObjectBuilder().add("prefix", "http://schema").build()) - .add("prefix:key", "value") - .build(); - } - - private CatalogRequestMessage message() { - return CatalogRequestMessage.Builder.newInstance() - .counterPartyAddress("http://connector") - .protocol("protocol") - .querySpec(QuerySpec.max()) - .build(); - } -} diff --git a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java index ff67e219f6f..dee5da6bff4 100644 --- a/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java +++ b/data-protocols/dsp/dsp-catalog/dsp-catalog-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/catalog/dispatcher/delegate/DatasetRequestHttpRawDelegateTest.java @@ -25,8 +25,6 @@ import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.catalog.dispatcher.CatalogApiPaths.DATASET_REQUEST; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,22 +34,7 @@ class DatasetRequestHttpRawDelegateTest extends DspHttpDispatcherDelegateTestBas @BeforeEach void setUp() { - delegate = new DatasetRequestHttpRawDelegate(serializer); - } - - @Test - void getMessageType_returnDatasetRequest() { - assertThat(delegate.getMessageType()).isEqualTo(DatasetRequestMessage.class); - } - - @Test - void buildRequest_returnRequest() { - var message = message(); - - var httpRequest = delegate().buildRequest(message); - - assertThat(httpRequest.method()).isEqualTo("GET"); - assertThat(httpRequest.url().url()).hasToString(message.getCounterPartyAddress() + BASE_PATH + DATASET_REQUEST + "/" + message.getDatasetId()); + delegate = new DatasetRequestHttpRawDelegate(); } @Test diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImpl.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImpl.java index ed5fd5f8198..2f010a920cf 100644 --- a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImpl.java +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImpl.java @@ -19,6 +19,7 @@ import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRemoteMessageDispatcher; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRequestFactory; import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.http.EdcHttpClient; @@ -44,7 +45,7 @@ */ public class DspHttpRemoteMessageDispatcherImpl implements DspHttpRemoteMessageDispatcher { - private final Map, DspHttpDispatcherDelegate> delegates = new HashMap<>(); + private final Map, Handlers> handlers = new HashMap<>(); private final Map, PolicyScope> policyScopes = new HashMap<>(); private final EdcHttpClient httpClient; private final IdentityService identityService; @@ -90,12 +91,12 @@ public CompletableFuture send(Class responseT @Override public CompletableFuture> dispatch(Class responseType, M message) { - var delegate = (DspHttpDispatcherDelegate) delegates.get(message.getClass()); - if (delegate == null) { + var handlers = (Handlers) this.handlers.get(message.getClass()); + if (handlers == null) { return failedFuture(new EdcException(format("No DSP message dispatcher found for message type %s", message.getClass()))); } - var request = delegate.buildRequest(message); + var request = handlers.requestFactory.createRequest(message); var tokenParametersBuilder = tokenDecorator.decorate(TokenParameters.Builder.newInstance()); @@ -118,21 +119,23 @@ public CompletableFuture> dispatch( .header("Authorization", token.getToken()) .build(); - return httpClient.executeAsync(requestWithAuth, List.of(retryWhenStatusNot2xxOr4xx()), delegate.handleResponse()); + return httpClient.executeAsync(requestWithAuth, List.of(retryWhenStatusNot2xxOr4xx()), handlers.delegate.handleResponse()); }) .orElse(failure -> failedFuture(new EdcException(format("Unable to obtain credentials: %s", failure.getFailureDetail())))); } @Override - public void registerDelegate(DspHttpDispatcherDelegate delegate) { - delegates.put(delegate.getMessageType(), delegate); + public void registerPolicyScope(Class messageClass, String scope, Function policyProvider) { + policyScopes.put(messageClass, new PolicyScope<>(messageClass, scope, policyProvider)); } @Override - public void registerPolicyScope(Class messageClass, String scope, Function policyProvider) { - policyScopes.put(messageClass, new PolicyScope(messageClass, scope, policyProvider)); + public void registerMessage(Class clazz, DspHttpRequestFactory requestFactory, DspHttpDispatcherDelegate delegate) { + handlers.put(clazz, new Handlers<>(requestFactory, delegate)); } + private record Handlers(DspHttpRequestFactory requestFactory, DspHttpDispatcherDelegate delegate) { } + private record PolicyScope(Class messageClass, String scope, Function policyProvider) {} } diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java new file mode 100644 index 00000000000..fe9ca9f98f9 --- /dev/null +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 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.dispatcher; + +import okhttp3.HttpUrl; +import okhttp3.Request; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRequestFactory; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.RequestPathProvider; +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; + +public class GetDspHttpRequestFactory implements DspHttpRequestFactory { + private final RequestPathProvider pathProvider; + + public GetDspHttpRequestFactory(RequestPathProvider pathProvider) { + this.pathProvider = pathProvider; + } + + @Override + public Request createRequest(M message) { + var url = HttpUrl.get(message.getCounterPartyAddress() + pathProvider.providePath(message)); + + return new Request.Builder() + .url(url) + .get() + .build(); + } +} diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java new file mode 100644 index 00000000000..eb8039718ec --- /dev/null +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 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.dispatcher; + +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRequestFactory; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.RequestPathProvider; +import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; + +public class PostDspHttpRequestFactory implements DspHttpRequestFactory { + + public static final String APPLICATION_JSON = "application/json"; + private final RequestPathProvider pathProvider; + private final JsonLdRemoteMessageSerializer serializer; + + public PostDspHttpRequestFactory(JsonLdRemoteMessageSerializer serializer, RequestPathProvider pathProvider) { + this.serializer = serializer; + this.pathProvider = pathProvider; + } + + @Override + public Request createRequest(M message) { + var body = serializer.serialize(message); + var requestBody = RequestBody.create(body, MediaType.get(APPLICATION_JSON)); + + var url = HttpUrl.get(message.getCounterPartyAddress() + pathProvider.providePath(message)); + + return new Request.Builder() + .url(url) + .header("Content-Type", APPLICATION_JSON) + .post(requestBody) + .build(); + } + +} diff --git a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtensionTest.java b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtensionTest.java index 2e2efc292c6..174540c32cf 100644 --- a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtensionTest.java +++ b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/DspHttpCoreExtensionTest.java @@ -14,24 +14,17 @@ package org.eclipse.edc.protocol.dsp; -import okhttp3.Request; -import okhttp3.Response; import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; -import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.spi.iam.IdentityService; import org.eclipse.edc.spi.iam.TokenDecorator; -import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.spi.system.injection.ObjectFactory; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import java.util.function.Function; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; @@ -41,78 +34,39 @@ @ExtendWith(DependencyInjectionExtension.class) class DspHttpCoreExtensionTest { + private final IdentityService identityService = mock(); private DspHttpCoreExtension extension; @BeforeEach void setUp(ServiceExtensionContext context) { - context.registerService(RemoteMessageDispatcherRegistry.class, mock(RemoteMessageDispatcherRegistry.class)); - + context.registerService(IdentityService.class, identityService); } @Test @DisplayName("Assert usage of the default (noop) token decorator") void createDispatcher_noTokenDecorator_shouldUseNoop(ServiceExtensionContext context, ObjectFactory factory) { - var isMock = mock(IdentityService.class); - when(isMock.obtainClientCredentials(any())).thenReturn(Result.failure("not-important")); - context.registerService(IdentityService.class, isMock); + when(identityService.obtainClientCredentials(any())).thenReturn(Result.failure("not-important")); context.registerService(TokenDecorator.class, null); - extension = factory.constructInstance(DspHttpCoreExtension.class); var dispatcher = extension.dspHttpRemoteMessageDispatcher(context); - dispatcher.registerDelegate(new TestMessageDelegate()); - dispatcher.dispatch(String.class, new TestMessage()); + dispatcher.registerMessage(TestMessage.class, mock(), mock()); + dispatcher.dispatch(String.class, new TestMessage("protocol", "address")); - verify(isMock).obtainClientCredentials(argThat(tokenParams -> tokenParams.getScope() == null)); + verify(identityService).obtainClientCredentials(argThat(tokenParams -> tokenParams.getScope() == null)); } @Test @DisplayName("Assert usage of an injected TokenDecorator") void createDispatcher_withTokenDecorator_shouldUse(ServiceExtensionContext context, ObjectFactory factory) { - var isMock = mock(IdentityService.class); - when(isMock.obtainClientCredentials(any())).thenReturn(Result.failure("not-important")); - context.registerService(IdentityService.class, isMock); + when(identityService.obtainClientCredentials(any())).thenReturn(Result.failure("not-important")); context.registerService(TokenDecorator.class, (td) -> td.scope("test-scope")); - extension = factory.constructInstance(DspHttpCoreExtension.class); var dispatcher = extension.dspHttpRemoteMessageDispatcher(context); - dispatcher.registerDelegate(new TestMessageDelegate()); - dispatcher.dispatch(String.class, new TestMessage()); - - verify(isMock).obtainClientCredentials(argThat(tokenParams -> tokenParams.getScope().equals("test-scope"))); - } - - private static class TestMessage implements RemoteMessage { - @Override - public String getProtocol() { - return null; - } - - @Override - public String getCounterPartyAddress() { - return "http://connector"; - } - } - - private static class TestMessageDelegate extends DspHttpDispatcherDelegate { - protected TestMessageDelegate() { - super(null); - } - - @Override - public Class getMessageType() { - return TestMessage.class; - } - - @Override - public Request buildRequest(TestMessage message) { - return null; - } + dispatcher.registerMessage(TestMessage.class, mock(), mock()); + dispatcher.dispatch(String.class, new TestMessage("protocol", "address")); - @Override - public Function parseResponse() { - return null; - } + verify(identityService).obtainClientCredentials(argThat(tokenParams -> tokenParams.getScope().equals("test-scope"))); } } diff --git a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/TestMessage.java b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/TestMessage.java new file mode 100644 index 00000000000..c408511083b --- /dev/null +++ b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/TestMessage.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 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; + +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; + +public record TestMessage(String protocol, String counterPartyAddress) implements RemoteMessage { + @Override + public String getProtocol() { + return protocol; + } + + @Override + public String getCounterPartyAddress() { + return counterPartyAddress; + } +} diff --git a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImplTest.java b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImplTest.java index 6c7da4b4079..0873b7e025e 100644 --- a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImplTest.java +++ b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/DspHttpRemoteMessageDispatcherImplTest.java @@ -21,6 +21,7 @@ import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRemoteMessageDispatcher; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRequestFactory; import org.eclipse.edc.spi.EdcException; import org.eclipse.edc.spi.http.EdcHttpClient; import org.eclipse.edc.spi.iam.IdentityService; @@ -54,21 +55,20 @@ class DspHttpRemoteMessageDispatcherImplTest { - private final EdcHttpClient httpClient = mock(EdcHttpClient.class); - private final IdentityService identityService = mock(IdentityService.class); + private final EdcHttpClient httpClient = mock(); + private final IdentityService identityService = mock(); + private final PolicyEngine policyEngine = mock(); + private final TokenDecorator tokenDecorator = mock(); + private final DspHttpRequestFactory requestFactory = mock(); private final DspHttpDispatcherDelegate delegate = mock(); - private final PolicyEngine policyEngine = mock(PolicyEngine.class); private final Duration timeout = Duration.of(5, SECONDS); private DspHttpRemoteMessageDispatcher dispatcher; - private TokenDecorator tokenDecoratorMock; @BeforeEach void setUp() { - tokenDecoratorMock = mock(TokenDecorator.class); - when(tokenDecoratorMock.decorate(any())).thenAnswer(a -> a.getArgument(0)); - dispatcher = new DspHttpRemoteMessageDispatcherImpl(httpClient, identityService, tokenDecoratorMock, policyEngine); - when(delegate.getMessageType()).thenReturn(TestMessage.class); + when(tokenDecorator.decorate(any())).thenAnswer(a -> a.getArgument(0)); + dispatcher = new DspHttpRemoteMessageDispatcherImpl(httpClient, identityService, tokenDecorator, policyEngine); } @Test @@ -82,20 +82,20 @@ void dispatch_sendRequestViaHttpClient() { Function> responseFunction = response -> StatusResult.success(responseBody); var authToken = "token"; - when(delegate.buildRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); + when(requestFactory.createRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); when(delegate.handleResponse()).thenReturn(responseFunction); when(httpClient.executeAsync(any(), any(), any())).thenReturn(completedFuture(responseBody)); when(identityService.obtainClientCredentials(any())) .thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token(authToken).build())); - dispatcher.registerDelegate(delegate); + dispatcher.registerMessage(TestMessage.class, requestFactory, delegate); var message = new TestMessage(); var result = dispatcher.dispatch(String.class, message); assertThat(result).succeedsWithin(timeout).isEqualTo(responseBody); - verify(delegate).buildRequest(message); + verify(requestFactory).createRequest(message); verify(identityService).obtainClientCredentials(argThat(tr -> tr.getAudience().equals(message.getCounterPartyAddress()))); verify(httpClient).executeAsync(argThat(r -> authToken.equals(r.headers().get("Authorization"))), any(), eq(responseFunction)); } @@ -108,14 +108,14 @@ void dispatch_ensureTokenDecoratorScope() { Map additional = Map.of("foo", "bar"); - when(tokenDecoratorMock.decorate(any())).thenAnswer(a -> a.getArgument(0, TokenParameters.Builder.class).scope("test-scope").additional(additional)); - when(delegate.buildRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); + when(tokenDecorator.decorate(any())).thenAnswer(a -> a.getArgument(0, TokenParameters.Builder.class).scope("test-scope").additional(additional)); + when(requestFactory.createRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); when(delegate.handleResponse()).thenReturn(responseFunction); when(httpClient.executeAsync(any(), any(), any())).thenReturn(completedFuture(responseBody)); when(identityService.obtainClientCredentials(any())) .thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token(authToken).build())); - dispatcher.registerDelegate(delegate); + dispatcher.registerMessage(TestMessage.class, requestFactory, delegate); var message = new TestMessage(); var result = dispatcher.dispatch(String.class, message); @@ -123,8 +123,6 @@ void dispatch_ensureTokenDecoratorScope() { assertThat(result).succeedsWithin(timeout); var captor = ArgumentCaptor.forClass(TokenParameters.class); - - verify(delegate).buildRequest(message); verify(identityService).obtainClientCredentials(captor.capture()); verify(httpClient).executeAsync(argThat(r -> authToken.equals(r.headers().get("Authorization"))), any(), eq(responseFunction)); @@ -146,8 +144,8 @@ void dispatch_noDelegateFound_throwException() { @Test void dispatch_failedToObtainToken_throwException() { - dispatcher.registerDelegate(delegate); - when(delegate.buildRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); + dispatcher.registerMessage(TestMessage.class, requestFactory, delegate); + when(requestFactory.createRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); when(identityService.obtainClientCredentials(any())).thenReturn(Result.failure("error")); assertThat(dispatcher.dispatch(String.class, new TestMessage())).failsWithin(timeout) @@ -158,12 +156,12 @@ void dispatch_failedToObtainToken_throwException() { @Test void dispatch_shouldNotEvaluatePolicy_whenItIsNotRegistered() { - when(delegate.buildRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); + when(requestFactory.createRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); when(delegate.handleResponse()).thenReturn(response -> null); when(httpClient.executeAsync(any(), any(), any())).thenReturn(completedFuture(null)); when(identityService.obtainClientCredentials(any())) .thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("any").build())); - dispatcher.registerDelegate(delegate); + dispatcher.registerMessage(TestMessage.class, requestFactory, delegate); var result = dispatcher.dispatch(String.class, new TestMessage()); @@ -173,12 +171,12 @@ void dispatch_shouldNotEvaluatePolicy_whenItIsNotRegistered() { @Test void dispatch_shouldEvaluatePolicy() { - when(delegate.buildRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); + when(requestFactory.createRequest(any())).thenReturn(new Request.Builder().url("http://url").build()); when(delegate.handleResponse()).thenReturn(response -> null); when(httpClient.executeAsync(any(), any(), any())).thenReturn(completedFuture(null)); when(identityService.obtainClientCredentials(any())) .thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("any").build())); - dispatcher.registerDelegate(delegate); + dispatcher.registerMessage(TestMessage.class, requestFactory, delegate); var policy = Policy.Builder.newInstance().build(); dispatcher.registerPolicyScope(TestMessage.class, "test.message", m -> policy); diff --git a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactoryTest.java b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactoryTest.java new file mode 100644 index 00000000000..03b00530d2c --- /dev/null +++ b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactoryTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 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.dispatcher; + +import org.eclipse.edc.protocol.dsp.TestMessage; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.RequestPathProvider; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class GetDspHttpRequestFactoryTest { + + private final RequestPathProvider pathProvider = mock(); + private final GetDspHttpRequestFactory factory = new GetDspHttpRequestFactory<>(pathProvider); + + @Test + void shouldCreateProperHttpRequest() { + when(pathProvider.providePath(any())).thenReturn("/message/request/path"); + + var message = new TestMessage("protocol", "http://counter-party"); + var request = factory.createRequest(message); + + assertThat(request.url().url().toString()).isEqualTo("http://counter-party/message/request/path"); + assertThat(request.method()).isEqualTo("GET"); + } +} diff --git a/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactoryTest.java b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactoryTest.java new file mode 100644 index 00000000000..60903bda5b7 --- /dev/null +++ b/data-protocols/dsp/dsp-http-core/src/test/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactoryTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 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.dispatcher; + +import okhttp3.MediaType; +import okio.Buffer; +import org.eclipse.edc.protocol.dsp.TestMessage; +import org.eclipse.edc.protocol.dsp.spi.dispatcher.RequestPathProvider; +import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class PostDspHttpRequestFactoryTest { + + private final RequestPathProvider pathProvider = mock(); + private final JsonLdRemoteMessageSerializer serializer = mock(); + private final PostDspHttpRequestFactory factory = new PostDspHttpRequestFactory<>(serializer, pathProvider); + + @Test + void shouldCreateProperHttpRequest() { + when(serializer.serialize(any())).thenReturn("serializedMessage"); + when(pathProvider.providePath(any())).thenReturn("/message/request/path"); + + var message = new TestMessage("protocol", "http://counter-party"); + var request = factory.createRequest(message); + + assertThat(request.url().url().toString()).isEqualTo("http://counter-party/message/request/path"); + assertThat(request.method()).isEqualTo("POST"); + assertThat(request.header("Content-Type")).isEqualTo("application/json"); + assertThat(request.body()).isNotNull().satisfies(body -> { + assertThat(body.contentType()).isNotNull().extracting(MediaType::toString).isEqualTo("application/json; charset=utf-8"); + try (var buffer = new Buffer()) { + body.writeTo(buffer); + assertThat(buffer.toString()).contains("serializedMessage"); + } + + }); + } +} diff --git a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java index 32e7ae0f6ac..6f64c407ba0 100644 --- a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java +++ b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegate.java @@ -14,13 +14,8 @@ package org.eclipse.edc.protocol.dsp.spi.dispatcher; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.spi.response.StatusResult; import org.eclipse.edc.spi.types.domain.message.RemoteMessage; @@ -39,30 +34,9 @@ */ public abstract class DspHttpDispatcherDelegate { - private static final String APPLICATION_JSON = "application/json"; - - private final JsonLdRemoteMessageSerializer serializer; - - protected DspHttpDispatcherDelegate(JsonLdRemoteMessageSerializer serializer) { - this.serializer = serializer; + protected DspHttpDispatcherDelegate() { } - /** - * Returns the type of {@link RemoteMessage} this delegate can handle. - * - * @return the message type - */ - public abstract Class getMessageType(); - - /** - * Builds the HTTP request for the message including method, URL, body and headers. The - * Authorization header can be omitted as it is handled centrally. - * - * @param message the message - * @return the request builder - */ - public abstract Request buildRequest(M message); - /** * Handles the response and returns a {@link StatusResult} containing the response object * @@ -93,19 +67,6 @@ public Function> handleResponse() { */ protected abstract Function parseResponse(); - protected Request buildPostRequest(M message, String path) { - var body = serializer.serialize(message); - var requestBody = RequestBody.create(body, MediaType.get(APPLICATION_JSON)); - - var url = HttpUrl.get(message.getCounterPartyAddress() + path); - - return new Request.Builder() - .url(url) - .header("Content-Type", APPLICATION_JSON) - .post(requestBody) - .build(); - } - private String asString(ResponseBody it) { try { return it.string(); diff --git a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRemoteMessageDispatcher.java b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRemoteMessageDispatcher.java index 0d0dd8e644b..3f6e97040c8 100644 --- a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRemoteMessageDispatcher.java +++ b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRemoteMessageDispatcher.java @@ -24,15 +24,17 @@ * {@link RemoteMessageDispatcher} for sending dataspace protocol messages. */ public interface DspHttpRemoteMessageDispatcher extends RemoteMessageDispatcher { - + /** - * Registers a {@link DspHttpDispatcherDelegate} for supporting a specific type of remote message. + * Registers a message request factory and response parser * - * @param delegate the delegate + * @param clazz the message class. + * @param requestFactory the request factory. + * @param delegate the response parser delegate. * @param the type of message * @param the response type */ - void registerDelegate(DspHttpDispatcherDelegate delegate); + void registerMessage(Class clazz, DspHttpRequestFactory requestFactory, DspHttpDispatcherDelegate delegate); /** * Registers a {@link Policy} scope to be evaluated for certain types of messages diff --git a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRequestFactory.java b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRequestFactory.java new file mode 100644 index 00000000000..63603520ea8 --- /dev/null +++ b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpRequestFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 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.spi.dispatcher; + +import okhttp3.Request; +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; + +/** + * Creates an HTTP request for the DSP HTTP Bindings given the message instance + * + * @param the message type. + */ +@FunctionalInterface +public interface DspHttpRequestFactory { + + /** + * Create the request given the message and a {@link RequestPathProvider} + * + * @param message the message. + * @return the request. + */ + Request createRequest(M message); +} diff --git a/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/RequestPathProvider.java b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/RequestPathProvider.java new file mode 100644 index 00000000000..77ad2cde990 --- /dev/null +++ b/data-protocols/dsp/dsp-http-spi/src/main/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/RequestPathProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 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.spi.dispatcher; + + +import org.eclipse.edc.spi.types.domain.message.RemoteMessage; + +/** + * Provide http request path given the outgoing message. + * + * @param the message type + */ +@FunctionalInterface +public interface RequestPathProvider { + /** + * Return the path + * + * @param message the message. + * @return the path. + */ + String providePath(M message); +} diff --git a/data-protocols/dsp/dsp-http-spi/src/test/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegateTest.java b/data-protocols/dsp/dsp-http-spi/src/test/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegateTest.java index b8926795d90..48d9847596d 100644 --- a/data-protocols/dsp/dsp-http-spi/src/test/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegateTest.java +++ b/data-protocols/dsp/dsp-http-spi/src/test/java/org/eclipse/edc/protocol/dsp/spi/dispatcher/DspHttpDispatcherDelegateTest.java @@ -91,17 +91,7 @@ void handleResponse_shouldReturnRetryError_whenResponseIsServerError() { private class TestDspHttpDispatcherDelegate extends DspHttpDispatcherDelegate { TestDspHttpDispatcherDelegate() { - super(DspHttpDispatcherDelegateTest.this.serializer); - } - - @Override - public Class getMessageType() { - return null; - } - - @Override - public Request buildRequest(RemoteMessage message) { - return null; + super(); } @Override diff --git a/data-protocols/dsp/dsp-http-spi/src/testFixtures/java/org/eclipse/edc/protocol/dsp/spi/testfixtures/dispatcher/DspHttpDispatcherDelegateTestBase.java b/data-protocols/dsp/dsp-http-spi/src/testFixtures/java/org/eclipse/edc/protocol/dsp/spi/testfixtures/dispatcher/DspHttpDispatcherDelegateTestBase.java index b63a5d617a5..d5bfc6b9113 100644 --- a/data-protocols/dsp/dsp-http-spi/src/testFixtures/java/org/eclipse/edc/protocol/dsp/spi/testfixtures/dispatcher/DspHttpDispatcherDelegateTestBase.java +++ b/data-protocols/dsp/dsp-http-spi/src/testFixtures/java/org/eclipse/edc/protocol/dsp/spi/testfixtures/dispatcher/DspHttpDispatcherDelegateTestBase.java @@ -37,8 +37,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** @@ -59,39 +57,6 @@ public abstract class DspHttpDispatcherDelegateTestBase */ protected abstract DspHttpDispatcherDelegate delegate(); - /** - * Checks that a delegate, given a message, builds the expected HTTP request. The message should - * be serialized and added as the request body. Validates that the delegate sets the expected - * request path. Relevant for all delegates. - * - * @param message the message - * @param path the expected path - */ - protected void testBuildRequest_shouldReturnRequest(M message, String path) throws IOException { - var serializedBody = "serialized"; - - when(serializer.serialize(eq(message))).thenReturn(serializedBody); - - var httpRequest = delegate().buildRequest(message); - - assertThat(httpRequest.url().url()).hasToString(message.getCounterPartyAddress() + path); - assertThat(readRequestBody(httpRequest)).isEqualTo(serializedBody); - - verify(serializer, times(1)).serialize(eq(message)); - } - - /** - * Checks that a delegate throws an exception if serialization of the message to send fails. - * Relevant for all delegates. - * - * @param message the message - */ - protected void testBuildRequest_shouldThrowException_whenSerializationFails(M message) { - when(serializer.serialize(eq(message))).thenThrow(EdcException.class); - - assertThatThrownBy(() -> delegate().buildRequest(message)).isInstanceOf(EdcException.class); - } - /** * Checks that a delegate throws an exception when the response body is missing. Only relevant * for delegates that process the response body. diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/DspNegotiationHttpDispatcherExtension.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/DspNegotiationHttpDispatcherExtension.java index 8f9b08b18f3..938ee3ce220 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/DspNegotiationHttpDispatcherExtension.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/DspNegotiationHttpDispatcherExtension.java @@ -14,7 +14,14 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher; +import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementMessage; +import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementVerificationMessage; +import org.eclipse.edc.connector.contract.spi.types.agreement.ContractNegotiationEventMessage; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationTerminationMessage; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractOfferMessage; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractRequestMessage; import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.protocol.dsp.dispatcher.PostDspHttpRequestFactory; import org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate.ContractAgreementMessageHttpDelegate; import org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate.ContractAgreementVerificationMessageHttpDelegate; import org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate.ContractNegotiationEventMessageHttpDelegate; @@ -29,6 +36,14 @@ import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.spi.types.TypeManager; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.AGREEMENT; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.CONTRACT_OFFER; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.CONTRACT_REQUEST; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.EVENT; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.INITIAL_CONTRACT_REQUEST; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.TERMINATION; +import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.VERIFICATION; import static org.eclipse.edc.spi.CoreConstants.JSON_LD; @Extension(value = DspNegotiationHttpDispatcherExtension.NAME) @@ -52,11 +67,41 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { - messageDispatcher.registerDelegate(new ContractAgreementMessageHttpDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new ContractAgreementVerificationMessageHttpDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new ContractNegotiationEventMessageHttpDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new ContractNegotiationTerminationMessageHttpDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new ContractRequestMessageHttpDelegate(remoteMessageSerializer, typeManager.getMapper(JSON_LD), jsonLdService)); - messageDispatcher.registerDelegate(new ContractOfferMessageHttpDelegate(remoteMessageSerializer)); + messageDispatcher.registerMessage( + ContractAgreementMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + AGREEMENT), + new ContractAgreementMessageHttpDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + ContractAgreementVerificationMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + AGREEMENT + VERIFICATION), + new ContractAgreementVerificationMessageHttpDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + ContractNegotiationEventMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + EVENT), + new ContractNegotiationEventMessageHttpDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + ContractNegotiationTerminationMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + TERMINATION), + new ContractNegotiationTerminationMessageHttpDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + ContractRequestMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> { + if (m.getType() == ContractRequestMessage.Type.INITIAL) { + return BASE_PATH + INITIAL_CONTRACT_REQUEST; + } else { + return BASE_PATH + m.getProcessId() + CONTRACT_REQUEST; + } + }), + new ContractRequestMessageHttpDelegate(remoteMessageSerializer, typeManager.getMapper(JSON_LD), jsonLdService) + ); + messageDispatcher.registerMessage( + ContractOfferMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + CONTRACT_OFFER), + new ContractOfferMessageHttpDelegate(remoteMessageSerializer) + ); } } diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java index db553cb263a..32c9a8762d9 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegate.java @@ -14,7 +14,6 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -22,33 +21,13 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.AGREEMENT; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; - /** * Delegate for dispatching contract agreement message as defined in the dataspace protocol specification. */ public class ContractAgreementMessageHttpDelegate extends DspHttpDispatcherDelegate { public ContractAgreementMessageHttpDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return ContractAgreementMessage.class; - } - - /** - * Sends a contract agreement message. The request body is constructed as defined in the dataspace - * protocol. The request is sent to the remote component using the path from the http binding. - * - * @param message the message. - * @return the built okhttp request. - */ - @Override - public Request buildRequest(ContractAgreementMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT); + super(); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java index c82d816e0dc..c260b9a4f65 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegate.java @@ -14,7 +14,6 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementVerificationMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -22,35 +21,13 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.AGREEMENT; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.VERIFICATION; - /** * Delegate for dispatching contract agreement verification message as defined in the dataspace protocol specification. */ public class ContractAgreementVerificationMessageHttpDelegate extends DspHttpDispatcherDelegate { public ContractAgreementVerificationMessageHttpDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return ContractAgreementVerificationMessage.class; - } - - /** - * Sends a contract agreement verification message. The request body is constructed as defined in - * the dataspace protocol. The request is sent to the remote component using the path from the http - * binding. - * - * @param message the message. - * @return the built okhttp request. - */ - @Override - public Request buildRequest(ContractAgreementVerificationMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT + VERIFICATION); + super(); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java index a0e3c63853f..87195908a12 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegate.java @@ -14,7 +14,6 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractNegotiationEventMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -22,34 +21,13 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.EVENT; - /** * Delegate for dispatching contract negotiation event message as defined in the dataspace protocol specification. */ public class ContractNegotiationEventMessageHttpDelegate extends DspHttpDispatcherDelegate { public ContractNegotiationEventMessageHttpDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return ContractNegotiationEventMessage.class; - } - - /** - * Sends a contract negotiation event message. The request body is constructed as defined in the - * dataspace protocol. The request is sent to the remote component using the path from the http - * binding. - * - * @param message the message. - * @return the built okhttp request. - */ - @Override - public Request buildRequest(ContractNegotiationEventMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + EVENT); + super(); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java index 148cd3c7a02..c80f7c12d02 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegate.java @@ -14,7 +14,6 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationTerminationMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -22,34 +21,13 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.TERMINATION; - /** * Delegate for dispatching contract negotiation termination message as defined in the dataspace protocol specification. */ public class ContractNegotiationTerminationMessageHttpDelegate extends DspHttpDispatcherDelegate { public ContractNegotiationTerminationMessageHttpDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return ContractNegotiationTerminationMessage.class; - } - - /** - * Sends a contract negotiation termination message. The request body is constructed as defined - * in the dataspace protocol. The request is sent to the remote component using the path from the - * http binding. - * - * @param message the message. - * @return the built okhttp request. - */ - @Override - public Request buildRequest(ContractNegotiationTerminationMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + TERMINATION); + super(); } /** diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java index ea88a0369ab..3d66c8b9c88 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegate.java @@ -14,7 +14,6 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractOfferMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -22,28 +21,15 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.CONTRACT_OFFER; - /** * Delegate for dispatching contract offer message as defined in the dataspace protocol specification. */ public class ContractOfferMessageHttpDelegate extends DspHttpDispatcherDelegate { public ContractOfferMessageHttpDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); + super(); } - - @Override - public Class getMessageType() { - return ContractOfferMessage.class; - } - - @Override - public Request buildRequest(ContractOfferMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_OFFER); - } - + @Override protected Function parseResponse() { return response -> null; diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java index 10e83018eee..dabbd8bac39 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegate.java @@ -16,7 +16,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.json.JsonObject; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractRequestMessage; import org.eclipse.edc.jsonld.spi.JsonLd; @@ -27,10 +26,6 @@ import java.io.IOException; import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.CONTRACT_REQUEST; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.INITIAL_CONTRACT_REQUEST; - /** * Delegate for dispatching contract request message as defined in the dataspace protocol specification. */ @@ -41,32 +36,11 @@ public class ContractRequestMessageHttpDelegate extends DspHttpDispatcherDelegat public ContractRequestMessageHttpDelegate(JsonLdRemoteMessageSerializer serializer, ObjectMapper mapper, JsonLd jsonLdService) { - super(serializer); + super(); this.mapper = mapper; this.jsonLdService = jsonLdService; } - @Override - public Class getMessageType() { - return ContractRequestMessage.class; - } - - /** - * Sends a contract request message. The request body is constructed as defined in the dataspace - * protocol. The request is sent to the remote component using the path from the http binding. - * - * @param message the message. - * @return the built okhttp request. - */ - @Override - public Request buildRequest(ContractRequestMessage message) { - if (message.getType() == ContractRequestMessage.Type.INITIAL) { - return buildPostRequest(message, BASE_PATH + INITIAL_CONTRACT_REQUEST); - } else { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_REQUEST); - } - } - @Override public Function parseResponse() { return response -> { diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegateTest.java index 2d20e37785c..e2631c31f63 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegateTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementMessageHttpDelegateTest.java @@ -14,25 +14,12 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreementMessage; -import org.eclipse.edc.policy.model.Action; -import org.eclipse.edc.policy.model.Duty; -import org.eclipse.edc.policy.model.Permission; -import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.policy.model.Prohibition; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static java.util.UUID.randomUUID; -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.AGREEMENT; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; - class ContractAgreementMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { private ContractAgreementMessageHttpDelegate delegate; @@ -42,58 +29,11 @@ void setUp() { delegate = new ContractAgreementMessageHttpDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(ContractAgreementMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private ContractAgreementMessage message() { - var value = "example"; - return ContractAgreementMessage.Builder.newInstance() - .protocol(value) - .processId(value) - .counterPartyAddress("http://connector") - .contractAgreement(contractAgreement()) - .build(); - } - - private ContractAgreement contractAgreement() { - return ContractAgreement.Builder.newInstance() - .id(randomUUID().toString()) - .providerId("agentId") - .consumerId("agentId") - .assetId("assetId") - .policy(policy()).build(); - } - - private Policy policy() { - var action = Action.Builder.newInstance().type("USE").build(); - var permission = Permission.Builder.newInstance().action(action).build(); - var prohibition = Prohibition.Builder.newInstance().action(action).build(); - var duty = Duty.Builder.newInstance().action(action).build(); - return Policy.Builder.newInstance() - .permission(permission) - .prohibition(prohibition) - .duty(duty) - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegateTest.java index b809f655df2..5d7084ea138 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegateTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractAgreementVerificationMessageHttpDelegateTest.java @@ -20,13 +20,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.AGREEMENT; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.VERIFICATION; - class ContractAgreementVerificationMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { private ContractAgreementVerificationMessageHttpDelegate delegate; @@ -36,36 +29,11 @@ void setUp() { delegate = new ContractAgreementVerificationMessageHttpDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(ContractAgreementVerificationMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + AGREEMENT + VERIFICATION); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private ContractAgreementVerificationMessage message() { - var value = "example"; - return ContractAgreementVerificationMessage.Builder.newInstance() - .protocol(value) - .processId(value) - .counterPartyAddress("http://connector") - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegateTest.java index 4e9c7273265..70d175b045a 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegateTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationEventMessageHttpDelegateTest.java @@ -20,12 +20,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.EVENT; - class ContractNegotiationEventMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { private ContractNegotiationEventMessageHttpDelegate delegate; @@ -35,37 +29,11 @@ void setUp() { delegate = new ContractNegotiationEventMessageHttpDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(ContractNegotiationEventMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + EVENT); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private ContractNegotiationEventMessage message() { - var value = "example"; - return ContractNegotiationEventMessage.Builder.newInstance() - .protocol(value) - .processId(value) - .counterPartyAddress("http://connector") - .type(ContractNegotiationEventMessage.Type.FINALIZED) - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegateTest.java index 2a31ff64574..69e59dbb75d 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegateTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractNegotiationTerminationMessageHttpDelegateTest.java @@ -20,12 +20,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.TERMINATION; - class ContractNegotiationTerminationMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { private ContractNegotiationTerminationMessageHttpDelegate delegate; @@ -35,37 +29,11 @@ void setUp() { delegate = new ContractNegotiationTerminationMessageHttpDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(ContractNegotiationTerminationMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + TERMINATION); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private ContractNegotiationTerminationMessage message() { - var value = "example"; - return ContractNegotiationTerminationMessage.Builder.newInstance() - .protocol(value) - .processId(value) - .counterPartyAddress("http://connector") - .rejectionReason(value) - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegateTest.java index c3652655180..a516df535f9 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegateTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractOfferMessageHttpDelegateTest.java @@ -15,20 +15,11 @@ package org.eclipse.edc.protocol.dsp.negotiation.dispatcher.delegate; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractOfferMessage; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; -import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static java.util.UUID.randomUUID; -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.CONTRACT_OFFER; - class ContractOfferMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { private ContractOfferMessageHttpDelegate delegate; @@ -37,23 +28,7 @@ class ContractOfferMessageHttpDelegateTest extends DspHttpDispatcherDelegateTest void setUp() { delegate = new ContractOfferMessageHttpDelegate(serializer); } - - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(ContractOfferMessage.class); - } - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_OFFER); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_shouldReturnNullFunction() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); @@ -63,22 +38,5 @@ void parseResponse_shouldReturnNullFunction() { protected DspHttpDispatcherDelegate delegate() { return delegate; } - - private ContractOfferMessage message() { - return ContractOfferMessage.Builder.newInstance() - .protocol("dsp") - .processId("processId") - .counterPartyAddress("http://connector") - .contractOffer(contractOffer()) - .callbackAddress("http://callback") - .build(); - } - - private ContractOffer contractOffer() { - return ContractOffer.Builder.newInstance() - .id(randomUUID().toString()) - .assetId("assetId") - .policy(Policy.Builder.newInstance().build()) - .build(); - } + } diff --git a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegateTest.java b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegateTest.java index 2582dd0b2d0..e71ba606864 100644 --- a/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegateTest.java +++ b/data-protocols/dsp/dsp-negotiation/dsp-negotiation-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/negotiation/dispatcher/delegate/ContractRequestMessageHttpDelegateTest.java @@ -19,14 +19,8 @@ import okhttp3.Response; import okhttp3.ResponseBody; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractRequestMessage; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; import org.eclipse.edc.jsonld.TitaniumJsonLd; import org.eclipse.edc.jsonld.spi.JsonLdKeywords; -import org.eclipse.edc.policy.model.Action; -import org.eclipse.edc.policy.model.Duty; -import org.eclipse.edc.policy.model.Permission; -import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.policy.model.Prohibition; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; import org.eclipse.edc.spi.monitor.Monitor; @@ -35,11 +29,7 @@ import java.io.IOException; -import static java.util.UUID.randomUUID; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.CONTRACT_REQUEST; -import static org.eclipse.edc.protocol.dsp.negotiation.dispatcher.NegotiationApiPaths.INITIAL_CONTRACT_REQUEST; import static org.eclipse.edc.protocol.dsp.type.DspNegotiationPropertyAndTypeNames.DSPACE_TYPE_CONTRACT_NEGOTIATION; import static org.eclipse.edc.protocol.dsp.type.DspNegotiationPropertyAndTypeNames.DSPACE_VALUE_NEGOTIATION_STATE_REQUESTED; import static org.eclipse.edc.protocol.dsp.type.DspPropertyAndTypeNames.DSPACE_PROPERTY_PROCESS_ID; @@ -51,8 +41,6 @@ class ContractRequestMessageHttpDelegateTest extends DspHttpDispatcherDelegateTestBase { private static final String PROCESS_ID = "processId"; - private static final String DATASET_ID = "datasetId"; - private static final String DSP = "DSP"; private ContractRequestMessageHttpDelegate delegate; private TitaniumJsonLd jsonLdService; @@ -63,27 +51,6 @@ void setUp() { delegate = new ContractRequestMessageHttpDelegate(serializer, mapper, jsonLdService); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(ContractRequestMessage.class); - } - - @Test - void buildRequest_initial() throws IOException { - testBuildRequest_shouldReturnRequest(message_initial(), BASE_PATH + INITIAL_CONTRACT_REQUEST); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + CONTRACT_REQUEST); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNegotiation() throws IOException { var response = mock(Response.class); @@ -117,48 +84,6 @@ void parseResponse_readingResponseBodyFails_throwException() throws IOException return delegate; } - private ContractRequestMessage message() { - return ContractRequestMessage.Builder.newInstance() - .protocol(DSP) - .processId(PROCESS_ID) - .counterPartyAddress("http://connector") - .dataSet(DATASET_ID) - .contractOffer(contractOffer()) - .type(ContractRequestMessage.Type.COUNTER_OFFER) - .build(); - } - - private ContractRequestMessage message_initial() { - var value = "example"; - return ContractRequestMessage.Builder.newInstance() - .protocol(value) - .processId(value) - .counterPartyAddress("http://connector") - .dataSet(value) - .contractOffer(contractOffer()) - .type(ContractRequestMessage.Type.INITIAL) - .build(); - } - - private ContractOffer contractOffer() { - return ContractOffer.Builder.newInstance() - .id(randomUUID().toString()) - .assetId("assetId") - .policy(policy()).build(); - } - - private Policy policy() { - var action = Action.Builder.newInstance().type("USE").build(); - var permission = Permission.Builder.newInstance().action(action).build(); - var prohibition = Prohibition.Builder.newInstance().action(action).build(); - var duty = Duty.Builder.newInstance().action(action).build(); - return Policy.Builder.newInstance() - .permission(permission) - .prohibition(prohibition) - .duty(duty) - .build(); - } - private JsonObject negotiation() { var builder = Json.createObjectBuilder(); builder.add(JsonLdKeywords.ID, "id1"); diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/build.gradle.kts b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/build.gradle.kts index fd474c54926..8a836d95807 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/build.gradle.kts +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/build.gradle.kts @@ -22,9 +22,10 @@ dependencies { api(project(":spi:control-plane:control-plane-spi")) api(project(":data-protocols:dsp:dsp-http-spi")) + implementation(project(":data-protocols:dsp:dsp-http-core")) implementation(project(":data-protocols:dsp:dsp-transfer-process:dsp-transfer-process-transform")) implementation(project(":extensions:common:json-ld")) testImplementation(testFixtures(project(":data-protocols:dsp:dsp-http-spi"))) -} \ No newline at end of file +} diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/DspTransferProcessDispatcherExtension.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/DspTransferProcessDispatcherExtension.java index 02db714d414..2008ba70b8e 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/DspTransferProcessDispatcherExtension.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/DspTransferProcessDispatcherExtension.java @@ -15,6 +15,11 @@ package org.eclipse.edc.protocol.dsp.transferprocess.dispatcher; +import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferCompletionMessage; +import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferRequestMessage; +import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferStartMessage; +import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferTerminationMessage; +import org.eclipse.edc.protocol.dsp.dispatcher.PostDspHttpRequestFactory; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpRemoteMessageDispatcher; import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.delegate.TransferCompletionDelegate; @@ -26,6 +31,12 @@ import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; +import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; +import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_COMPLETION; +import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_INITIAL_REQUEST; +import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_START; +import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_TERMINATION; + /** * Provides HTTP dispatching for Dataspace Protocol transfer process messages via the {@link DspHttpRemoteMessageDispatcher}. @@ -47,9 +58,25 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { - messageDispatcher.registerDelegate(new TransferRequestDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new TransferCompletionDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new TransferStartDelegate(remoteMessageSerializer)); - messageDispatcher.registerDelegate(new TransferTerminationDelegate(remoteMessageSerializer)); + messageDispatcher.registerMessage( + TransferRequestMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + TRANSFER_INITIAL_REQUEST), + new TransferRequestDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + TransferCompletionMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + TRANSFER_COMPLETION), + new TransferCompletionDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + TransferStartMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + TRANSFER_START), + new TransferStartDelegate(remoteMessageSerializer) + ); + messageDispatcher.registerMessage( + TransferTerminationMessage.class, + new PostDspHttpRequestFactory<>(remoteMessageSerializer, m -> BASE_PATH + m.getProcessId() + TRANSFER_TERMINATION), + new TransferTerminationDelegate(remoteMessageSerializer) + ); } } diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java index 09dcdfab3b8..49fbfa6ff6d 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegate.java @@ -15,7 +15,6 @@ package org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.delegate; import jakarta.json.JsonObject; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferCompletionMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -23,23 +22,10 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_COMPLETION; - public class TransferCompletionDelegate extends DspHttpDispatcherDelegate { public TransferCompletionDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return TransferCompletionMessage.class; - } - - @Override - public Request buildRequest(TransferCompletionMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_COMPLETION); + super(); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java index 157e257cc28..486b3fe1d14 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegate.java @@ -15,7 +15,6 @@ package org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.delegate; import jakarta.json.JsonObject; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferRequestMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -23,23 +22,10 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_INITIAL_REQUEST; - public class TransferRequestDelegate extends DspHttpDispatcherDelegate { public TransferRequestDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return TransferRequestMessage.class; - } - - @Override - public Request buildRequest(TransferRequestMessage message) { - return buildPostRequest(message, BASE_PATH + TRANSFER_INITIAL_REQUEST); + super(); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java index ab5a1320228..e47b28e2f08 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegate.java @@ -15,7 +15,6 @@ package org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.delegate; import jakarta.json.JsonObject; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferStartMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -23,23 +22,10 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_START; - public class TransferStartDelegate extends DspHttpDispatcherDelegate { public TransferStartDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return TransferStartMessage.class; - } - - @Override - public Request buildRequest(TransferStartMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_START); + super(); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java index 14f69b197b8..6481a1dd492 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/main/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegate.java @@ -15,7 +15,6 @@ package org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.delegate; import jakarta.json.JsonObject; -import okhttp3.Request; import okhttp3.Response; import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferTerminationMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; @@ -23,23 +22,10 @@ import java.util.function.Function; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_TERMINATION; - public class TransferTerminationDelegate extends DspHttpDispatcherDelegate { public TransferTerminationDelegate(JsonLdRemoteMessageSerializer serializer) { - super(serializer); - } - - @Override - public Class getMessageType() { - return TransferTerminationMessage.class; - } - - @Override - public Request buildRequest(TransferTerminationMessage message) { - return buildPostRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_TERMINATION); + super(); } @Override diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegateTest.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegateTest.java index e87a7a2dee3..faba2990943 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegateTest.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferCompletionDelegateTest.java @@ -20,12 +20,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_COMPLETION; - class TransferCompletionDelegateTest extends DspHttpDispatcherDelegateTestBase { private TransferCompletionDelegate delegate; @@ -35,35 +29,11 @@ void setUp() { delegate = new TransferCompletionDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(TransferCompletionMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_COMPLETION); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private TransferCompletionMessage message() { - return TransferCompletionMessage.Builder.newInstance() - .processId("testId") - .protocol("dataspace-protocol") - .counterPartyAddress("http://test-connector-address") - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegateTest.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegateTest.java index a7371a3f760..48e0b6bf07b 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegateTest.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferRequestDelegateTest.java @@ -14,22 +14,12 @@ package org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.delegate; -import jakarta.json.Json; -import jakarta.json.JsonObject; import org.eclipse.edc.connector.transfer.spi.types.protocol.TransferRequestMessage; import org.eclipse.edc.protocol.dsp.spi.dispatcher.DspHttpDispatcherDelegate; import org.eclipse.edc.protocol.dsp.spi.testfixtures.dispatcher.DspHttpDispatcherDelegateTestBase; -import org.eclipse.edc.spi.types.domain.DataAddress; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_INITIAL_REQUEST; - class TransferRequestDelegateTest extends DspHttpDispatcherDelegateTestBase { private TransferRequestDelegate delegate; @@ -39,22 +29,6 @@ void setUp() { delegate = new TransferRequestDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(TransferRequestMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + TRANSFER_INITIAL_REQUEST); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); @@ -65,23 +39,4 @@ void parseResponse_returnNull() { return delegate; } - private TransferRequestMessage message() { - return TransferRequestMessage.Builder.newInstance() - .processId("testId") - .protocol("dataspace-protocol") - .callbackAddress("http://test-connector-address") - .counterPartyAddress("http://test-connector-address") - .contractId("contractId") - .dataDestination(DataAddress.Builder.newInstance() - .type("type") - .build()) - .build(); - } - - private JsonObject getJsonObject() { - return Json.createObjectBuilder() - .add(CONTEXT, Json.createObjectBuilder().add("prefix", "http://schema").build()) - .add("prefix:key", "value") - .build(); - } } diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegateTest.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegateTest.java index 086ac0c33c5..83ec4bda372 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegateTest.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferStartDelegateTest.java @@ -20,12 +20,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_START; - class TransferStartDelegateTest extends DspHttpDispatcherDelegateTestBase { private TransferStartDelegate delegate; @@ -35,35 +29,11 @@ void setUp() { delegate = new TransferStartDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(TransferStartMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_START); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private TransferStartMessage message() { - return TransferStartMessage.Builder.newInstance() - .processId("testId") - .protocol("dataspace-protocol") - .counterPartyAddress("http://test-connector-address") - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegateTest.java b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegateTest.java index 17d35be11b7..6e44f1206e1 100644 --- a/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegateTest.java +++ b/data-protocols/dsp/dsp-transfer-process/dsp-transfer-process-http-dispatcher/src/test/java/org/eclipse/edc/protocol/dsp/transferprocess/dispatcher/delegate/TransferTerminationDelegateTest.java @@ -20,12 +20,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.BASE_PATH; -import static org.eclipse.edc.protocol.dsp.transferprocess.dispatcher.TransferProcessApiPaths.TRANSFER_TERMINATION; - class TransferTerminationDelegateTest extends DspHttpDispatcherDelegateTestBase { private TransferTerminationDelegate delegate; @@ -35,35 +29,11 @@ void setUp() { delegate = new TransferTerminationDelegate(serializer); } - @Test - void getMessageType() { - assertThat(delegate.getMessageType()).isEqualTo(TransferTerminationMessage.class); - } - - @Test - void buildRequest() throws IOException { - var message = message(); - testBuildRequest_shouldReturnRequest(message, BASE_PATH + message.getProcessId() + TRANSFER_TERMINATION); - } - - @Test - void buildRequest_serializationFails_throwException() { - testBuildRequest_shouldThrowException_whenSerializationFails(message()); - } - @Test void parseResponse_returnNull() { testParseResponse_shouldReturnNullFunction_whenResponseBodyNotProcessed(); } - private TransferTerminationMessage message() { - return TransferTerminationMessage.Builder.newInstance() - .processId("testId") - .protocol("dataspace-protocol") - .counterPartyAddress("http://test-connector-address") - .build(); - } - @Override protected DspHttpDispatcherDelegate delegate() { return delegate; diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java index 9de57111b22..4b5078f1a02 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/CatalogApiExtension.java @@ -14,8 +14,6 @@ package org.eclipse.edc.connector.api.management.catalog; -import org.eclipse.edc.catalog.spi.CatalogRequest; -import org.eclipse.edc.catalog.spi.DatasetRequest; import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToCatalogRequestTransformer; import org.eclipse.edc.connector.api.management.catalog.transform.JsonObjectToDatasetRequestTransformer; import org.eclipse.edc.connector.api.management.catalog.validation.CatalogRequestValidator; @@ -30,6 +28,9 @@ import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; import org.eclipse.edc.web.spi.WebService; +import static org.eclipse.edc.catalog.spi.CatalogRequest.CATALOG_REQUEST_TYPE; +import static org.eclipse.edc.catalog.spi.DatasetRequest.DATASET_REQUEST_TYPE; + @Extension(value = CatalogApiExtension.NAME) public class CatalogApiExtension implements ServiceExtension { @@ -62,7 +63,7 @@ public void initialize(ServiceExtensionContext context) { webService.registerResource(config.getContextAlias(), new CatalogApiController(service, transformerRegistry, validatorRegistry)); - validatorRegistry.register(CatalogRequest.CATALOG_REQUEST_TYPE, CatalogRequestValidator.instance()); - validatorRegistry.register(DatasetRequest.DATASET_REQUEST_TYPE, DatasetRequestValidator.instance()); + validatorRegistry.register(CATALOG_REQUEST_TYPE, CatalogRequestValidator.instance()); + validatorRegistry.register(DATASET_REQUEST_TYPE, DatasetRequestValidator.instance()); } } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java index afe62f289c4..1da549348f4 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/main/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformer.java @@ -51,10 +51,15 @@ public JsonObjectToCatalogRequestTransformer(Monitor monitor) { return object.get(CATALOG_REQUEST_PROVIDER_URL); }); + var querySpec = Optional.of(object) + .map(it -> it.get(CATALOG_REQUEST_QUERY_SPEC)) + .map(it -> transformObject(it, QuerySpec.class, context)) + .orElse(null); + return CatalogRequest.Builder.newInstance() .protocol(transformString(object.get(CATALOG_REQUEST_PROTOCOL), context)) - .querySpec(transformObject(object.get(CATALOG_REQUEST_QUERY_SPEC), QuerySpec.class, context)) .counterPartyAddress(transformString(counterPartyAddress, context)) + .querySpec(querySpec) .build(); } diff --git a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java index 27664a67ee7..413895496ed 100644 --- a/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java +++ b/extensions/control-plane/api/management-api/catalog-api/src/test/java/org/eclipse/edc/connector/api/management/catalog/transform/JsonObjectToCatalogRequestTransformerTest.java @@ -34,6 +34,7 @@ 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; class JsonObjectToCatalogRequestTransformerTest { @@ -91,4 +92,19 @@ void transform_shouldUseProviderId_whenCounterPartyAddressIsMissing() { verify(monitor).warning(anyString()); } + @Test + void transform_shouldHandleEmptyQuerySpec() { + var json = Json.createObjectBuilder() + .add(TYPE, CATALOG_REQUEST_TYPE) + .add(CATALOG_REQUEST_PROTOCOL, "protocol") + .add(CATALOG_REQUEST_COUNTER_PARTY_ADDRESS, "http://provider/url") + .build(); + + var result = transformer.transform(json, context); + + assertThat(result).isNotNull(); + assertThat(result.getQuerySpec()).isEqualTo(null); + verifyNoInteractions(context); + } + } diff --git a/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java index 963ca140527..96c0fb2e5b7 100644 --- a/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java +++ b/spi/common/catalog-spi/src/main/java/org/eclipse/edc/catalog/spi/CatalogRequest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import org.eclipse.edc.spi.query.QuerySpec; -import static java.util.Objects.requireNonNull; import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; public class CatalogRequest { diff --git a/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java b/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java index dd93ec5451b..e61868c06c8 100644 --- a/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java +++ b/system-tests/e2e-test-fixtures/src/testFixtures/java/org/eclipse/edc/test/system/utils/Participant.java @@ -217,7 +217,7 @@ public JsonObject getDatasetForAsset(Participant provider, String assetId) { .contentType(JSON) .when() .body(requestBody) - .post("/v2/catalog/request") + .post("/v2/catalog/dataset/request") .then() .log().all() .statusCode(200) diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java index 0676d3c91b5..712858e18a7 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/CatalogApiEndToEndTest.java @@ -57,6 +57,7 @@ void requestCatalog_shouldReturnCatalog_withoutQuerySpec() { .body(requestBody) .post("/v2/catalog/request") .then() + .log().ifError() .statusCode(200) .contentType(JSON) .body(TYPE, is("dcat:Catalog")); From 33dd6149cc4fc62c605e6cf85064fe16fb8764cc Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Wed, 2 Aug 2023 14:18:03 +0200 Subject: [PATCH 4/4] PR remarks --- .../protocol/dsp/dispatcher/GetDspHttpRequestFactory.java | 5 +++++ .../protocol/dsp/dispatcher/PostDspHttpRequestFactory.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java index fe9ca9f98f9..bf6574fb185 100644 --- a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/GetDspHttpRequestFactory.java @@ -20,6 +20,11 @@ import org.eclipse.edc.protocol.dsp.spi.dispatcher.RequestPathProvider; import org.eclipse.edc.spi.types.domain.message.RemoteMessage; +/** + * Creates a GET request through the Dataspace Protocol + * + * @param the message class. + */ public class GetDspHttpRequestFactory implements DspHttpRequestFactory { private final RequestPathProvider pathProvider; diff --git a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java index eb8039718ec..c9bcc634d3a 100644 --- a/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java +++ b/data-protocols/dsp/dsp-http-core/src/main/java/org/eclipse/edc/protocol/dsp/dispatcher/PostDspHttpRequestFactory.java @@ -23,6 +23,11 @@ import org.eclipse.edc.protocol.dsp.spi.serialization.JsonLdRemoteMessageSerializer; import org.eclipse.edc.spi.types.domain.message.RemoteMessage; +/** + * Creates a POST request through the Dataspace Protocol + * + * @param the message class. + */ public class PostDspHttpRequestFactory implements DspHttpRequestFactory { public static final String APPLICATION_JSON = "application/json";