From 6a7cb790992ffa62d03387dea9e7ef10f3fc18a1 Mon Sep 17 00:00:00 2001 From: efiege <105237007+efiege@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:22:36 +0200 Subject: [PATCH 1/2] chore: upgrade to core EDC version 0.2.0 (#465) Co-authored-by: Tim Dahlmanns --- CHANGELOG.md | 56 +- connector/.env | 23 +- connector/Dockerfile | 2 +- connector/build.gradle.kts | 4 +- docker-compose-dev.yaml | 18 +- docs/openapi.yaml | 2265 +++++++++-------- docs/postman_collection.json | 1391 ++++++---- e2e-test/build.gradle.kts | 34 + .../e2e/PostgresFlywayExtensionTest.java | 141 + .../extension/e2e/connector/Connector.java | 59 + .../e2e/connector/JsonLdConnectorUtil.java | 45 + .../e2e/connector/TestConnector.java | 364 +++ .../connector/config/DatasourceConfig.java | 38 + .../e2e/connector/config/EdcApiGroup.java | 31 + .../connector/config/EdcApiGroupConfig.java | 53 + .../e2e/connector/config/EdcConfig.java | 20 + .../e2e/connector/config/SimpleConfig.java | 24 + .../connector/factory/ConnectorFactory.java | 21 + .../factory/TestConnectorFactory.java | 101 + .../extension/e2e/db/DataSourceFactory.java | 54 + .../edc/extension/e2e/db/JdbcCredentials.java | 29 + .../edc/extension/e2e/db/TestDatabase.java | 40 + .../extension/e2e/db/TestDatabaseFactory.java | 37 + .../extension/e2e/db/TestDatabaseViaEnv.java | 62 + .../e2e/db/TestDatabaseViaTestcontainers.java | 70 + .../src/test/resources/logging.properties | 6 + extensions/edc-ui-config/build.gradle.kts | 3 + .../controller/EdcUiConfigAllSetTest.java | 9 + .../controller/EdcUiConfigNothingSetTest.java | 33 +- extensions/ids-broker-client/README.md | 87 - extensions/ids-broker-client/build.gradle.kts | 44 - .../docs/broker-extension.png | Bin 37693 -> 0 bytes .../docs/broker-extension.puml | 50 - .../extension/broker/BrokerExtension.java | 306 --- .../sender/QueryMessageRequestSender.java | 145 -- .../RegisterConnectorRequestSender.java | 106 - .../sender/RegisterResourceRequestSender.java | 239 -- .../UnregisterConnectorRequestSender.java | 66 - .../UnregisterResourceRequestSender.java | 69 - .../broker/sender/message/QueryMessage.java | 36 - .../message/RegisterConnectorMessage.java | 38 - .../message/RegisterResourceMessage.java | 39 - .../message/UnregisterConnectorMessage.java | 36 - .../message/UnregisterResourceMessage.java | 37 - .../ExtendedMessageProtocol.java | 25 - ...tipartExtendedRemoteMessageDispatcher.java | 29 - .../MultiContextJsonLdSerializer.java | 132 - .../broker/service/IdsBrokerService.java | 33 - .../broker/service/IdsBrokerServiceImpl.java | 369 --- ...rg.eclipse.edc.spi.system.ServiceExtension | 1 - extensions/ids-clearinghouse-client/README.md | 53 - .../ids-clearinghouse-client/build.gradle.kts | 46 - .../clearinghouse/ClearingHouseExtension.java | 190 -- .../sender/LogMessageSender.java | 100 - .../sender/message/LogMessage.java | 21 - .../ExtendedMessageProtocolClearing.java | 25 - ...tipartClearingRemoteMessageDispatcher.java | 29 - .../MultiContextJsonLdSerializer.java | 132 - .../service/IdsClearingHouseService.java | 28 - .../service/IdsClearingHouseServiceImpl.java | 120 - ...rg.eclipse.edc.spi.system.ServiceExtension | 1 - extensions/last-commit-info/build.gradle.kts | 12 +- .../controller/LastCommitInfoTest.java | 9 + .../policy-always-true/build.gradle.kts | 3 + .../policy/AlwaysTruePolicyExtensionTest.java | 19 +- extensions/postgres-flyway/build.gradle.kts | 5 + .../consumer/V1__m8-consumer-sample-data.sql | 97 + .../migration/default/V3__MS8-to-0.2.0.sql | 98 + .../provider/V1__m8-provider-sample-data.sql | 404 +++ .../src/main/resources/application.properties | 15 +- extensions/wrapper/client-ts/README.md | 2 +- extensions/wrapper/client/README.md | 2 +- extensions/wrapper/client/build.gradle.kts | 10 +- ...ntractAgreementTransferApiServiceTest.java | 46 +- ...GetTransferProcessAssetApiServiceTest.java | 8 +- .../TransferHistoryPageApiServiceTest.java | 5 + .../edc/client/TransferProcessTestUtils.java | 28 +- .../sovity/edc/client/UseCaseClientTest.java | 5 + .../wrapper-common-api/build.gradle.kts | 6 +- .../api/common/model/AtomicConstraintDto.java | 13 + .../api/common/model/CriterionDto.java | 31 + .../api/common/model/ExpressionDto.java | 16 +- .../wrapper/api/common/model/OperatorDto.java | 13 + .../api/common/model/PermissionDto.java | 13 + .../wrapper/wrapper-ee-api/build.gradle.kts | 6 +- .../api/ee/EnterpriseEditionResourceImpl.java | 13 + extensions/wrapper/wrapper/build.gradle.kts | 11 +- .../edc/ext/wrapper/WrapperExtension.java | 9 +- .../WrapperExtensionContextBuilder.java | 37 +- .../edc/ext/wrapper/api/ui/UiResource.java | 11 +- ...ontractAgreementTransferRequestParams.java | 4 +- .../ContractAgreementTransferApiService.java | 22 +- .../ContractAgreementDataFetcher.java | 25 +- .../ContractAgreementPageCardBuilder.java | 3 +- .../services/TransferProcessStateService.java | 2 +- .../services/TransferRequestBuilder.java | 50 +- .../utils/TransformerRegistryUtils.java | 34 - ...ransferHistoryPageAssetFetcherService.java | 13 + .../api/usecase/model/AssetEntryDto.java | 24 + .../model/ContractDefinitionRequestDto.java | 36 + .../api/usecase/model/CreateOfferingDto.java | 3 +- .../api/usecase/services/OfferingService.java | 62 +- .../edc/ext/wrapper/utils/MapUtils.java | 8 + .../api/ui/ContractAgreementPageTest.java | 62 +- .../TransferProcessStateServiceTest.java | 13 +- .../ext/wrapper/api/usecase/KpiApiTest.java | 6 + .../api/usecase/OfferingResourceTest.java | 5 + .../api/usecase/SupportedPolicyApiTest.java | 8 +- .../usecase/services/OfferingServiceTest.java | 135 +- .../usecase/contract-offer-valid.json | 27 +- gradle.properties | 5 +- settings.gradle.kts | 3 +- 112 files changed, 4575 insertions(+), 4587 deletions(-) create mode 100644 e2e-test/build.gradle.kts create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/PostgresFlywayExtensionTest.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/Connector.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/JsonLdConnectorUtil.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/TestConnector.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfig.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroup.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroupConfig.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcConfig.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/SimpleConfig.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/ConnectorFactory.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/TestConnectorFactory.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/DataSourceFactory.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabase.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnv.java create mode 100644 e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java create mode 100644 e2e-test/src/test/resources/logging.properties delete mode 100644 extensions/ids-broker-client/README.md delete mode 100644 extensions/ids-broker-client/build.gradle.kts delete mode 100644 extensions/ids-broker-client/docs/broker-extension.png delete mode 100644 extensions/ids-broker-client/docs/broker-extension.puml delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/BrokerExtension.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/QueryMessageRequestSender.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterConnectorRequestSender.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterResourceRequestSender.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterConnectorRequestSender.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterResourceRequestSender.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/QueryMessage.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterConnectorMessage.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterResourceMessage.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterConnectorMessage.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterResourceMessage.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/ExtendedMessageProtocol.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/IdsMultipartExtendedRemoteMessageDispatcher.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/serializer/MultiContextJsonLdSerializer.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerService.java delete mode 100644 extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerServiceImpl.java delete mode 100644 extensions/ids-broker-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension delete mode 100644 extensions/ids-clearinghouse-client/README.md delete mode 100644 extensions/ids-clearinghouse-client/build.gradle.kts delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/ClearingHouseExtension.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/LogMessageSender.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/LogMessage.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/ExtendedMessageProtocolClearing.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/IdsMultipartClearingRemoteMessageDispatcher.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/serializer/MultiContextJsonLdSerializer.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseService.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseServiceImpl.java delete mode 100644 extensions/ids-clearinghouse-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension create mode 100644 extensions/postgres-flyway/src/main/resources/migration/consumer/V1__m8-consumer-sample-data.sql create mode 100644 extensions/postgres-flyway/src/main/resources/migration/default/V3__MS8-to-0.2.0.sql create mode 100644 extensions/postgres-flyway/src/main/resources/migration/provider/V1__m8-provider-sample-data.sql create mode 100644 extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/CriterionDto.java delete mode 100644 extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/utils/TransformerRegistryUtils.java create mode 100644 extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/AssetEntryDto.java create mode 100644 extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/ContractDefinitionRequestDto.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 95373ee47..f9d43e8c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,28 +4,22 @@ All notable changes to this project will be documented in this file. ## [x.x.x] - UNRELEASED -### Overview - -### EDC UI - -### EDC-Extensions - -#### Major Changes - -#### Minor Changes - -#### Patch Changes - -### Deployment Migration Notes +### Major Changes -#### Compatible Versions +- Upgrade to core-EDC version `0.2.0` +- Now using the `Dataspace Protocol` +- Major changes to the management API + - Examples for the new requests are located in the postman collection in the `docs` folder + - The `OpenAPI` file has been updated to represent the EDC version `0.1.2` -- Connector Backend Docker Images: - - Dev EDC: `ghcr.io/sovity/edc-dev:{{ VERSION HERE }}` - - Sovity EDC CE: `ghcr.io/sovity/edc-ce:{{ VERSION HERE }}` - - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:{{ VERSION HERE }}` -- Connector UI Docker Image: `ghcr.io/sovity/edc-ui:0.0.1-milestone-8-sovity{{ VERSION HERE }}` +### Migration Notes +1. The `MY_EDC_IDS_BASE_URL` has been renamed to `MY_EDC_PROTOCOL_BASE_URL` +2. The default value of `WEB_HTTP_PROTOCOL_PATH` been changed from `${MY_EDC_BASE_PATH}/api/v1/ids` to `${MY_EDC_BASE_PATH}/api/v1/dsp` +3. New environment variable: `EDC_PARTICIPANT_ID`: `provider` +4. New environment variable: `EDC_JSONLD_HTTPS_ENABLED`: `true` +5. New environment variable: `EDC_DSP_CALLBACK_ADDRESS`: `http://edc:11003/api/v1/dsp` +6. `v1` Management API has been deprecated in favor of the `JSON-LD` `v2` Management API. All endpoints have a `v2` prefix now (example: `http://localhost:11002/api/v1/management/assets/request` is now available at `http://localhost:11002/api/management/v2/assets/request`) ## [4.1.0] - 2023-07-24 @@ -48,13 +42,18 @@ Security improvements of container image and enhancements for the `ReferringConn - Run java process with a non-root user ### Deployment Migration Notes +- `default` datasource has to be added + - `EDC_DATASOURCE_DEFAULT_NAME`=default + - `EDC_DATASOURCE_DEFAULT_URL`=jdbc:postgresql://connector:5432/edc + - `EDC_DATASOURCE_DEFAULT_USER`=user + - `EDC_DATASOURCE_DEFAULT_PASSWORD`=password #### Compatible Versions - Connector Backend Docker Images: - - Dev EDC: `ghcr.io/sovity/edc-dev:4.1.0` - - Sovity EDC CE: `ghcr.io/sovity/edc-ce:4.1.0` - - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:4.1.0` + - Dev EDC: `ghcr.io/sovity/edc-dev:4.1.0` + - Sovity EDC CE: `ghcr.io/sovity/edc-ce:4.1.0` + - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:4.1.0` - Connector UI Docker Image: `ghcr.io/sovity/edc-ui:0.0.1-milestone-8-sovity12` ## [4.0.1] - 2023-07-07 @@ -80,9 +79,9 @@ No changes besides docker image versions. #### Compatible Versions - Connector Backend Docker Images: - - Dev EDC: `ghcr.io/sovity/edc-dev:4.0.1` - - Sovity EDC CE: `ghcr.io/sovity/edc-ce:4.0.1` - - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:4.0.1` + - Dev EDC: `ghcr.io/sovity/edc-dev:4.0.1` + - Sovity EDC CE: `ghcr.io/sovity/edc-ce:4.0.1` + - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:4.0.1` - Connector UI Docker Image: `ghcr.io/sovity/edc-ui:0.0.1-milestone-8-sovity11` ## [4.0.0] - 2023-07-05 @@ -116,9 +115,9 @@ No changes besides docker image versions. #### Compatible Versions - Connector Backend Docker Images: - - Dev EDC: `ghcr.io/sovity/edc-dev:4.0.0` - - Sovity EDC CE: `ghcr.io/sovity/edc-ce:4.0.0` - - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:4.0.0` + - Dev EDC: `ghcr.io/sovity/edc-dev:4.0.0` + - Sovity EDC CE: `ghcr.io/sovity/edc-ce:4.0.0` + - MDS EDC CE: `ghcr.io/sovity/edc-ce-mds:4.0.0` - Connector UI Docker Image: `ghcr.io/sovity/edc-ui:0.0.1-milestone-8-sovity9` ## [3.3.0] - 2023-06-06 @@ -133,6 +132,7 @@ No changes besides docker image versions. - Minor EE API adjustments. + ## [3.2.0] - 2023-05-17 ### Minor Changes diff --git a/connector/.env b/connector/.env index 77545aa7b..a79c499da 100644 --- a/connector/.env +++ b/connector/.env @@ -11,23 +11,10 @@ MY_EDC_PROTOCOL=https:// # MY_EDC_NAME_KEBAB_CASE EDC_CONNECTOR_NAME=$MY_EDC_NAME_KEBAB_CASE -EDC_IDS_ID=urn:connector:$MY_EDC_NAME_KEBAB_CASE - -# MY_EDC_TITLE -EDC_IDS_TITLE=$MY_EDC_TITLE - -# MY_EDC_DESCRIPTION -EDC_IDS_DESCRIPTION=$MY_EDC_DESCRIPTION - -# MY_EDC_CURATOR_URL -EDC_IDS_CURATOR=$MY_EDC_CURATOR_URL # MY_EDC_CURATOR_NAME EDC_UI_CURATOR_ORGANIZATION_NAME=$MY_EDC_CURATOR_NAME -# MY_EDC_MAINTAINER_URL -EDC_IDS_MAINTAINER=$MY_EDC_MAINTAINER_URL - # MY_EDC_MAINTAINER_NAME EDC_UI_MAINTAINER_ORGANIZATION_NAME=$MY_EDC_MAINTAINER_NAME @@ -37,17 +24,17 @@ WEB_HTTP_MANAGEMENT_PORT=11002 WEB_HTTP_PROTOCOL_PORT=11003 WEB_HTTP_CONTROL_PORT=11004 WEB_HTTP_PATH=${MY_EDC_BASE_PATH}/api -WEB_HTTP_MANAGEMENT_PATH=${MY_EDC_BASE_PATH}/api/v1/management -WEB_HTTP_PROTOCOL_PATH=${MY_EDC_BASE_PATH}/api/v1/ids +WEB_HTTP_MANAGEMENT_PATH=${MY_EDC_BASE_PATH}/api/management +WEB_HTTP_PROTOCOL_PATH=${MY_EDC_BASE_PATH}/api/v1/dsp WEB_HTTP_CONTROL_PATH=${MY_EDC_BASE_PATH}/api/v1/control +EDC_PARTICIPANT_ID=${MY_EDC_NAME_KEBAB_CASE} +EDC_JSONLD_HTTPS_ENABLED=true EDC_HOSTNAME=${MY_EDC_FQDN} EDC_UI_CONNECTOR_ID=${MY_EDC_PROTOCOL}${MY_EDC_FQDN} -MY_EDC_IDS_BASE_URL=${MY_EDC_PROTOCOL}${MY_EDC_FQDN} -IDS_WEBHOOK_ADDRESS=${MY_EDC_IDS_BASE_URL} -EDC_IDS_ENDPOINT=${MY_EDC_IDS_BASE_URL}${WEB_HTTP_PROTOCOL_PATH} +EDC_DSP_CALLBACK_ADDRESS=${MY_EDC_PROTOCOL}${MY_EDC_FQDN}${WEB_HTTP_PROTOCOL_PATH} # Flyway Extension: Required MY_EDC_JDBC_URL=jdbc:postgresql://missing-postgresql-url diff --git a/connector/Dockerfile b/connector/Dockerfile index ec48ac048..2f4b72ca5 100644 --- a/connector/Dockerfile +++ b/connector/Dockerfile @@ -33,7 +33,7 @@ COPY --from=build /home/gradle/project/connector/build/libs/app.jar /app COPY ./connector/src/main/resources/logging.properties /app # health status is determined by the availability of the /health endpoint -HEALTHCHECK --interval=5s --timeout=5s --retries=10 CMD curl -H "X-Api-Key: $EDC_API_AUTH_KEY" --fail http://localhost:11002/api/v1/management/check/health +HEALTHCHECK --interval=5s --timeout=5s --retries=10 CMD curl --fail http://localhost:11001/api/check/health # Use "exec" for graceful termination (SIGINT) to reach JVM. # ARG can not be used in ENTRYPOINT so storing values in ENV variables diff --git a/connector/build.gradle.kts b/connector/build.gradle.kts index 8465b7ca2..cb2e32a14 100644 --- a/connector/build.gradle.kts +++ b/connector/build.gradle.kts @@ -15,7 +15,9 @@ dependencies { implementation("${edcGroup}:configuration-filesystem:${edcVersion}") implementation("${edcGroup}:control-plane-aggregate-services:${edcVersion}") implementation("${edcGroup}:http:${edcVersion}") - implementation("${edcGroup}:ids:${edcVersion}") + implementation("${edcGroup}:dsp:${edcVersion}") + implementation("${edcGroup}:json-ld:${edcVersion}") + implementation("${edcGroup}:monitor-jdk-logger:${edcVersion}") // Control-plane to Data-plane implementation("${edcGroup}:transfer-data-plane:${edcVersion}") diff --git a/docker-compose-dev.yaml b/docker-compose-dev.yaml index 64f8a80dd..b49ab2616 100644 --- a/docker-compose-dev.yaml +++ b/docker-compose-dev.yaml @@ -7,15 +7,15 @@ services: environment: - EDC_UI_ACTIVE_PROFILE=${EDC_UI_ACTIVE_PROFILE} - EDC_UI_CONFIG_URL=edc-ui-config - - EDC_UI_DATA_MANAGEMENT_API_URL=http://localhost:11002/api/v1/management + - EDC_UI_DATA_MANAGEMENT_API_URL=http://localhost:11002/api/management/v2 - EDC_UI_DATA_MANAGEMENT_API_KEY=ApiKeyDefaultValue - - EDC_UI_CATALOG_URLS=http://edc2:11003/api/v1/ids/data + - EDC_UI_CATALOG_URLS=http://edc2:11003/api/v1/dsp edc: image: ${DEV_EDC_IMAGE} depends_on: - postgresql environment: - MY_EDC_NAME_KEBAB_CASE: "example-connector" + MY_EDC_NAME_KEBAB_CASE: "provider" MY_EDC_TITLE: "EDC Connector" MY_EDC_DESCRIPTION: "sovity Community Edition EDC Connector" MY_EDC_CURATOR_URL: "https://example.com" @@ -43,7 +43,6 @@ services: MY_EDC_PROTOCOL: "http://" MY_EDC_FQDN: "edc" - MY_EDC_IDS_BASE_URL: "http://edc:11003" MY_EDC_JDBC_URL: jdbc:postgresql://postgresql:5432/edc MY_EDC_JDBC_USER: edc @@ -51,6 +50,8 @@ services: EDC_WEB_REST_CORS_ENABLED: 'true' EDC_WEB_REST_CORS_HEADERS: 'origin,content-type,accept,authorization,x-api-key' EDC_WEB_REST_CORS_ORIGINS: '*' + + EDC_DSP_CALLBACK_ADDRESS: http://edc:11003/api/v1/dsp ports: - '11001:11001' - '11002:11002' @@ -78,15 +79,15 @@ services: environment: - EDC_UI_ACTIVE_PROFILE=${EDC_UI_ACTIVE_PROFILE} - EDC_UI_CONFIG_URL=edc-ui-config - - EDC_UI_DATA_MANAGEMENT_API_URL=http://localhost:22002/api/v1/management + - EDC_UI_DATA_MANAGEMENT_API_URL=http://localhost:22002/api/management/v2 - EDC_UI_DATA_MANAGEMENT_API_KEY=ApiKeyDefaultValue - - EDC_UI_CATALOG_URLS=http://edc:11003/api/v1/ids/data + - EDC_UI_CATALOG_URLS=http://edc:11003/api/v1/dsp edc2: image: ${DEV_EDC_IMAGE} depends_on: - postgresql2 environment: - MY_EDC_NAME_KEBAB_CASE: "example-connector" + MY_EDC_NAME_KEBAB_CASE: "consumer" MY_EDC_TITLE: "EDC Connector" MY_EDC_DESCRIPTION: "sovity Community Edition EDC Connector" MY_EDC_CURATOR_URL: "https://example.com" @@ -114,7 +115,6 @@ services: MY_EDC_PROTOCOL: "http://" MY_EDC_FQDN: "edc2" - MY_EDC_IDS_BASE_URL: "http://edc2:11003" MY_EDC_JDBC_URL: jdbc:postgresql://postgresql2:5432/edc MY_EDC_JDBC_USER: edc @@ -122,6 +122,8 @@ services: EDC_WEB_REST_CORS_ENABLED: 'true' EDC_WEB_REST_CORS_HEADERS: 'origin,content-type,accept,authorization,x-api-key' EDC_WEB_REST_CORS_ORIGINS: '*' + + EDC_DSP_CALLBACK_ADDRESS: http://edc2:11003/api/v1/dsp ports: - '22001:11001' - '22002:11002' diff --git a/docs/openapi.yaml b/docs/openapi.yaml index fda222531..92b4b02b4 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -2,16 +2,16 @@ openapi: 3.0.1 info: title: EDC REST API description: EDC REST APIs - merged by OpenApiMerger - version: 0.0.1-SNAPSHOT + version: 0.1.2-SNAPSHOT servers: -- url: / + - url: / tags: -- name: Data Plane control API - description: 'Api targeted by the Control Plane to delegate a data transfer (Provider + - name: Data Plane control API + description: 'Api targeted by the Control Plane to delegate a data transfer (Provider Push or Streaming) to the Data Plane after the contract has been successfully negotiated and agreed between the two participants. ' -- name: Data Plane public API - description: "The public API of the Data Plane is a data proxy enabling a data consumer\ + - name: Data Plane public API + description: "The public API of the Data Plane is a data proxy enabling a data consumer\ \ to actively querydata from the provider data source (e.g. backend Rest API,\ \ internal database...) through its Data Planeinstance. Thus the Data Plane is\ \ the only entry/output door for the data, which avoids the provider to exposedirectly\ @@ -22,80 +22,325 @@ tags: \ path parameters and request body are supported (in the limits fixed by the HTTP\ \ server) and can also conveyed to the actual data source." paths: - /assets: + /callback/{processId}/deprovision: + post: + tags: + - HTTP Provisioner Webhook + operationId: callDeprovisionWebhook + parameters: + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DeprovisionedResource' + responses: + default: + description: default response + content: + application/json: {} + /callback/{processId}/provision: + post: + tags: + - HTTP Provisioner Webhook + operationId: callProvisionWebhook + parameters: + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ProvisionerWebhookRequest' + responses: + default: + description: default response + content: + application/json: {} + /check/health: + get: + tags: + - Application Observability + description: Performs a liveness probe to determine whether the runtime is working + properly. + operationId: checkHealth + responses: + "200": + description: The runtime is working properly. + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/HealthStatus' + /check/liveness: + get: + tags: + - Application Observability + description: Performs a liveness probe to determine whether the runtime is working + properly. + operationId: getLiveness + responses: + "200": + description: The runtime is working properly. + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/HealthStatus' + /check/readiness: get: tags: - - Asset - description: Gets all assets according to a particular query - operationId: getAllAssets + - Application Observability + description: Performs a readiness probe to determine whether the runtime is + able to accept requests. + operationId: getReadiness + responses: + "200": + description: The runtime is able to accept requests. + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/HealthStatus' + /check/startup: + get: + tags: + - Application Observability + description: Performs a startup probe to determine whether the runtime has completed + startup. + operationId: getStartup + responses: + "200": + description: The runtime has completed startup. + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/HealthStatus' + /instances: + get: + tags: + - Dataplane Selector + operationId: getAll + responses: + default: + description: default response + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/DataPlaneInstance' + post: + tags: + - Dataplane Selector + operationId: addEntry + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DataPlaneInstance' + responses: + default: + description: default response + content: + application/json: {} + /instances/select: + post: + tags: + - Dataplane Selector + operationId: find + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SelectionRequest' + responses: + default: + description: default response + content: + application/json: + schema: + $ref: '#/components/schemas/DataPlaneInstance' + /token: + get: + tags: + - Consumer Pull Token Validation + description: "Checks that the provided token has been signed by the present\ + \ entity and asserts its validity. If token is valid, then the data address\ + \ contained in its claims is decrypted and returned back to the caller." + operationId: validate parameters: - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string + - name: Authorization + in: header + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": + description: Token is valid + "400": + description: Request was malformed + "403": + description: Token is invalid + /transfer: + post: + tags: + - Data Plane control API + description: Initiates a data transfer for the given request. The transfer will + be performed asynchronously. + operationId: initiateTransfer + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DataFlowRequest' + responses: + "200": + description: Data transfer initiated + "400": + description: Failed to validate request + /transfer/{processId}: + get: + tags: + - Data Plane control API + description: Get the current state of a data transfer. + operationId: getTransferState + parameters: + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + responses: + "200": + description: Missing access token + /transferprocess/{processId}/complete: + post: + tags: + - Transfer Process Control Api + description: "Requests completion of the transfer process. Due to the asynchronous\ + \ nature of transfers, a successful response only indicates that the request\ + \ was successfully received" + operationId: complete + parameters: + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + responses: + "400": + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array + example: null items: - $ref: '#/components/schemas/AssetResponseDto' + $ref: '#/components/schemas/ApiErrorDetail' + /transferprocess/{processId}/fail: + post: + tags: + - Transfer Process Control Api + description: "Requests completion of the transfer process. Due to the asynchronous\ + \ nature of transfers, a successful response only indicates that the request\ + \ was successfully received" + operationId: fail + parameters: + - name: processId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TransferProcessFailStateDto' + required: true + responses: "400": - description: Request body was malformed + description: "Request was malformed, e.g. id was null" + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/ApiErrorDetail' + /v2/assets: + put: + tags: + - Asset + description: "Updates an asset with the given ID if it exists. If the asset\ + \ is not found, no further action is taken. DANGER ZONE: Note that updating\ + \ assets can have unexpected results, especially for contract offers that\ + \ have been sent out or are ongoing in contract negotiations." + operationId: updateAsset + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AssetUpdateRequestDto' + responses: + "200": + description: Asset was updated successfully + "400": + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true + "404": + description: "Asset could not be updated, because it does not exist." post: tags: - - Asset + - Asset description: Creates a new asset together with a data address operationId: createAsset requestBody: content: application/json: schema: - $ref: '#/components/schemas/AssetEntryDto' + $ref: '#/components/schemas/AssetEntryNewDto' responses: "200": description: Asset was created successfully. Returns the asset Id and created @@ -110,6 +355,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "409": @@ -119,12 +365,13 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /assets/request: + /v2/assets/request: post: tags: - - Asset + - Asset description: ' all assets according to a particular query' operationId: requestAssets requestBody: @@ -134,10 +381,12 @@ paths: $ref: '#/components/schemas/QuerySpecDto' responses: "200": + description: The assets matching the query content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/AssetResponseDto' "400": @@ -146,22 +395,65 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /assets/{id}: + /v2/assets/{assetId}/dataaddress: + put: + tags: + - Asset + description: Updates a DataAddress for an asset with the given ID. + operationId: updateDataAddress + parameters: + - name: assetId + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AssetUpdateRequestDto' + responses: + "200": + description: Asset was updated successfully + "400": + description: "Request was malformed, e.g. id was null" + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/ApiErrorDetail' + "404": + description: An asset with the given ID does not exist + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/ApiErrorDetail' + /v2/assets/{id}: get: tags: - - Asset + - Asset description: Gets an asset with the given ID operationId: getAsset parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The asset @@ -175,6 +467,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -183,11 +476,12 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' delete: tags: - - Asset + - Asset description: "Removes an asset with the given ID if possible. Deleting an asset\ \ is only possible if that asset is not yet referenced by a contract agreement,\ \ in which case an error is returned. DANGER ZONE: Note that deleting assets\ @@ -195,13 +489,14 @@ paths: \ sent out or ongoing or contract negotiations." operationId: removeAsset parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: Asset was deleted successfully @@ -211,6 +506,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -219,6 +515,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "409": @@ -228,22 +525,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /assets/{id}/address: + /v2/assets/{id}/dataaddress: get: tags: - - Asset + - Asset description: Gets a data address of an asset with the given ID operationId: getAssetDataAddress parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The data address @@ -257,6 +556,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -265,126 +565,19 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /callback/{processId}/deprovision: - post: - tags: - - HTTP Provisioner Webhook - operationId: callDeprovisionWebhook - parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/DeprovisionedResource' - responses: - default: - description: default response - content: - application/json: {} - /callback/{processId}/provision: + /v2/catalog/request: post: tags: - - HTTP Provisioner Webhook - operationId: callProvisionWebhook - parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ProvisionerWebhookRequest' - responses: - default: - description: default response - content: - application/json: {} - /catalog: - get: - tags: - - Catalog - operationId: getCatalog - parameters: - - name: providerUrl - in: query - required: true - style: form - explode: true - schema: - type: string - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string - responses: - default: - description: Gets contract offers (=catalog) of a single connector - content: - application/json: - schema: - $ref: '#/components/schemas/Catalog' - deprecated: true - /catalog/request: - post: - tags: - - Catalog + - Catalog operationId: requestCatalog requestBody: content: - '*/*': + application/json: schema: $ref: '#/components/schemas/CatalogRequestDto' - required: true responses: default: description: Gets contract offers (=catalog) of a single connector @@ -392,134 +585,10 @@ paths: application/json: schema: $ref: '#/components/schemas/Catalog' - /check/health: - get: - tags: - - Application Observability - description: Performs a liveness probe to determine whether the runtime is working - properly. - operationId: checkHealth - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/HealthStatus' - /check/liveness: - get: - tags: - - Application Observability - description: Performs a liveness probe to determine whether the runtime is working - properly. - operationId: getLiveness - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/HealthStatus' - /check/readiness: - get: - tags: - - Application Observability - description: Performs a readiness probe to determine whether the runtime is - able to accept requests. - operationId: getReadiness - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/HealthStatus' - /check/startup: - get: - tags: - - Application Observability - description: Performs a startup probe to determine whether the runtime has completed - startup. - operationId: getStartup - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/HealthStatus' - /contractagreements: - get: - tags: - - Contract Agreement - description: Gets all contract agreements according to a particular query - operationId: getAllAgreements - parameters: - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ContractAgreementDto' - "400": - description: Request body was malformed - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true - /contractagreements/request: + /v2/contractagreements/request: post: tags: - - Contract Agreement + - Contract Agreement description: Gets all contract agreements according to a particular query operationId: queryAllAgreements requestBody: @@ -529,10 +598,12 @@ paths: $ref: '#/components/schemas/QuerySpecDto' responses: "200": + description: The contract agreements matching the query content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ContractAgreementDto' "400": @@ -541,22 +612,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractagreements/{id}: + /v2/contractagreements/{id}: get: tags: - - Contract Agreement + - Contract Agreement description: Gets an contract agreement with the given ID - operationId: getContractAgreement + operationId: getAgreementById parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract agreement @@ -570,6 +643,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -578,75 +652,45 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractdefinitions: - get: + /v2/contractdefinitions: + put: tags: - - Contract Definition - description: Returns all contract definitions according to a query - operationId: getAllContractDefinitions - parameters: - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string + - Contract Definition + description: Updated a contract definition with the given ID. The supplied JSON + structure must be a valid JSON-LD object + operationId: updateContractDefinition + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/ContractDefinitionRequestDto' responses: - "200": + "204": + description: Contract definition was updated successfully + "400": + description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array + example: null items: - $ref: '#/components/schemas/ContractDefinitionResponseDto' - "400": - description: Request was malformed + $ref: '#/components/schemas/ApiErrorDetail' + "404": + description: A contract definition with the given ID does not exist content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true post: tags: - - Contract Definition + - Contract Definition description: Creates a new contract definition operationId: createContractDefinition requestBody: @@ -668,6 +712,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "409": @@ -677,12 +722,13 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractdefinitions/request: + /v2/contractdefinitions/request: post: tags: - - Contract Definition + - Contract Definition description: Returns all contract definitions according to a query operationId: queryAllContractDefinitions requestBody: @@ -692,10 +738,12 @@ paths: $ref: '#/components/schemas/QuerySpecDto' responses: "200": + description: The contract definitions matching the query content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ContractDefinitionResponseDto' "400": @@ -704,22 +752,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractdefinitions/{id}: + /v2/contractdefinitions/{id}: get: tags: - - Contract Definition + - Contract Definition description: Gets an contract definition with the given ID operationId: getContractDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract definition @@ -733,6 +783,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -741,24 +792,26 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' delete: tags: - - Contract Definition + - Contract Definition description: "Removes a contract definition with the given ID if possible. DANGER\ \ ZONE: Note that deleting contract definitions can have unexpected results,\ \ especially for contract offers that have been sent out or ongoing or contract\ \ negotiations." operationId: deleteContractDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: Contract definition was deleted successfully @@ -768,6 +821,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -776,75 +830,13 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations: - get: - tags: - - Contract Negotiation - description: Returns all contract negotiations according to a query - operationId: getNegotiations - parameters: - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ContractNegotiationDto' - "400": - description: Request was malformed - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true + /v2/contractnegotiations: post: tags: - - Contract Negotiation + - Contract Negotiation description: "Initiates a contract negotiation for a given offer and with the\ \ given counter part. Please note that successfully invoking this endpoint\ \ only means that the negotiation was initiated. Clients must poll the /{id}/state\ @@ -874,12 +866,13 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations/request: + /v2/contractnegotiations/request: post: tags: - - Contract Negotiation + - Contract Negotiation description: Returns all contract negotiations according to a query operationId: queryNegotiations requestBody: @@ -889,10 +882,12 @@ paths: $ref: '#/components/schemas/QuerySpecDto' responses: "200": + description: The contract negotiations that match the query content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ContractNegotiationDto' "400": @@ -901,22 +896,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations/{id}: + /v2/contractnegotiations/{id}: get: tags: - - Contract Negotiation - description: Gets an contract negotiation with the given ID + - Contract Negotiation + description: Gets a contract negotiation with the given ID operationId: getNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract negotiation @@ -930,6 +927,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -938,23 +936,25 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations/{id}/agreement: + /v2/contractnegotiations/{id}/agreement: get: tags: - - Contract Negotiation + - Contract Negotiation description: Gets a contract agreement for a contract negotiation with the given ID operationId: getAgreementForNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: "The contract agreement that is attached to the negotiation,\ @@ -969,6 +969,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -977,25 +978,27 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations/{id}/cancel: + /v2/contractnegotiations/{id}/cancel: post: tags: - - Contract Negotiation + - Contract Negotiation description: "Requests aborting the contract negotiation. Due to the asynchronous\ \ nature of contract negotiations, a successful response only indicates that\ \ the request was successfully received. Clients must poll the /{id}/state\ \ endpoint to track the state." operationId: cancelNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: Request to cancel the Contract negotiation was successfully @@ -1009,6 +1012,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1017,25 +1021,27 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations/{id}/decline: + /v2/contractnegotiations/{id}/decline: post: tags: - - Contract Negotiation + - Contract Negotiation description: "Requests cancelling the contract negotiation. Due to the asynchronous\ \ nature of contract negotiations, a successful response only indicates that\ \ the request was successfully received. Clients must poll the /{id}/state\ \ endpoint to track the state." operationId: declineNegotiation parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: Request to decline the Contract negotiation was successfully @@ -1049,6 +1055,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1057,22 +1064,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /contractnegotiations/{id}/state: + /v2/contractnegotiations/{id}/state: get: tags: - - Contract Negotiation + - Contract Negotiation description: Gets the state of a contract negotiation with the given ID operationId: getNegotiationState parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The contract negotiation's state @@ -1086,6 +1095,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1094,122 +1104,15 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /instances: - get: - tags: - - Dataplane Selector - operationId: getAll - responses: - default: - description: default response - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/DataPlaneInstance' - post: - tags: - - Dataplane Selector - operationId: addEntry - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/DataPlaneInstance' - responses: - default: - description: default response - content: - application/json: {} - /instances/select: - post: - tags: - - Dataplane Selector - operationId: find - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SelectionRequest' - responses: - default: - description: default response - content: - application/json: - schema: - $ref: '#/components/schemas/DataPlaneInstance' - /policydefinitions: - get: - tags: - - Policy - description: Returns all policy definitions according to a query - operationId: getAllPolicies - parameters: - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/PolicyDefinitionResponseDto' - "400": - description: Request was malformed - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true + /v2/policydefinitions: post: tags: - - Policy + - Policy Definition description: Creates a new policy definition - operationId: createPolicy + operationId: createPolicyDefinition requestBody: content: application/json: @@ -1229,6 +1132,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "409": @@ -1238,14 +1142,15 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /policydefinitions/request: + /v2/policydefinitions/request: post: tags: - - Policy + - Policy Definition description: Returns all policy definitions according to a query - operationId: queryAllPolicies + operationId: queryPolicyDefinitions requestBody: content: application/json: @@ -1253,10 +1158,12 @@ paths: $ref: '#/components/schemas/QuerySpecDto' responses: "200": + description: The policy definitions matching the query content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/PolicyDefinitionResponseDto' "400": @@ -1265,22 +1172,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /policydefinitions/{id}: + /v2/policydefinitions/{id}: get: tags: - - Policy + - Policy Definition description: Gets a policy definition with the given ID - operationId: getPolicy + operationId: getPolicyDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The policy definition @@ -1294,6 +1203,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1302,25 +1212,67 @@ paths: application/json: schema: type: array + example: null + items: + $ref: '#/components/schemas/ApiErrorDetail' + put: + tags: + - Policy Definition + description: "Updates an existing Policy, If the Policy is not found, an error\ + \ is reported" + operationId: updatePolicyDefinition + parameters: + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyDefinitionUpdateDto' + responses: + "200": + description: policy definition was updated successfully. Returns the Policy + Definition Id and updated timestamp + "400": + description: Request body was malformed + content: + application/json: + schema: + type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' + "404": + description: "policy definition could not be updated, because it does not\ + \ exists" + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDetail' delete: tags: - - Policy + - Policy Definition description: "Removes a policy definition with the given ID if possible. Deleting\ \ a policy definition is only possible if that policy definition is not yet\ \ referenced by a contract definition, in which case an error is returned.\ \ DANGER ZONE: Note that deleting policy definitions can have unexpected results,\ \ do this at your own risk!" - operationId: deletePolicy + operationId: deletePolicyDefinition parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: Policy definition was deleted successfully @@ -1330,6 +1282,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1338,6 +1291,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "409": @@ -1347,136 +1301,17 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /token: - get: - tags: - - Consumer Pull Token Validation - description: "Checks that the provided token has been signed by the present\ - \ entity and asserts its validity. If token is valid, then the data address\ - \ contained in its claims is decrypted and returned back to the caller." - operationId: validate - parameters: - - name: Authorization - in: header - required: true - style: simple - explode: false - schema: - type: string - responses: - "200": - description: Token is valid - "400": - description: Request was malformed - "403": - description: Token is invalid - /transfer: - post: - tags: - - Data Plane control API - description: Initiates a data transfer for the given request. The transfer will - be performed asynchronously. - operationId: initiateTransfer - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/DataFlowRequest' - responses: - "200": - description: Data transfer initiated - "400": - description: Failed to validate request - /transfer/{processId}: - get: - tags: - - Data Plane control API - description: Get the current state of a data transfer. - operationId: getTransferState - parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string - responses: - "200": - description: Missing access token - /transferprocess: - get: - tags: - - Transfer Process - description: Returns all transfer process according to a query - operationId: getAllTransferProcesses - parameters: - - name: offset - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: limit - in: query - required: false - style: form - explode: true - schema: - type: integer - format: int32 - - name: filter - in: query - required: false - style: form - explode: true - schema: - type: string - - name: sort - in: query - required: false - style: form - explode: true - schema: - type: string - enum: - - ASC - - DESC - - name: sortField - in: query - required: false - style: form - explode: true - schema: - type: string - responses: - "200": - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/TransferProcessDto' - "400": - description: Request was malformed - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApiErrorDetail' - deprecated: true + /v2/transferprocesses: post: tags: - - Transfer Process + - Transfer Process description: "Initiates a data transfer with the given parameters. Please note\ \ that successfully invoking this endpoint only means that the transfer was\ \ initiated. Clients must poll the /{id}/state endpoint to track the state" - operationId: initiateTransfer + operationId: initiateTransferProcess requestBody: content: application/json: @@ -1501,14 +1336,15 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/request: + /v2/transferprocesses/request: post: tags: - - Transfer Process + - Transfer Process description: Returns all transfer process according to a query - operationId: queryAllTransferProcesses + operationId: queryTransferProcesses requestBody: content: application/json: @@ -1516,10 +1352,12 @@ paths: $ref: '#/components/schemas/QuerySpecDto' responses: "200": + description: The transfer processes matching the query content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/TransferProcessDto' "400": @@ -1528,22 +1366,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/{id}: + /v2/transferprocesses/{id}: get: tags: - - Transfer Process + - Transfer Process description: Gets an transfer process with the given ID operationId: getTransferProcess parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The transfer process @@ -1557,6 +1397,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1565,51 +1406,13 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/{id}/cancel: - post: - tags: - - Transfer Process - description: "Requests aborting the transfer process. Due to the asynchronous\ - \ nature of transfers, a successful response only indicates that the request\ - \ was successfully received. Clients must poll the /{id}/state endpoint to\ - \ track the state." - operationId: cancelTransferProcess - parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string - responses: - "200": - description: Request to cancel the transfer process was successfully received - links: - poll-state: - operationId: getTransferProcessState - "400": - description: "Request was malformed, e.g. id was null" - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApiErrorDetail' - "404": - description: A contract negotiation with the given ID does not exist - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/{id}/deprovision: + /v2/transferprocesses/{id}/deprovision: post: tags: - - Transfer Process + - Transfer Process description: "Requests the deprovisioning of resources associated with a transfer\ \ process. Due to the asynchronous nature of transfers, a successful response\ \ only indicates that the request was successfully received. This may take\ @@ -1617,13 +1420,14 @@ paths: \ state." operationId: deprovisionTransferProcess parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: Request to deprovision the transfer process was successfully @@ -1637,6 +1441,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1645,22 +1450,24 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/{id}/state: + /v2/transferprocesses/{id}/state: get: tags: - - Transfer Process + - Transfer Process description: Gets the state of a transfer process with the given ID operationId: getTransferProcessState parameters: - - name: id - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null responses: "200": description: The transfer process's state @@ -1674,6 +1481,7 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' "404": @@ -1682,68 +1490,70 @@ paths: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/{processId}/complete: + /v2/transferprocesses/{id}/terminate: post: tags: - - Transfer Process Control Api - description: "Requests completion of the transfer process. Due to the asynchronous\ + - Transfer Process + description: "Requests the termination of a transfer process. Due to the asynchronous\ \ nature of transfers, a successful response only indicates that the request\ - \ was successfully received" - operationId: complete + \ was successfully received. Clients must poll the /{id}/state endpoint to\ + \ track the state." + operationId: terminateTransferProcess parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string + - name: id + in: path + required: true + style: simple + explode: false + schema: + type: string + example: null + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TerminateTransferDto' responses: + "200": + description: Request to cancel the transfer process was successfully received + links: + poll-state: + operationId: getTransferProcessState "400": description: "Request was malformed, e.g. id was null" content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' - /transferprocess/{processId}/fail: - post: - tags: - - Transfer Process Control Api - description: "Requests completion of the transfer process. Due to the asynchronous\ - \ nature of transfers, a successful response only indicates that the request\ - \ was successfully received" - operationId: fail - parameters: - - name: processId - in: path - required: true - style: simple - explode: false - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/TransferProcessFailStateDto' - required: true - responses: - "400": - description: "Request was malformed, e.g. id was null" + "404": + description: A contract negotiation with the given ID does not exist + content: + application/json: + schema: + type: array + example: null + items: + $ref: '#/components/schemas/ApiErrorDetail' + "409": + description: "Could not terminate transfer process, because it is already\ + \ completed or terminated." content: application/json: schema: type: array + example: null items: $ref: '#/components/schemas/ApiErrorDetail' /{any}: get: tags: - - Data Plane public API + - Data Plane public API description: Send `GET` data query to the Data Plane. operationId: get responses: @@ -1755,7 +1565,7 @@ paths: description: Failed to transfer data put: tags: - - Data Plane public API + - Data Plane public API description: Send `PUT` data query to the Data Plane. operationId: put responses: @@ -1767,7 +1577,7 @@ paths: description: Failed to transfer data post: tags: - - Data Plane public API + - Data Plane public API description: Send `POST` data query to the Data Plane. operationId: post responses: @@ -1779,7 +1589,7 @@ paths: description: Failed to transfer data delete: tags: - - Data Plane public API + - Data Plane public API description: Send `DELETE` data query to the Data Plane. operationId: delete responses: @@ -1791,7 +1601,7 @@ paths: description: Failed to transfer data patch: tags: - - Data Plane public API + - Data Plane public API description: Send `PATCH` data query to the Data Plane. operationId: patch responses: @@ -1810,239 +1620,375 @@ components: $ref: '#/components/schemas/Constraint' includedIn: type: string + example: null type: type: string + example: null + example: null ApiErrorDetail: type: object properties: invalidValue: type: string + example: null message: type: string + example: null path: type: string + example: null type: type: string + example: null + example: null Asset: type: object properties: createdAt: type: integer format: int64 + example: null id: type: string + example: null + privateProperties: + type: object + additionalProperties: + type: object + example: null + example: null properties: type: object additionalProperties: type: object - AssetEntryDto: - required: - - asset - - dataAddress + example: null + example: null + example: null + AssetEntryNewDto: type: object properties: asset: - $ref: '#/components/schemas/AssetRequestDto' + $ref: '#/components/schemas/Asset' dataAddress: - $ref: '#/components/schemas/DataAddressDto' - AssetRequestDto: - required: - - properties + $ref: '#/components/schemas/DataAddress' + example: null + AssetResponseDto: type: object properties: - id: + '@context': + type: object + example: null + '@id': type: string + example: null + '@type': + type: string + example: null + createdAt: + type: integer + format: int64 + example: null + privateProperties: + type: object + additionalProperties: + type: object + example: null + example: null properties: type: object additionalProperties: type: object - AssetResponseDto: + example: null + example: null + example: null + AssetUpdateRequestDto: + required: + - properties type: object properties: - createdAt: - type: integer - format: int64 - id: + '@context': + type: object + example: null + '@type': type: string + example: null + privateProperties: + type: object + additionalProperties: + type: object + example: null + example: null properties: type: object additionalProperties: type: object + example: null + example: null + example: null + CallbackAddress: + type: object + properties: + authCodeId: + type: string + example: null + authKey: + type: string + example: null + events: + uniqueItems: true + type: array + example: null + items: + type: string + example: null + transactional: + type: boolean + example: null + uri: + type: string + example: null + example: null Catalog: type: object properties: contractOffers: type: array + example: null items: $ref: '#/components/schemas/ContractOffer' + dataServices: + type: array + example: null + items: + $ref: '#/components/schemas/DataService' + datasets: + type: array + example: null + items: + $ref: '#/components/schemas/Dataset' id: type: string + example: null + properties: + type: object + additionalProperties: + type: object + example: null + example: null + example: null CatalogRequestDto: required: - - providerUrl + - providerUrl type: object properties: + '@context': + type: object + example: null + '@type': + type: string + example: null + protocol: + type: string + example: null providerUrl: type: string + example: null querySpec: $ref: '#/components/schemas/QuerySpecDto' + example: null Constraint: required: - - edctype + - edctype type: object properties: edctype: type: string + example: null + example: null discriminator: propertyName: edctype ContractAgreementDto: required: - - assetId - - consumerAgentId - - id - - policy - - providerAgentId + - '@id' + - assetId + - consumerId + - policy + - providerId type: object properties: + '@context': + type: object + example: null + '@id': + type: string + example: null + '@type': + type: string + example: null assetId: type: string - consumerAgentId: + example: null + consumerId: type: string - contractEndDate: - type: integer - format: int64 + example: null contractSigningDate: type: integer format: int64 - contractStartDate: - type: integer - format: int64 - id: - type: string + example: null policy: $ref: '#/components/schemas/Policy' - providerAgentId: + providerId: type: string + example: null + example: null ContractDefinitionRequestDto: - required: - - accessPolicyId - - contractPolicyId - - criteria type: object properties: - accessPolicyId: + '@context': + type: object + example: null + '@id': type: string - contractPolicyId: + example: null + '@type': + type: string + example: null + accessPolicyId: type: string - criteria: + example: null + assetsSelector: type: array + example: null items: $ref: '#/components/schemas/CriterionDto' - id: + contractPolicyId: type: string - validity: - type: integer - format: int64 + example: null + example: null ContractDefinitionResponseDto: type: object properties: - accessPolicyId: + '@context': + type: object + example: null + '@id': type: string - contractPolicyId: + example: null + '@type': type: string - createdAt: - type: integer - format: int64 - criteria: + example: null + accessPolicyId: + type: string + example: null + assetsSelector: type: array + example: null items: $ref: '#/components/schemas/CriterionDto' - id: + contractPolicyId: type: string - validity: + example: null + createdAt: type: integer format: int64 + example: null + example: null ContractNegotiationDto: type: object properties: + '@context': + type: object + example: null + '@id': + type: string + example: null + '@type': + type: string + example: null + callbackAddresses: + type: array + example: null + items: + $ref: '#/components/schemas/CallbackAddress' contractAgreementId: type: string + example: null counterPartyAddress: type: string + example: null createdAt: type: integer format: int64 + example: null errorDetail: type: string - id: - type: string + example: null protocol: type: string + example: null state: type: string + example: null type: type: string + example: null enum: - - CONSUMER - - PROVIDER + - CONSUMER + - PROVIDER updatedAt: type: integer format: int64 + example: null + example: null ContractOffer: type: object properties: - asset: - $ref: '#/components/schemas/Asset' - consumer: - type: string - format: uri - contractEnd: - type: string - format: date-time - contractStart: + assetId: type: string - format: date-time + example: null id: type: string - offerEnd: - type: string - format: date-time - offerStart: - type: string - format: date-time + example: null policy: $ref: '#/components/schemas/Policy' - provider: + providerId: type: string - format: uri + example: null + example: null ContractOfferDescription: - required: - - assetId - - offerId - - policy type: object properties: assetId: type: string + example: null offerId: type: string + example: null policy: $ref: '#/components/schemas/Policy' - validity: - type: integer - format: int64 + example: null CriterionDto: required: - - operandLeft - - operator + - operandLeft + - operator type: object properties: + '@context': + type: object + example: null + '@type': + type: string + example: null operandLeft: type: object + example: null operandRight: type: object + example: null operator: type: string + example: null + example: null DataAddress: type: object properties: @@ -2050,96 +1996,176 @@ components: type: object additionalProperties: type: string + example: null + example: null + example: null DataAddressDto: required: - - properties + - properties type: object properties: - properties: + '@context': type: object - additionalProperties: - type: string - DataAddressInformationDto: - type: object - properties: + example: null + '@type': + type: string + example: null properties: type: object additionalProperties: type: string + example: null + example: null + example: null DataFlowRequest: type: object properties: callbackAddress: type: string format: url + example: null destinationDataAddress: $ref: '#/components/schemas/DataAddress' id: type: string + example: null processId: type: string + example: null properties: type: object additionalProperties: type: string + example: null + example: null sourceDataAddress: $ref: '#/components/schemas/DataAddress' traceContext: type: object additionalProperties: type: string + example: null + example: null trackable: type: boolean + example: null + example: null DataPlaneInstance: type: object properties: allowedDestTypes: uniqueItems: true type: array + example: null items: type: string + example: null allowedSourceTypes: uniqueItems: true type: array + example: null items: type: string + example: null id: type: string + example: null lastActive: type: integer format: int64 + example: null properties: type: object additionalProperties: type: object + example: null + example: null turnCount: type: integer format: int32 + example: null url: type: string format: url + example: null + example: null DataRequestDto: type: object properties: assetId: type: string + example: null connectorId: type: string + example: null contractId: type: string + example: null + id: + type: string + example: null + example: null + DataService: + type: object + properties: + endpointUrl: + type: string + example: null id: type: string + example: null + terms: + type: string + example: null + example: null + Dataset: + type: object + properties: + distributions: + type: array + example: null + items: + $ref: '#/components/schemas/Distribution' + id: + type: string + example: null + offers: + type: object + additionalProperties: + $ref: '#/components/schemas/Policy' + example: null + properties: + type: object + additionalProperties: + type: object + example: null + example: null + example: null DeprovisionedResource: type: object properties: error: type: boolean + example: null errorMessage: type: string + example: null inProcess: type: boolean + example: null provisionedResourceId: type: string + example: null + example: null + Distribution: + type: object + properties: + dataService: + $ref: '#/components/schemas/DataService' + format: + type: string + example: null + example: null Duty: type: object properties: @@ -2147,76 +2173,177 @@ components: $ref: '#/components/schemas/Action' assignee: type: string + example: null assigner: type: string + example: null consequence: $ref: '#/components/schemas/Duty' constraints: type: array + example: null items: $ref: '#/components/schemas/Constraint' parentPermission: $ref: '#/components/schemas/Permission' target: type: string - uid: - type: string + example: null + example: null Failure: type: object properties: failureDetail: type: string + example: null messages: type: array + example: null items: type: string + example: null + example: null HealthCheckResult: type: object properties: component: type: string + example: null failure: $ref: '#/components/schemas/Failure' isHealthy: type: boolean + example: null + example: null HealthStatus: type: object properties: componentResults: type: array + example: null items: $ref: '#/components/schemas/HealthCheckResult' isSystemHealthy: type: boolean + example: null + example: null IdResponseDto: type: object properties: + '@context': + type: object + example: null + '@id': + type: string + example: null + '@type': + type: string + example: null createdAt: type: integer format: int64 - id: + example: null + example: null + JsonArray: + type: array + properties: + empty: + type: boolean + example: null + valueType: type: string + example: null + enum: + - ARRAY + - OBJECT + - STRING + - NUMBER + - "TRUE" + - "FALSE" + - "NULL" + example: null + items: + $ref: '#/components/schemas/JsonValue' + JsonObject: + type: object + properties: + empty: + type: boolean + example: null + valueType: + type: string + example: null + enum: + - ARRAY + - OBJECT + - STRING + - NUMBER + - "TRUE" + - "FALSE" + - "NULL" + additionalProperties: + $ref: '#/components/schemas/JsonValue' + example: null + JsonValue: + type: object + properties: + valueType: + type: string + example: null + enum: + - ARRAY + - OBJECT + - STRING + - NUMBER + - "TRUE" + - "FALSE" + - "NULL" + example: null NegotiationInitiateRequestDto: - required: - - connectorAddress - - connectorId - - offer - - protocol type: object properties: + '@context': + type: object + example: null + '@type': + type: string + example: null + callbackAddresses: + type: array + example: null + items: + $ref: '#/components/schemas/CallbackAddress' connectorAddress: type: string + example: null connectorId: type: string + example: null + consumerId: + type: string + example: null offer: $ref: '#/components/schemas/ContractOfferDescription' protocol: type: string + example: null + providerId: + type: string + example: null + example: null NegotiationState: type: object properties: + '@context': + type: object + example: null + '@type': + type: string + example: null state: type: string + example: null + example: null Permission: type: object properties: @@ -2224,74 +2351,102 @@ components: $ref: '#/components/schemas/Action' assignee: type: string + example: null assigner: type: string + example: null constraints: type: array + example: null items: $ref: '#/components/schemas/Constraint' duties: type: array + example: null items: $ref: '#/components/schemas/Duty' target: type: string - uid: - type: string + example: null + example: null Policy: type: object properties: '@type': type: string + example: null enum: - - SET - - OFFER - - CONTRACT + - SET + - OFFER + - CONTRACT assignee: type: string + example: null assigner: type: string + example: null extensibleProperties: type: object additionalProperties: type: object + example: null + example: null inheritsFrom: type: string + example: null obligations: type: array + example: null items: $ref: '#/components/schemas/Duty' permissions: type: array + example: null items: $ref: '#/components/schemas/Permission' prohibitions: type: array + example: null items: $ref: '#/components/schemas/Prohibition' target: type: string + example: null + example: null PolicyDefinitionRequestDto: - required: - - policy type: object properties: - id: + '@id': type: string + example: null policy: $ref: '#/components/schemas/Policy' + example: null PolicyDefinitionResponseDto: - required: - - policy type: object properties: + '@context': + type: object + example: null + '@id': + type: string + example: null + '@type': + type: string + example: null createdAt: type: integer format: int64 - id: - type: string + example: null + policy: + $ref: '#/components/schemas/Policy' + example: null + PolicyDefinitionUpdateDto: + type: object + properties: policy: $ref: '#/components/schemas/Policy' + example: null Prohibition: type: object properties: @@ -2299,59 +2454,78 @@ components: $ref: '#/components/schemas/Action' assignee: type: string + example: null assigner: type: string + example: null constraints: type: array + example: null items: $ref: '#/components/schemas/Constraint' target: type: string - uid: - type: string + example: null + example: null ProvisionerWebhookRequest: required: - - apiKeyJwt - - assetId - - contentDataAddress - - resourceDefinitionId - - resourceName + - apiKeyJwt + - assetId + - contentDataAddress + - resourceDefinitionId + - resourceName type: object properties: apiKeyJwt: type: string + example: null assetId: type: string + example: null contentDataAddress: $ref: '#/components/schemas/DataAddress' hasToken: type: boolean + example: null resourceDefinitionId: type: string + example: null resourceName: type: string + example: null + example: null QuerySpecDto: type: object properties: - filter: + '@context': + type: object + example: null + '@type': type: string + example: null filterExpression: type: array + example: null items: $ref: '#/components/schemas/CriterionDto' limit: type: integer format: int32 + example: null offset: type: integer format: int32 + example: null sortField: type: string + example: null sortOrder: type: string + example: null enum: - - ASC - - DESC + - ASC + - DESC + example: null SelectionRequest: type: object properties: @@ -2361,79 +2535,130 @@ components: $ref: '#/components/schemas/DataAddress' strategy: type: string + example: null + example: null + TerminateTransferDto: + required: + - reason + type: object + properties: + reason: + type: string + example: null + example: null TransferProcessDto: type: object properties: + '@context': + type: object + example: null + '@id': + type: string + example: null + '@type': + type: string + example: null + callbackAddresses: + type: array + example: null + items: + $ref: '#/components/schemas/CallbackAddress' createdAt: type: integer format: int64 + example: null dataDestination: - $ref: '#/components/schemas/DataAddressInformationDto' + $ref: '#/components/schemas/DataAddressDto' dataRequest: $ref: '#/components/schemas/DataRequestDto' errorDetail: type: string - id: - type: string + example: null + properties: + type: object + additionalProperties: + type: string + example: null + example: null state: type: string + example: null stateTimestamp: type: integer format: int64 + example: null type: type: string + example: null updatedAt: type: integer format: int64 + example: null + example: null TransferProcessFailStateDto: required: - - errorMessage + - errorMessage type: object properties: errorMessage: type: string + example: null + example: null TransferRequestDto: required: - - assetId - - connectorAddress - - connectorId - - contractId - - dataDestination - - protocol - - transferType + - assetId + - connectorAddress + - connectorId + - contractId + - dataDestination + - protocol type: object properties: assetId: type: string + example: null + callbackAddresses: + type: array + example: null + items: + $ref: '#/components/schemas/CallbackAddress' connectorAddress: type: string + example: null connectorId: type: string + example: null contractId: type: string + example: null dataDestination: $ref: '#/components/schemas/DataAddress' id: type: string + example: null managedResources: type: boolean + example: null + privateProperties: + type: object + additionalProperties: + type: string + example: null + example: null properties: type: object additionalProperties: type: string + example: null + example: null protocol: type: string - transferType: - $ref: '#/components/schemas/TransferType' + example: null + example: null TransferState: type: object properties: state: type: string - TransferType: - type: object - properties: - contentType: - type: string - isFinite: - type: boolean + example: null + example: null diff --git a/docs/postman_collection.json b/docs/postman_collection.json index 544ab7978..ff0d03d45 100644 --- a/docs/postman_collection.json +++ b/docs/postman_collection.json @@ -1,605 +1,860 @@ { "info": { - "_postman_id": "68ee6d40-b4f6-4db4-873b-c843de7159a0", - "name": "sovity EDC", + "_postman_id": "91a35646-a337-4456-89d0-e3b96d21a593", + "name": "sovity EDC (0.1.2)", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { - "name": "1 Create Asset", - "event": [ + "name": "Assets", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([204, 409])", - "});" + "name": "1 Create Asset", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"http pull test 2\",\n \"asset:prop:description\": \"http pull 2\",\n \"asset:prop:id\": \"urn:artifact:http-pull\"\n }\n },\n \"dataAddress\": {\n \"properties\": {\n \"type\": \"HttpData\",\n \"baseUrl\": \"https://google.de\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } + "body": { + "mode": "raw", + "raw": "{\n \"@context\": {\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\n },\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"http source\",\n \"asset:prop:description\": \"http source asset description\",\n \"edc:id\": \"{{ASSET_ID}}\"\n }\n },\n \"dataAddress\": {\n \"type\": \"HttpData\",\n \"baseUrl\": \"{{PROVIDER_EDC_SOURCE_URL}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/assets", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "assets" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/assets", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "assets" - ] - } - }, - "response": [] - }, - { - "name": "1 Create Asset MDS", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([204, 409])", - "});" + "name": "1 Create Asset MDS", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"test-document\",\n \"asset:prop:description\": \"test-document\",\n \"asset:prop:id\": \"test-document\",\n \"asset:prop:contenttype\": \"text/plain\",\n \"asset:prop:version\": \"1.0\",\n \"type\": \"AzureStorage\",\n \"asset:prop:keywords\": \"keyword1,keyword2\",\n \"asset:prop:language\": \"https://w3id.org/idsa/code/EN\",\n \"asset:prop:publisher\": \"https://sovity.de/\",\n \"asset:prop:standardLicense\":\"https://creativecommons.org/licenses/by/4.0/\",\n \"asset:prop:endpointDocumentation\":\"https://github.com/Mobility-Data-Space/mobility-data-space/wiki/MDS-Ontology\",\n \"http://w3id.org/mds#transportMode\": \"Road\",\n \"http://w3id.org/mds#dataCategory\": \"Traffic Information\",\n \"http://w3id.org/mds#dataSubcategory\": \"Hazard Warnings\",\n \"http://w3id.org/mds#dataModel\": \"CSV\",\n \"http://w3id.org/mds#geoReferenceMethod\": \"Geo Ref Method Test\"\n }\n },\n \"dataAddress\": {\n \"properties\": {\n \"type\": \"HttpData\",\n \"baseUrl\": \"https://google.de\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } + "body": { + "mode": "raw", + "raw": "{\n \"@context\": {\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\n },\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"test-document\",\n \"asset:prop:description\": \"test-document\",\n \"edc:id\": \"{{ASSET_ID}}\",\n \"asset:prop:contenttype\": \"text/plain\",\n \"asset:prop:version\": \"1.0\",\n \"type\": \"AzureStorage\",\n \"asset:prop:keywords\": \"keyword1,keyword2\",\n \"asset:prop:language\": \"https://w3id.org/idsa/code/EN\",\n \"asset:prop:publisher\": \"https://sovity.de/\",\n \"asset:prop:standardLicense\": \"https://creativecommons.org/licenses/by/4.0/\",\n \"asset:prop:endpointDocumentation\": \"https://github.com/Mobility-Data-Space/mobility-data-space/wiki/MDS-Ontology\",\n \"http://w3id.org/mds#transportMode\": \"Road\",\n \"http://w3id.org/mds#dataCategory\": \"Traffic Information\",\n \"http://w3id.org/mds#dataSubcategory\": \"Hazard Warnings\",\n \"http://w3id.org/mds#dataModel\": \"CSV\",\n \"http://w3id.org/mds#geoReferenceMethod\": \"Geo Ref Method Test\"\n }\n },\n \"dataAddress\": {\n \"type\": \"HttpData\",\n \"baseUrl\": \"{{PROVIDER_EDC_SOURCE_URL}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/assets", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "assets" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/assets", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "assets" - ] - } - }, - "response": [] - }, - { - "name": "1 Delete Asset", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([204, 409])", - "});" + "name": "1 Delete Asset", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"text-document\",\n \"asset:prop:contenttype\": \"text/plain\",\n \"asset:prop:version\": \"1.0\",\n \"asset:prop:id\": \"text-document\",\n \"type\": \"AzureStorage\"\n }\n },\n \"dataAddress\": {\n \"properties\": {\n \"type\": \"AzureStorage\",\n \"account\": \"{{storage_account}}\",\n \"container\": \"src-container\",\n \"blobname\": \"text-document.txt\",\n \"keyName\": \"{{storage_account}}-key1\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } + "body": { + "mode": "raw", + "raw": "{\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"text-document\",\n \"asset:prop:contenttype\": \"text/plain\",\n \"asset:prop:version\": \"1.0\",\n \"asset:prop:id\": \"text-document\",\n \"type\": \"AzureStorage\"\n }\n },\n \"dataAddress\": {\n \"properties\": {\n \"type\": \"AzureStorage\",\n \"account\": \"{{storage_account}}\",\n \"container\": \"src-container\",\n \"blobname\": \"text-document.txt\",\n \"keyName\": \"{{storage_account}}-key1\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/assets/{{ASSET_ID}}", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "assets", + "{{ASSET_ID}}" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/assets/urn:artifact:http-pull", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "assets", - "urn:artifact:http-pull" - ] + { + "name": "1 Request Assets", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/assets/request", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "assets", + "request" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "2 Create Policy", - "event": [ + "name": "Policies", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([204, 409])", - "});" + "name": "2 Create Simple Policy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"id\": \"policy-id-2\",\n \"policy\": {\n \"permissions\": [\n {\n \"edctype\": \"dataspaceconnector:permission\",\n \"id\": null,\n \"target\": \"urn:artifact:http-pull\",\n \"action\": {\n \"type\": \"USE\",\n \"includedIn\": null,\n \"constraint\": null\n },\n \"assignee\": null,\n \"assigner\": null,\n \"constraints\": [],\n \"duties\": []\n }\n ],\n \"prohibitions\": [],\n \"obligations\": [],\n \"extensibleProperties\": {},\n \"inheritsFrom\": null,\n \"assigner\": null,\n \"assignee\": null,\n \"target\": null,\n \"@type\": {\n \"@policytype\": \"set\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } + "body": { + "mode": "raw", + "raw": "{\n \"@context\": {\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\n },\n \"@type\": \"PolicyDefinitionDto\",\n \"@id\": \"{{POLICY_ID}}\",\n \"policy\": {\n \"@context\": \"https://www.w3.org/ns/odrl.jsonld\",\n \"@type\": \"use\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/policydefinitions", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "policydefinitions" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/policydefinitions", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "policydefinitions" - ] - } - }, - "response": [] - }, - { - "name": "(get all policies)", - "request": { - "method": "GET", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/policydefinitions", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "policydefinitions" - ] - } - }, - "response": [] - }, - { - "name": "3 Create ContractDefinition", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([204, 409])", - "});" + "name": "2 Create Time Policy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"id\": \"contract-definition-id-2\",\n \"accessPolicyId\": \"policy-id-2\",\n \"contractPolicyId\": \"policy-id-2\"\n}", - "options": { - "raw": { - "language": "json" - } - } + "body": { + "mode": "raw", + "raw": "{\n \"@context\": {\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\",\n \"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n },\n \"@type\": \"PolicyDefinitionDto\",\n \"@id\": \"{{POLICY_ID}}\",\n \"edc:policy\": {\n \"@context\": \"https://www.w3.org/ns/odrl.jsonld\",\n \"odrl:permission\": [\n {\n \"odrl:action\": {\n \"odrl:type\": \"USE\"\n },\n \"odrl:constraint\": [\n {\n \"odrl:leftOperand\": \"POLICY_EVALUATION_TIME\",\n \"odrl:operator\": {\n \"@id\": \"odrl:gteq\"\n },\n \"odrl:rightOperand\": \"2022-05-31T22:00:00.000Z\"\n },\n {\n \"odrl:leftOperand\": \"POLICY_EVALUATION_TIME\",\n \"odrl:operator\": {\n \"@id\": \"odrl:lt\"\n },\n \"odrl:rightOperand\": \"2030-06-30T22:00:00.000Z\"\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/policydefinitions", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "policydefinitions" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/contractdefinitions", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "contractdefinitions" - ] - } - }, - "response": [] - }, - { - "name": "(get all contractdefinitions)", - "request": { - "method": "GET", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/contractdefinitions", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "contractdefinitions" - ] - } - }, - "response": [] - }, - { - "name": "Delete ContractDefinition", - "event": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", - " pm.expect(pm.response.code).to.be.oneOf([204, 409])", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "DELETE", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/contractdefinitions/contract-definition-id-2", - "host": [ - "{{BASE_URL}}" + "name": "2 Create Participant Policy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } ], - "path": [ - "management", - "contractdefinitions", - "contract-definition-id-2" - ] - } - }, - "response": [] - }, - { - "name": "4. Contract Offer", - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"connectorId\": \"provider\",\r\n \"connectorAddress\": \"http://edc:11003/api/v1/ids/data\",\r\n \"protocol\": \"ids-multipart\",\r\n \"offer\": {\r\n \"offerId\": \"contract-definition-id-2:contract-negotiation-id-2\",\r\n \"assetId\": \"urn:artifact:http-pull\",\r\n \"policy\": {\r\n \"uid\": \"policy-id-2\",\r\n \"type\": \"SET\",\r\n \"permissions\": [\r\n {\r\n \"edctype\": \"dataspaceconnector:permission\",\r\n \"uid\": null,\r\n \"target\": \"urn:artifact:http-pull\",\r\n \"action\": {\r\n \"type\": \"USE\",\r\n \"includedIn\": null,\r\n \"constraint\": null\r\n },\r\n \"assignee\": null,\r\n \"assigner\": null,\r\n \"constraints\": [],\r\n \"duties\": []\r\n }\r\n ]\r\n }\r\n },\r\n \"asset\": {\r\n \"properties\": {\r\n \"ids:byteSize\": null,\r\n \"asset:prop:id\": \"urn:artifact:http-pull\",\r\n \"ids:fileName\": null\r\n }\r\n }\r\n}\r\n}", - "options": { - "raw": { - "language": "json" - } - } + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"@context\": {\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\",\n \"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n },\n \"@type\": \"PolicyDefinitionDto\",\n \"@id\": \"{{POLICY_ID}}\",\n \"edc:policy\": {\n \"odrl:permission\": [\n {\n \"odrl:action\": {\n \"odrl:type\": \"USE\"\n },\n \"odrl:constraint\": [\n {\n \"odrl:leftOperand\": \"REFERRING_CONNECTOR\",\n \"odrl:operator\": {\n \"@id\": \"odrl:eq\"\n },\n \"odrl:rightOperand\": \"{{CONSUMER_EDC_PROTOCOL_URL}}\"\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/policydefinitions", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "policydefinitions" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL_2}}/management/contractnegotiations", - "host": [ - "{{BASE_URL_2}}" + { + "name": "2 Delete Policy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } ], - "path": [ - "management", - "contractnegotiations" - ] + "request": { + "method": "DELETE", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"asset\": {\n \"properties\": {\n \"asset:prop:name\": \"text-document\",\n \"asset:prop:contenttype\": \"text/plain\",\n \"asset:prop:version\": \"1.0\",\n \"asset:prop:id\": \"text-document\",\n \"type\": \"AzureStorage\"\n }\n },\n \"dataAddress\": {\n \"properties\": {\n \"type\": \"AzureStorage\",\n \"account\": \"{{storage_account}}\",\n \"container\": \"src-container\",\n \"blobname\": \"text-document.txt\",\n \"keyName\": \"{{storage_account}}-key1\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/policydefinitions/{{POLICY_ID}}", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "policydefinitions", + "{{POLICY_ID}}" + ] + } + }, + "response": [] + }, + { + "name": "2 Request Policies", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "pass", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/policydefinitions/request", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "policydefinitions", + "request" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "Contract Offer", - "request": { - "method": "GET", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/contractnegotiations", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "contractnegotiations" - ], - "query": [ + "name": "ContractDefinitions", + "item": [ + { + "name": "3 Create ContractDefinition", + "event": [ { - "key": "", - "value": "", - "disabled": true + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } } - ] - } - }, - "response": [] - }, - { - "name": "Cancel Contract Offer", - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/contractnegotiations/3f009db0-775d-4dfc-a965-decdf5a76aea/cancel", - "host": [ - "{{BASE_URL}}" ], - "path": [ - "management", - "contractnegotiations", - "3f009db0-775d-4dfc-a965-decdf5a76aea", - "cancel" - ] - } - }, - "response": [] - }, - { - "name": "Decline Contract Offer", - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/contractnegotiations/88687cb0-1d97-40c5-86c2-ad744afed538/decline", - "host": [ - "{{BASE_URL}}" + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"@context\": {\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\n },\n \"@id\": \"{{CONTRACT_DEFINITION_ID}}\",\n \"@type\": \"ContractDefinition\",\n \"edc:accessPolicyId\": \"{{POLICY_ID}}\",\n \"edc:contractPolicyId\": \"{{POLICY_ID}}\",\n \"edc:assetsSelector\": [\n {\n \"@type\": \"CriterionDto\",\n \"edc:operandLeft\": \"https://w3id.org/edc/v0.0.1/ns/id\",\n \"edc:operator\": \"=\",\n \"edc:operandRight\": \"{{ASSET_ID}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/contractdefinitions", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractdefinitions" + ] + } + }, + "response": [] + }, + { + "name": "3 Delete ContractDefinition", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 204 No Content (if new asset) or 409 Conflict (if asset already exists)\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([204, 409])", + "});" + ], + "type": "text/javascript" + } + } ], - "path": [ - "management", - "contractnegotiations", - "88687cb0-1d97-40c5-86c2-ad744afed538", - "decline" - ] + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/contractdefinitions/{{CONTRACT_DEFINITION_ID}}", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractdefinitions", + "{{CONTRACT_DEFINITION_ID}}" + ] + } + }, + "response": [] + }, + { + "name": "3 Request ContractDefinitions", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "pass", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{PROVIDER_EDC_MANAGEMENT_URL}}/contractdefinitions/request", + "host": [ + "{{PROVIDER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractdefinitions", + "request" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "4.1 Get ContractNegotiation", - "request": { - "method": "GET", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "url": { - "raw": "{{BASE_URL}}/management/contractnegotiations/", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "contractnegotiations", - "" - ] + "name": "Catalog", + "item": [ + { + "name": "4 Request Catalog", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"protocol\": \"dataspace-protocol-http\",\r\n \"providerUrl\": \"{{PROVIDER_EDC_PROTOCOL_URL}}\",\r\n \"querySpec\": {\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/catalog/request", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "catalog", + "request" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "5. Request Data Push", - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"protocol\": \"ids-multipart\",\r\n \"assetId\": \"urn:artifact:http-pull\",\r\n \"contractId\": \"contract-definition-id-2:39a5544c-f1d0-4145-8d22-269b6c0cd34c\",\r\n \"dataDestination\": {\r\n \"properties\": {\r\n \"type\": \"HttpData\",\r\n \"baseUrl\": \"https://webhook.site/792ee0b3-a601-4fff-b538-6b8f84e93a8a\",\r\n \"assetId\": \"urn:artifact:http-pull\"\r\n }\r\n },\r\n \"transferType\": {\r\n \"contentType\": \"application/octet-stream\",\r\n \"isFinite\": true\r\n },\r\n \"managedResources\": false,\r\n \"connectorAddress\": \"http://edc:8282/api/v1/ids/data\",\r\n \"connectorId\": \"consumer\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } + "name": "Contract Negotiations", + "item": [ + { + "name": "5 Start Negotiation", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"NegotiationInitiateRequestDto\",\r\n \"connectorId\": \"provider\",\r\n \"consumerId\": \"consumer\",\r\n \"providerId\": \"provider\",\r\n \"connectorAddress\": \"{{PROVIDER_EDC_PROTOCOL_URL}}\",\r\n \"protocol\": \"dataspace-protocol-http\",\r\n \"offer\": {\r\n \"offerId\": \"{{CONTRACT_DEFINITION_ID}}:{{ASSET_ID}}:b95a4734-009b-44a8-aac6-d36ef5da43c4\",\r\n \"assetId\": \"{{ASSET_ID}}\",\r\n \"policy\": {\r\n \"@id\": \"{{CONTRACT_DEFINITION_ID}}:{{ASSET_ID}}:b95a4734-009b-44a8-aac6-d36ef5da43c4\",\r\n \"@type\": \"http://www.w3.org/ns/odrl/2/Set\",\r\n \"http://www.w3.org/ns/odrl/2/permission\": [],\r\n \"http://www.w3.org/ns/odrl/2/prohibition\": [],\r\n \"http://www.w3.org/ns/odrl/2/obligation\": [],\r\n \"http://www.w3.org/ns/odrl/2/target\": \"http-source\"\r\n }\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractnegotiations", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractnegotiations" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL_2}}/management/transferprocess", - "host": [ - "{{BASE_URL_2}}" - ], - "path": [ - "management", - "transferprocess" - ] + { + "name": "5 Request Contract Negotiations", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractnegotiations/request", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractnegotiations", + "request" + ], + "query": [ + { + "key": "", + "value": "", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "5 Cancel Negotiation", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "pass", + "type": "default" + } + ], + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractnegotiations/3f009db0-775d-4dfc-a965-decdf5a76aea/cancel", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractnegotiations", + "3f009db0-775d-4dfc-a965-decdf5a76aea", + "cancel" + ] + } + }, + "response": [] + }, + { + "name": "5 Decline Negotiation", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "pass", + "type": "default" + } + ], + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractnegotiations/88687cb0-1d97-40c5-86c2-ad744afed538/decline", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractnegotiations", + "88687cb0-1d97-40c5-86c2-ad744afed538", + "decline" + ] + } + }, + "response": [] + }, + { + "name": "5 Get ContractNegotiation", + "request": { + "method": "GET", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractnegotiations/a4f61c8f-2406-4035-b091-ab73023643ac", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractnegotiations", + "a4f61c8f-2406-4035-b091-ab73023643ac" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "Get Transfer Process", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"protocol\": \"ids-multipart\",\r\n \"assetId\": \"assetId-rest-text-document\",\r\n \"contractId\": \"4a75736e-001d-4364-8bd4-9888490edb56abc-2:9df253dd-d523-431f-97ac-f2e90372c0b3\",\r\n \"dataDestination\": {\r\n \"properties\": {\r\n \"type\": \"HttpData\",\r\n \"assetId\": \"consumer-rest-text-document\"\r\n }\r\n },\r\n \"transferType\": {\r\n \"contentType\": \"application/octet-stream\",\r\n \"isFinite\": true\r\n },\r\n \"managedResources\": false,\r\n \"connectorAddress\": \"http://daps-connector-a-controlplane-1:8282/api/v1/ids/data\",\r\n \"connectorId\": \"consumer\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } + "name": "Contract Agreements", + "item": [ + { + "name": "6 Request Contract Agreements", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractagreements/request", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractagreements", + "request" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/transferprocess/", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "transferprocess", - "" - ] + { + "name": "6 Get Contract Agreement", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/contractagreements/{{CONTRACT_DEFINITION_ID}}:{{ASSET_ID}}:3de78ab9-9400-4996-b136-e6ac5201ddd8", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "contractagreements", + "{{CONTRACT_DEFINITION_ID}}:{{ASSET_ID}}:3de78ab9-9400-4996-b136-e6ac5201ddd8" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "Cancel Transfer Process", - "request": { - "method": "POST", - "header": [ - { - "key": "X-Api-Key", - "value": "ApiKeyDefaultValue", - "type": "default" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"protocol\": \"ids-multipart\",\r\n \"assetId\": \"assetId-rest-text-document\",\r\n \"contractId\": \"4a75736e-001d-4364-8bd4-9888490edb56abc-2:9df253dd-d523-431f-97ac-f2e90372c0b3\",\r\n \"dataDestination\": {\r\n \"properties\": {\r\n \"type\": \"HttpData\",\r\n \"assetId\": \"consumer-rest-text-document\"\r\n }\r\n },\r\n \"transferType\": {\r\n \"contentType\": \"application/octet-stream\",\r\n \"isFinite\": true\r\n },\r\n \"managedResources\": false,\r\n \"connectorAddress\": \"http://daps-connector-a-controlplane-1:8282/api/v1/ids/data\",\r\n \"connectorId\": \"consumer\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } + "name": "Data Transfer", + "item": [ + { + "name": "7 Start Data Push", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "ApiKeyDefaultValue", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"TransferRequestDto\",\r\n \"dataDestination\": {\r\n \"@type\": \"https://w3id.org/edc/v0.0.1/ns/DataAddress\",\r\n \"edc:type\": \"HttpData\",\r\n \"edc:properties\": {\r\n \"edc:baseUrl\": \"{{CONSUMER_EDC_TRANSFER_TARGET_URL}}\"\r\n }\r\n },\r\n \"protocol\": \"dataspace-protocol-http\",\r\n \"managedResources\": false,\r\n \"assetId\": \"{{ASSET_ID}}\",\r\n \"contractId\": \"{{CONTRACT_DEFINITION_ID}}:{{ASSET_ID}}:2037d0ff-e874-453d-bbb0-64ceed620015\",\r\n \"connectorAddress\": \"{{PROVIDER_EDC_PROTOCOL_URL}}\",\r\n \"privateProperties\": {}\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/transferprocesses", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "transferprocesses" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{BASE_URL}}/management/transferprocess/c715355b-1e4b-49a9-9ef0-956405e88fe3/cancel", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "management", - "transferprocess", - "c715355b-1e4b-49a9-9ef0-956405e88fe3", - "cancel" - ] + { + "name": "8 Request Transfer Processes", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "pass", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"QuerySpecDto\",\r\n \"offset\": 0,\r\n \"limit\": 10\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/transferprocesses/request", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "transferprocesses", + "request" + ] + } + }, + "response": [] + }, + { + "name": "8 Cancel Transfer Process", + "request": { + "method": "POST", + "header": [ + { + "key": "X-Api-Key", + "value": "pass", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"@context\": {\r\n \"edc\": \"https://w3id.org/edc/v0.0.1/ns/\"\r\n },\r\n \"@type\": \"TerminateTransferDto\",\r\n \"reason\": \"Termination reason\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{CONSUMER_EDC_MANAGEMENT_URL}}/transferprocesses/c715355b-1e4b-49a9-9ef0-956405e88fe3/terminate", + "host": [ + "{{CONSUMER_EDC_MANAGEMENT_URL}}" + ], + "path": [ + "transferprocesses", + "c715355b-1e4b-49a9-9ef0-956405e88fe3", + "terminate" + ] + } + }, + "response": [] } - }, - "response": [] + ] } ], "auth": { - "type": "oauth2", - "oauth2": [ + "type": "apikey", + "apikey": [ { - "key": "clientId", - "value": "control-plane", + "key": "key", + "value": "x-api-key", "type": "string" }, { - "key": "addTokenTo", - "value": "header", - "type": "string" - }, - { - "key": "redirect_uri", - "value": "http://localhost:8583/*", - "type": "string" - }, - { - "key": "useBrowser", - "value": false, - "type": "boolean" - }, - { - "key": "accessTokenUrl", - "value": "http://localhost:9191/realms/sovity/protocol/openid-connect/token", - "type": "string" - }, - { - "key": "authUrl", - "value": "http://localhost:9191/realms/sovity/protocol/openid-connect/auth", + "key": "value", + "value": "ApiKeyDefaultValue", "type": "string" } ] @@ -629,13 +884,53 @@ ], "variable": [ { - "key": "BASE_URL", - "value": "http://localhost:11002/api/v1", + "key": "PROVIDER_EDC_MANAGEMENT_URL", + "value": "http://localhost:11002/api/management/v2", + "type": "default" + }, + { + "key": "PROVIDER_EDC_PROTOCOL_URL", + "value": "http://edc:11003/api/v1/protocol", + "type": "default" + }, + { + "key": "PROVIDER_EDC_SOURCE_URL", + "value": "https://api.github.com/repos/sovity/edc-extensions/events", + "type": "default" + }, + { + "key": "CONSUMER_EDC_MANAGEMENT_URL", + "value": "http://localhost:22002/api/management/v2", + "type": "default" + }, + { + "key": "CONSUMER_EDC_PROTOCOL_URL", + "value": "http://edc2:11003/api/v1/protocol", + "type": "default" + }, + { + "key": "CONSUMER_EDC_TRANSFER_TARGET_URL", + "value": "https://webhook.site/a418c986-299d-4e22-a1e1-bf532631913a", + "type": "default" + }, + { + "key": "COUNTER", + "value": "1", + "type": "default" + }, + { + "key": "ASSET_ID", + "value": "http-source-{{COUNTER}}", + "type": "default" + }, + { + "key": "POLICY_ID", + "value": "policy-{{COUNTER}}", "type": "default" }, { - "key": "BASE_URL_2", - "value": "http://localhost:12002/api/v1", + "key": "CONTRACT_DEFINITION_ID", + "value": "contract-definition-{{COUNTER}}", "type": "default" } ] diff --git a/e2e-test/build.gradle.kts b/e2e-test/build.gradle.kts new file mode 100644 index 000000000..9137c762b --- /dev/null +++ b/e2e-test/build.gradle.kts @@ -0,0 +1,34 @@ +val edcVersion: String by project +val edcGroup: String by project +val testcontainersVersion: String by project +val lombokVersion: String by project +val restAssured: String by project +val awaitilityVersion: String by project +val assertj: String by project + +plugins { + `java-library` +} + +dependencies { + testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}") + testCompileOnly("org.projectlombok:lombok:${lombokVersion}") + + testImplementation(project(":connector")) + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") + testImplementation("org.apache.commons:commons-lang3:3.12.0") + testImplementation("${edcGroup}:junit:${edcVersion}") + testImplementation("${edcGroup}:sql-core:${edcVersion}") + testImplementation("${edcGroup}:json-ld-spi:${edcVersion}") + testImplementation("${edcGroup}:json-ld:${edcVersion}") + testImplementation("${edcGroup}:transfer-spi:${edcVersion}") + testImplementation("org.assertj:assertj-core:${assertj}") + testImplementation("${edcGroup}:contract-spi:${edcVersion}") + testImplementation("org.testcontainers:testcontainers:${testcontainersVersion}") + testImplementation("org.testcontainers:junit-jupiter:${testcontainersVersion}") + testImplementation("org.testcontainers:postgresql:${testcontainersVersion}") + testImplementation("io.rest-assured:rest-assured:${restAssured}") + testImplementation("org.awaitility:awaitility:${awaitilityVersion}") + +} \ No newline at end of file diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/PostgresFlywayExtensionTest.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/PostgresFlywayExtensionTest.java new file mode 100644 index 000000000..45ae5ecc9 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/PostgresFlywayExtensionTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e; + +import de.sovity.edc.extension.e2e.connector.Connector; +import de.sovity.edc.extension.e2e.connector.JsonLdConnectorUtil; +import de.sovity.edc.extension.e2e.connector.factory.TestConnectorFactory; +import de.sovity.edc.extension.e2e.db.TestDatabase; +import de.sovity.edc.extension.e2e.db.TestDatabaseFactory; +import jakarta.json.JsonObject; +import org.eclipse.edc.junit.extensions.EdcExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.net.URI; +import java.time.Duration; +import java.util.Map; +import java.util.UUID; + +import static de.sovity.edc.extension.e2e.connector.config.EdcApiGroup.PROTOCOL; +import static jakarta.json.Json.createObjectBuilder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; +import static org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates.COMPLETED; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_POLICY_ATTRIBUTE; + +@Disabled("Just to be executed with postgres-flyway property set") +public class PostgresFlywayExtensionTest { + + private static final String PROVIDER_TARGET_URL = "https://google.de"; + private static final String CONSUMER_BACKEND_URL = "https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a"; + private static final Duration TIMEOUT = Duration.ofSeconds(60); + private static final String MIGRATED_M8_ASSET_ID = "test-1.0"; + + @RegisterExtension + static EdcExtension providerEdcContext = new EdcExtension(); + @RegisterExtension + static EdcExtension consumerEdcContext = new EdcExtension(); + + @RegisterExtension + private static final TestDatabase PROVIDER_DATABASE = TestDatabaseFactory.getTestDatabase(); + @RegisterExtension + private static final TestDatabase CONSUMER_DATABASE = TestDatabaseFactory.getTestDatabase(); + + private Connector providerConnector; + private Connector consumerConnector; + + @BeforeEach + void setUp() { + providerConnector = new TestConnectorFactory( + "provider", + providerEdcContext, + PROVIDER_DATABASE) + .createConnector(); + consumerConnector = new TestConnectorFactory( + "consumer", + consumerEdcContext, + CONSUMER_DATABASE) + .createConnector(); + } + + @Test + void consumeM8Offer() { + var assetIds = providerConnector.getAssetIds(); + assertThat(assetIds).contains(MIGRATED_M8_ASSET_ID); + var providerProtocolApi = providerConnector.getUriForApi(PROTOCOL); + consumeOffer(providerProtocolApi, MIGRATED_M8_ASSET_ID); + } + + @Test + void createAndConsumeOffer() { + var assetId = UUID.randomUUID().toString(); + createContractOffer(assetId); + var providerProtocolApi = providerConnector.getUriForApi(PROTOCOL); + consumeOffer(providerProtocolApi, assetId); + } + + private void consumeOffer(URI providerProtocolApi, String assetId) { + var dataset = consumerConnector.getDatasetForAsset(assetId, providerProtocolApi); + var contractId = JsonLdConnectorUtil.getContractId(dataset); + var policy = dataset.getJsonArray(ODRL_POLICY_ATTRIBUTE).get(0).asJsonObject(); + + var contractAgreementId = consumerConnector.negotiateContract( + providerConnector.getParticipantId(), + providerProtocolApi, + contractId.toString(), + contractId.assetIdPart(), + policy); + + var destination = JsonLdConnectorUtil.httpDataAddress(CONSUMER_BACKEND_URL); + var transferProcessId = consumerConnector.initiateTransfer(contractAgreementId, assetId, + providerProtocolApi, destination); + + await().atMost(TIMEOUT).untilAsserted(() -> { + var state = consumerConnector.getTransferProcessState(transferProcessId); + assertThat(state).isEqualTo(COMPLETED.name()); + }); + } + + private void createContractOffer(String assetId) { + var contractDefinitionId = UUID.randomUUID().toString(); + providerConnector.createAsset(assetId, httpDataAddressProperties()); + var noConstraintPolicyId = providerConnector.createPolicy(noConstraintPolicy()); + providerConnector.createContractDefinition( + assetId, + contractDefinitionId, + noConstraintPolicyId, + noConstraintPolicyId); + } + + private JsonObject noConstraintPolicy() { + return createObjectBuilder() + .add(CONTEXT, "https://www.w3.org/ns/odrl.jsonld") + .add(TYPE, "use") + .build(); + } + + private Map httpDataAddressProperties() { + return Map.of( + "name", "transfer-test", + "baseUrl", PROVIDER_TARGET_URL, + "type", "HttpData", + "proxyQueryParams", "true" + ); + } +} \ No newline at end of file diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/Connector.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/Connector.java new file mode 100644 index 000000000..29b4519c5 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/Connector.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector; + +import de.sovity.edc.extension.e2e.connector.config.EdcApiGroup; +import jakarta.json.JsonObject; + +import java.net.URI; +import java.util.List; +import java.util.Map; + +public interface Connector { + + void createAsset(String assetId, Map dataAddressProperties); + + List getAssetIds(); + + String createPolicy(JsonObject policyJsonObject); + + void createContractDefinition( + String assetId, + String contractDefinitionId, + String accessPolicyId, + String contractPolicyId); + + JsonObject getDatasetForAsset(String assetId, URI providerProtocolEndpoint); + + String negotiateContract( + String providerParticipantId, + URI providerProtocolEndpoint, + String offerId, + String assetId, + JsonObject policy); + + Map getConfig(); + + URI getUriForApi(EdcApiGroup edcApiGroup); + + String getParticipantId(); + + String initiateTransfer( + String contractAgreementId, + String assetId, + URI providerProtocolApi, + JsonObject destination); + + String getTransferProcessState(String id); +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/JsonLdConnectorUtil.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/JsonLdConnectorUtil.java new file mode 100644 index 000000000..d21b48be6 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/JsonLdConnectorUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector; + +import jakarta.json.JsonObject; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.eclipse.edc.connector.contract.spi.ContractId; + +import static jakarta.json.Json.createObjectBuilder; +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.ODRL_POLICY_ATTRIBUTE; +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonLdConnectorUtil { + + public static ContractId getContractId(JsonObject dataset) { + var id = dataset.getJsonArray(ODRL_POLICY_ATTRIBUTE).get(0).asJsonObject().getString(ID); + return ContractId.parse(id); + } + + + public static JsonObject httpDataAddress(String baseUrl) { + return createObjectBuilder() + .add(TYPE, EDC_NAMESPACE + "DataAddress") + .add(EDC_NAMESPACE + "type", "HttpData") + .add(EDC_NAMESPACE + "properties", createObjectBuilder() + .add(EDC_NAMESPACE + "baseUrl", baseUrl) + .build()) + .build(); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/TestConnector.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/TestConnector.java new file mode 100644 index 000000000..e960a256e --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/TestConnector.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector; + +import com.fasterxml.jackson.databind.ObjectMapper; +import de.sovity.edc.extension.e2e.connector.config.DatasourceConfig; +import de.sovity.edc.extension.e2e.connector.config.EdcApiGroup; +import de.sovity.edc.extension.e2e.connector.config.EdcApiGroupConfig; +import de.sovity.edc.extension.e2e.connector.config.EdcConfig; +import de.sovity.edc.extension.e2e.connector.config.SimpleConfig; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import lombok.Builder; +import lombok.Singular; +import org.eclipse.edc.jsonld.TitaniumJsonLd; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; + +import java.net.URI; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Stream; + +import static de.sovity.edc.extension.e2e.connector.config.EdcApiGroup.MANAGEMENT; +import static io.restassured.RestAssured.given; +import static io.restassured.http.ContentType.JSON; +import static jakarta.json.Json.createObjectBuilder; +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; +import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates.FINALIZED; +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.jsonld.spi.PropertyAndTypeNames.DCAT_DATASET_ATTRIBUTE; +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX; + +@Builder +public class TestConnector implements Connector { + + private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); + private final Duration timeout = Duration.ofSeconds(60); + private final JsonLd jsonLd = new TitaniumJsonLd(new ConsoleMonitor()); + private final String participantId; + + @Singular + private final List datasourceConfigs; + + @Singular + private final List simpleConfigs; + + private final String baseUrl; + private final Map apiGroupConfigMap; + + @Override + public void createAsset(String assetId, Map dataAddressProperties) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add("asset", createObjectBuilder() + .add(ID, assetId) + .add("properties", createObjectBuilder() + .add("description", "description"))) + .add("dataAddress", createObjectBuilder(dataAddressProperties)) + .build(); + + given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/assets") + .then() + .statusCode(200) + .contentType(JSON); + } + + @Override + public List getAssetIds() { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "QuerySpecDto") + .build(); + return given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/assets/request") + .then() + .statusCode(200) + .contentType(JSON) + .extract().jsonPath().getList("@id"); + } + + @Override + public String createPolicy(JsonObject policyJsonObject) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "PolicyDefinitionDto") + .add("policy", policyJsonObject) + .build(); + + return given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/policydefinitions") + .then() + .statusCode(200) + .contentType(JSON) + .extract().jsonPath().getString(ID); + } + + @Override + public void createContractDefinition( + String assetId, + String contractDefinitionId, + String accessPolicyId, + String contractPolicyId) { + var requestBody = createObjectBuilder() + .add(ID, contractDefinitionId) + .add(TYPE, EDC_NAMESPACE + "ContractDefinition") + .add(EDC_NAMESPACE + "accessPolicyId", accessPolicyId) + .add(EDC_NAMESPACE + "contractPolicyId", contractPolicyId) + .add(EDC_NAMESPACE + "assetsSelector", Json.createArrayBuilder() + .add(createObjectBuilder() + .add(TYPE, "CriterionDto") + .add(EDC_NAMESPACE + "operandLeft", EDC_NAMESPACE + "id") + .add(EDC_NAMESPACE + "operator", "=") + .add(EDC_NAMESPACE + "operandRight", assetId) + .build()) + .build()) + .build(); + + given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/contractdefinitions") + .then() + .statusCode(200) + .contentType(JSON); + } + + public JsonArray getCatalogDatasets(URI providerProtocolEndpoint) { + var datasetReference = new AtomicReference(); + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "CatalogRequest") + .add("providerUrl", providerProtocolEndpoint.toString()) + .add("protocol", "dataspace-protocol-http") + .build(); + + await().atMost(timeout).untilAsserted(() -> { + var response = given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .when() + .body(requestBody) + .post("/v2/catalog/request") + .then() + .statusCode(200) + .extract().body().asString(); + + var responseBody = objectMapper.readValue(response, JsonObject.class); + + var catalog = + jsonLd.expand(responseBody).orElseThrow(f -> new EdcException(f.getFailureDetail())); + + var datasets = catalog.getJsonArray(DCAT_DATASET_ATTRIBUTE); + assertThat(datasets).hasSizeGreaterThan(0); + + datasetReference.set(datasets); + }); + + return datasetReference.get(); + } + + @Override + public JsonObject getDatasetForAsset(String assetId, URI providerProtocolEndpoint) { + var datasets = getCatalogDatasets(providerProtocolEndpoint); + return datasets.stream() + .map(JsonValue::asJsonObject) + .filter(it -> assetId.equals(JsonLdConnectorUtil.getContractId(it).assetIdPart())) + .findFirst() + .orElseThrow(() -> new EdcException(format("No dataset for asset %s in the " + + "catalog", assetId))); + } + + @Override + public String negotiateContract( + String providerParticipantId, + URI providerProtocolEndpoint, + String offerId, + String assetId, + JsonObject policy) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "NegotiationInitiateRequestDto") + .add("connectorId", providerParticipantId) + .add("consumerId", participantId) + .add("providerId", providerParticipantId) + .add("connectorAddress", providerProtocolEndpoint.toString()) + .add("protocol", "dataspace-protocol-http") + .add("offer", createObjectBuilder() + .add("offerId", offerId) + .add("assetId", assetId) + .add("policy", jsonLd.compact(policy).getContent()) + ) + .build(); + + var negotiationId = given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/contractnegotiations") + .then() + .statusCode(200) + .extract().body().jsonPath().getString(ID); + + await().atMost(timeout).untilAsserted(() -> { + var state = getContractNegotiationState(negotiationId); + assertThat(state).isEqualTo(FINALIZED.name()); + }); + + return getContractAgreementId(negotiationId); + } + + public String getContractAgreementId(String negotiationId) { + var contractAgreementId = new AtomicReference(); + + await().atMost(timeout).untilAsserted(() -> { + var agreementId = getContractNegotiationField(negotiationId, "contractAgreementId"); + assertThat(agreementId).isNotNull().isInstanceOf(String.class); + + contractAgreementId.set(agreementId); + }); + + var id = contractAgreementId.get(); + assertThat(id).isNotEmpty(); + return id; + } + + private String getContractNegotiationField(String negotiationId, String fieldName) { + return given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .when() + .get("/v2/contractnegotiations/{id}", negotiationId) + .then() + .statusCode(200) + .extract().body().jsonPath() + .getString(format("'edc:%s'", fieldName)); + } + + public String getContractNegotiationState(String id) { + return given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .when() + .get("/v2/contractnegotiations/{id}/state", id) + .then() + .statusCode(200) + .extract().body().jsonPath().getString("'edc:state'"); + } + + + @Override + public URI getUriForApi(EdcApiGroup edcApiGroup) { + return apiGroupConfigMap.get(edcApiGroup).getUri(); + } + + @Override + public String getParticipantId() { + return participantId; + } + + @Override + public String initiateTransfer( + String contractAgreementId, + String assetId, + URI providerProtocolApi, + JsonObject destination) { + var requestBody = createObjectBuilder() + .add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE)) + .add(TYPE, "TransferRequestDto") + .add("dataDestination", destination) + .add("protocol", "dataspace-protocol-http") + .add("managedResources", false) + .add("assetId", assetId) + .add("contractId", contractAgreementId) + .add("connectorAddress", providerProtocolApi.toString()) + .add("privateProperties", Json.createObjectBuilder().build()) + .add("connectorId", participantId) + .build(); + + return given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .body(requestBody) + .when() + .post("/v2/transferprocesses") + .then() + .statusCode(200) + .extract().body().jsonPath().getString(ID); + } + + @Override + public String getTransferProcessState(String id) { + return given() + .baseUri(getUriForApi(MANAGEMENT).toString()) + .contentType(JSON) + .when() + .get("/v2/transferprocesses/{id}/state", id) + .then() + .statusCode(200) + .extract().body().jsonPath().getString("'edc:state'"); + } + + @Override + public Map getConfig() { + var configStream = Stream.of( + apiGroupConfigMap.values().stream().toList(), + datasourceConfigs, + simpleConfigs); + return new HashMap<>() { + { + configStream.flatMap(List::stream) + .map(EdcConfig::toMap) + .forEach(this::putAll); + } + }; + } + + public static class TestConnectorBuilder { + public TestConnectorBuilder configProperty(String key, String value) { + this.simpleConfig(new SimpleConfig(key, value)); + return this; + } + } + +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfig.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfig.java new file mode 100644 index 000000000..63bc1005e --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/DatasourceConfig.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.config; + +import java.util.Map; + +public record DatasourceConfig( + String name, + String jdbcUrl, + String jdbcUser, + String jdbcPassword) implements EdcConfig { + + private static final String SETTING_DATASOURCE_NAME = "edc.datasource.%s.name"; + private static final String SETTING_DATASOURCE_URL = "edc.datasource.%s.url"; + private static final String SETTING_DATASOURCE_USER = "edc.datasource.%s.user"; + private static final String SETTING_DATASOURCE_PASSWORD = "edc.datasource.%s.password"; + + @Override + public Map toMap() { + return Map.of( + String.format(SETTING_DATASOURCE_NAME, name), name, + String.format(SETTING_DATASOURCE_URL, name), jdbcUrl, + String.format(SETTING_DATASOURCE_USER, name), jdbcUser, + String.format(SETTING_DATASOURCE_PASSWORD, name), jdbcPassword + ); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroup.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroup.java new file mode 100644 index 000000000..1795b60ee --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroup.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.config; + +public enum EdcApiGroup { + DEFAULT(""), + PROTOCOL("protocol"), + MANAGEMENT("management"), + CONTROL("control"); + + private final String dataSourcePropertyName; + + EdcApiGroup(String dataSourcePropertyName) { + this.dataSourcePropertyName = dataSourcePropertyName; + } + + public String getDataSourcePropertyName() { + return dataSourcePropertyName; + } +} \ No newline at end of file diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroupConfig.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroupConfig.java new file mode 100644 index 000000000..1ad3de619 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcApiGroupConfig.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.config; + +import java.net.URI; +import java.util.Map; + +public record EdcApiGroupConfig( + EdcApiGroup edcApiGroup, + String baseUrl, + int port, + String path) implements EdcConfig { + + private static final String SETTING_WEB_HTTP_PATH = "web.http.%s.path"; + private static final String SETTING_WEB_HTTP_PORT = "web.http.%s.port"; + private static final String SETTING_WEB_HTTP_DEFAULT_PATH = "web.http.path"; + private static final String SETTING_WEB_HTTP_DEFAULT_PORT = "web.http.port"; + + public URI getUri() { + return URI.create(String.format("%s:%s%s", baseUrl, port, path)); + } + + @Override + public Map toMap() { + if ("".equals(edcApiGroup.getDataSourcePropertyName())) { + return Map.of( + SETTING_WEB_HTTP_DEFAULT_PATH, path, + SETTING_WEB_HTTP_DEFAULT_PORT, String.valueOf(port) + ); + } else { + var webHttpPathProperty = String.format( + SETTING_WEB_HTTP_PATH, + edcApiGroup.getDataSourcePropertyName()); + var webHttpPortProperty = String.format( + SETTING_WEB_HTTP_PORT, + edcApiGroup.getDataSourcePropertyName()); + return Map.of( + webHttpPathProperty, path, + webHttpPortProperty, String.valueOf(port)); + } + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcConfig.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcConfig.java new file mode 100644 index 000000000..e46970de6 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/EdcConfig.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.config; + +import java.util.Map; + +public interface EdcConfig { + Map toMap(); +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/SimpleConfig.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/SimpleConfig.java new file mode 100644 index 000000000..47c00901a --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/config/SimpleConfig.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.config; + +import java.util.Map; + +public record SimpleConfig(String name, String value) implements EdcConfig { + + @Override + public Map toMap() { + return Map.of(name, value); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/ConnectorFactory.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/ConnectorFactory.java new file mode 100644 index 000000000..0679d192b --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/ConnectorFactory.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.factory; + +import de.sovity.edc.extension.e2e.connector.Connector; + +public interface ConnectorFactory { + + Connector createConnector(); +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/TestConnectorFactory.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/TestConnectorFactory.java new file mode 100644 index 000000000..85bfcbb45 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/connector/factory/TestConnectorFactory.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.connector.factory; + +import de.sovity.edc.extension.e2e.connector.Connector; +import de.sovity.edc.extension.e2e.connector.TestConnector; +import de.sovity.edc.extension.e2e.connector.config.DatasourceConfig; +import de.sovity.edc.extension.e2e.connector.config.EdcApiGroup; +import de.sovity.edc.extension.e2e.connector.config.EdcApiGroupConfig; +import de.sovity.edc.extension.e2e.db.TestDatabase; +import lombok.RequiredArgsConstructor; +import org.eclipse.edc.junit.extensions.EdcExtension; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static de.sovity.edc.extension.e2e.connector.config.EdcApiGroup.CONTROL; +import static de.sovity.edc.extension.e2e.connector.config.EdcApiGroup.DEFAULT; +import static de.sovity.edc.extension.e2e.connector.config.EdcApiGroup.MANAGEMENT; +import static de.sovity.edc.extension.e2e.connector.config.EdcApiGroup.PROTOCOL; +import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; + +@RequiredArgsConstructor +public class TestConnectorFactory implements ConnectorFactory { + + private static final String BASE_URL = "http://localhost"; + private static final List DATASOURCE_NAMES = List.of( + "asset", + "contractdefinition", + "contractnegotiation", + "policy", + "transferprocess", + "dataplaneinstance", + "default" + ); + private static final String DEFAULT_API_GROUP_PATH = "/api"; + private static final String PROTOCOL_API_GROUP_PATH = "/dsp"; + private static final String MANAGEMENT_API_GROUP_PATH = "/api/management"; + private static final String CONTROL_API_GROUP_PATH = "/control"; + + private final String participantId; + private final EdcExtension edcContext; + private final TestDatabase testDatabase; + + @Override + public Connector createConnector() { + var apiGroupConfigMap = createApiGroupConfigMap(); + var dspCallbackAddress = apiGroupConfigMap.get(PROTOCOL).getUri(); + var datasourceConfigs = getDatasourceConfigs(testDatabase); + var migrationLocation = "classpath:migration/" + participantId; + var connector = TestConnector.builder() + .participantId(participantId) + .apiGroupConfigMap(apiGroupConfigMap) + .datasourceConfigs(datasourceConfigs) + .configProperty("edc.participant.id", participantId) + .configProperty("edc.api.auth.key", UUID.randomUUID().toString()) + .configProperty("edc.last.commit.info", "test env commit message") + .configProperty("edc.build.date", "2023-05-08T15:30:00Z") + .configProperty("edc.jsonld.https.enabled", "true") + .configProperty("edc.dsp.callback.address", dspCallbackAddress.toString()) + .configProperty("edc.flyway.additional.migration.locations", migrationLocation) + .build(); + System.out.println(connector.getConfig()); + edcContext.setConfiguration(connector.getConfig()); + return connector; + } + + private Map createApiGroupConfigMap() { + return Map.of( + DEFAULT, createApiGroupConfig(DEFAULT, DEFAULT_API_GROUP_PATH), + PROTOCOL, createApiGroupConfig(PROTOCOL, PROTOCOL_API_GROUP_PATH), + MANAGEMENT, createApiGroupConfig(MANAGEMENT, MANAGEMENT_API_GROUP_PATH), + CONTROL, createApiGroupConfig(CONTROL, CONTROL_API_GROUP_PATH)); + } + + private EdcApiGroupConfig createApiGroupConfig(EdcApiGroup edcApiGroup, String path) { + return new EdcApiGroupConfig(edcApiGroup, BASE_URL, getFreePort(), path); + } + + private List getDatasourceConfigs(TestDatabase testDatabase) { + return DATASOURCE_NAMES.stream() + .map(name -> new DatasourceConfig( + name, + testDatabase.getJdbcUrl(), + testDatabase.getJdbcUser(), + testDatabase.getJdbcPassword())) + .toList(); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/DataSourceFactory.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/DataSourceFactory.java new file mode 100644 index 000000000..40731d051 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/DataSourceFactory.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.extension.e2e.db; + +import org.eclipse.edc.spi.persistence.EdcPersistenceException; +import org.eclipse.edc.sql.datasource.ConnectionFactoryDataSource; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Create {@link DataSource}s from EDC Config. + */ +public class DataSourceFactory { + + /** + * Create a new {@link DataSource} from JDBC Credentials. + *
+ * This method was extracted into a static method, so we can call it from our Test Code. + *
+ * warning: Just use this method in Test Code, as it will not reuse connections. + * + * @param jdbcCredentials jdbc credentials + * @return {@link DataSource} + */ + public static DataSource fromJdbcCredentials(JdbcCredentials jdbcCredentials) { + return new ConnectionFactoryDataSource(() -> newConnection(jdbcCredentials)); + } + + private static Connection newConnection(JdbcCredentials jdbcCredentials) { + try { + return DriverManager.getConnection( + jdbcCredentials.jdbcUrl(), + jdbcCredentials.jdbcUser(), + jdbcCredentials.jdbcPassword() + ); + } catch (SQLException e) { + throw new EdcPersistenceException(e); + } + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java new file mode 100644 index 000000000..81357af93 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/JdbcCredentials.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - initial implementation + * + */ + +package de.sovity.edc.extension.e2e.db; + +/** + * JDBC Credentials + * + * @param jdbcUrl JDBC URL without credentials + * @param jdbcUser JDBC User + * @param jdbcPassword JDBC Password + */ +public record JdbcCredentials( + String jdbcUrl, + String jdbcUser, + String jdbcPassword +) { +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabase.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabase.java new file mode 100644 index 000000000..104a7a47f --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabase.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - initial implementation + * + */ + +package de.sovity.edc.extension.e2e.db; + +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; + +import javax.sql.DataSource; + +public interface TestDatabase extends BeforeAllCallback, AfterAllCallback { + + JdbcCredentials getJdbcCredentials(); + String getJdbcUrl(); + + String getJdbcUser(); + + String getJdbcPassword(); + + /** + * Returns a {@link DataSource} to the test database + * + * @return {@link DataSource} + */ + default DataSource getDataSource() { + var jdbcCredentials = new JdbcCredentials(getJdbcUrl(), getJdbcUser(), getJdbcPassword()); + return DataSourceFactory.fromJdbcCredentials(jdbcCredentials); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java new file mode 100644 index 000000000..955665f7f --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - initial implementation + * + */ + +package de.sovity.edc.extension.e2e.db; + +public class TestDatabaseFactory { + + private static int postgresHostPort = 5432; + + private TestDatabaseFactory() { + } + + /** + * Returns a JUnit 5 Extension that either connects to a test database or launches a + * testcontainer. + * + * @return {@link TestDatabase} + */ + public static TestDatabase getTestDatabase() { + if (TestDatabaseViaEnv.isSkipTestcontainers()) { + return new TestDatabaseViaEnv(); + } + + return new TestDatabaseViaTestcontainers(postgresHostPort++); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnv.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnv.java new file mode 100644 index 000000000..281231013 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaEnv.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - initial implementation + * + */ + +package de.sovity.edc.extension.e2e.db; + +import org.apache.commons.lang3.Validate; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class TestDatabaseViaEnv implements TestDatabase { + public static final String SKIP_TESTCONTAINERS = "SKIP_TESTCONTAINERS"; + public static final String TEST_POSTGRES_JDBC_URL = "TEST_POSTGRES_JDBC_URL"; + public static final String TEST_POSTGRES_JDBC_USER = "TEST_POSTGRES_JDBC_USER"; + public static final String TEST_POSTGRES_JDBC_PASSWORD = "TEST_POSTGRES_JDBC_PASSWORD"; + + @Override + public void afterAll(ExtensionContext context) throws Exception { + + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + + } + + @Override + public JdbcCredentials getJdbcCredentials() { + return new JdbcCredentials(getJdbcUrl(), getJdbcUser(), getJdbcPassword()); + } + + public String getJdbcUrl() { + return getRequiredEnv(TEST_POSTGRES_JDBC_URL); + } + + public String getJdbcUser() { + return getRequiredEnv(TEST_POSTGRES_JDBC_USER); + } + + public String getJdbcPassword() { + return getRequiredEnv(TEST_POSTGRES_JDBC_PASSWORD); + } + + private static String getRequiredEnv(String name) { + String value = System.getenv(name); + Validate.notBlank(value, "Need env var %s since %s is true", name, SKIP_TESTCONTAINERS); + return value; + } + + public static boolean isSkipTestcontainers() { + return "true".equals(System.getenv(SKIP_TESTCONTAINERS)); + } +} diff --git a/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java new file mode 100644 index 000000000..de2b3ae69 --- /dev/null +++ b/e2e-test/src/test/java/de/sovity/edc/extension/e2e/db/TestDatabaseViaTestcontainers.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - initial implementation + * + */ + +package de.sovity.edc.extension.e2e.db; + +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.testcontainers.containers.PostgreSQLContainer; + +public class TestDatabaseViaTestcontainers implements TestDatabase { + + private static final int POSTGRES_PORT = 5432; + private static final String POSTGRES_USER = "postgres"; + private static final String POSTGRES_PASSWORD = "postgres"; + private static final String POSTGRES_DB = "edc"; + + private final PostgreSQLContainer container; + + public TestDatabaseViaTestcontainers(int hostPort) { + var portBinding = new PortBinding( + Ports.Binding.bindPort(hostPort), + new ExposedPort(POSTGRES_PORT)); + container = new PostgreSQLContainer<>("postgres:15-alpine") + .withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(new HostConfig().withPortBindings(portBinding))) + .withUsername(POSTGRES_USER) + .withPassword(POSTGRES_PASSWORD) + .withDatabaseName(POSTGRES_DB) + .withExposedPorts(POSTGRES_PORT); + } + + @Override + public void afterAll(ExtensionContext context) throws Exception { + container.stop(); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + container.start(); + } + @Override + public JdbcCredentials getJdbcCredentials() { + return new JdbcCredentials(getJdbcUrl(), getJdbcUser(), getJdbcPassword()); + } + + public String getJdbcUrl() { + return container.getJdbcUrl(); + } + + public String getJdbcUser() { + return container.getUsername(); + } + + public String getJdbcPassword() { + return container.getPassword(); + } +} diff --git a/e2e-test/src/test/resources/logging.properties b/e2e-test/src/test/resources/logging.properties new file mode 100644 index 000000000..d2212b2a2 --- /dev/null +++ b/e2e-test/src/test/resources/logging.properties @@ -0,0 +1,6 @@ +.level=ALL +org.eclipse.edc.level=ALL +handlers=java.util.logging.ConsoleHandler +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.ConsoleHandler.level=ALL +java.util.logging.SimpleFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS] [%4$-7s] %5$s%6$s%n \ No newline at end of file diff --git a/extensions/edc-ui-config/build.gradle.kts b/extensions/edc-ui-config/build.gradle.kts index 42430ad93..41a8fe40c 100644 --- a/extensions/edc-ui-config/build.gradle.kts +++ b/extensions/edc-ui-config/build.gradle.kts @@ -1,6 +1,7 @@ val edcVersion: String by project val edcGroup: String by project val restAssured: String by project +val mockitoVersion: String by project plugins { `java-library` @@ -20,6 +21,8 @@ dependencies { testImplementation("${edcGroup}:junit:${edcVersion}") testImplementation("${edcGroup}:http:${edcVersion}") testImplementation("io.rest-assured:rest-assured:${restAssured}") + testImplementation("${edcGroup}:data-plane-selector-core:${edcVersion}") + testImplementation("org.mockito:mockito-core:${mockitoVersion}") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") } diff --git a/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigAllSetTest.java b/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigAllSetTest.java index 32e38c8f0..171a0da69 100644 --- a/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigAllSetTest.java +++ b/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigAllSetTest.java @@ -14,8 +14,11 @@ package de.sovity.edc.extension.version.controller; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,6 +28,7 @@ import static de.sovity.edc.extension.version.controller.TestUtils.createConfiguration; import static de.sovity.edc.extension.version.controller.TestUtils.mockRequest; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -42,6 +46,11 @@ class EdcUiConfigAllSetTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); + extension.registerServiceMock( + DataPlaneInstanceStore.class, + mock(DataPlaneInstanceStore.class)); extension.setConfiguration(createConfiguration(Map.of( "edc.ids.endpoint", "http://my-edc/api/v1/ids", "edc.connector.name", CONNECTOR_NAME, diff --git a/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigNothingSetTest.java b/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigNothingSetTest.java index 3b6643d90..50d267fee 100644 --- a/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigNothingSetTest.java +++ b/extensions/edc-ui-config/src/test/java/de/sovity/edc/extension/version/controller/EdcUiConfigNothingSetTest.java @@ -14,8 +14,11 @@ package de.sovity.edc.extension.version.controller; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,6 +28,7 @@ import static de.sovity.edc.extension.version.controller.TestUtils.createConfiguration; import static de.sovity.edc.extension.version.controller.TestUtils.mockRequest; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -32,21 +36,34 @@ class EdcUiConfigNothingSetTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); + extension.registerServiceMock( + DataPlaneInstanceStore.class, + mock(DataPlaneInstanceStore.class)); extension.setConfiguration(createConfiguration(Map.of())); } @Test void testEdcUiConfigWithNothingSet() { mockRequest().assertThat() - .body("EDC_UI_CONNECTOR_ENDPOINT", equalTo("http://property.edc-ids-endpoint.not.set.in.edc.backend/ids/data")) - .body("EDC_UI_CONNECTOR_NAME", equalTo(missingMessage("EDC_UI_CONNECTOR_NAME", "edc.connector.name"))) + .body("EDC_UI_CONNECTOR_ENDPOINT", equalTo("http://property.edc-ids-endpoint.not" + + ".set.in.edc.backend/ids/data")) + .body("EDC_UI_CONNECTOR_NAME", equalTo(missingMessage("EDC_UI_CONNECTOR_NAME", + "edc.connector.name"))) .body("EDC_UI_IDS_ID", equalTo(missingMessage("EDC_UI_IDS_ID", "edc.ids.id"))) - .body("EDC_UI_IDS_TITLE", equalTo(missingMessage("EDC_UI_IDS_TITLE", "edc.ids.title"))) - .body("EDC_UI_IDS_DESCRIPTION", equalTo(missingMessage("EDC_UI_IDS_DESCRIPTION", "edc.ids.description"))) - .body("EDC_UI_CURATOR_URL", equalTo(missingMessage("EDC_UI_CURATOR_URL", "edc.ids.curator"))) - .body("EDC_UI_MAINTAINER_URL", equalTo(missingMessage("EDC_UI_MAINTAINER_URL", "edc.ids.maintainer"))) - .body("EDC_UI_DAPS_OAUTH_TOKEN_URL", equalTo(missingMessage("EDC_UI_DAPS_OAUTH_TOKEN_URL", "edc.oauth.token.url"))) - .body("EDC_UI_DAPS_OAUTH_JWKS_URL", equalTo(missingMessage("EDC_UI_DAPS_OAUTH_JWKS_URL", "edc.oauth.provider.jwks.url"))); + .body("EDC_UI_IDS_TITLE", equalTo(missingMessage("EDC_UI_IDS_TITLE", "edc.ids" + + ".title"))) + .body("EDC_UI_IDS_DESCRIPTION", equalTo(missingMessage("EDC_UI_IDS_DESCRIPTION", + "edc.ids.description"))) + .body("EDC_UI_CURATOR_URL", equalTo(missingMessage("EDC_UI_CURATOR_URL", "edc.ids" + + ".curator"))) + .body("EDC_UI_MAINTAINER_URL", equalTo(missingMessage("EDC_UI_MAINTAINER_URL", + "edc.ids.maintainer"))) + .body("EDC_UI_DAPS_OAUTH_TOKEN_URL", equalTo(missingMessage( + "EDC_UI_DAPS_OAUTH_TOKEN_URL", "edc.oauth.token.url"))) + .body("EDC_UI_DAPS_OAUTH_JWKS_URL", equalTo(missingMessage( + "EDC_UI_DAPS_OAUTH_JWKS_URL", "edc.oauth.provider.jwks.url"))); } private String missingMessage(String uiName, String backendName) { diff --git a/extensions/ids-broker-client/README.md b/extensions/ids-broker-client/README.md deleted file mode 100644 index 59dc15294..000000000 --- a/extensions/ids-broker-client/README.md +++ /dev/null @@ -1,87 +0,0 @@ - -
-
- - Logo - - -

EDC-Connector Extension:
Broker Client Extension

- -

- Report Bug - · - Request Feature -

-
- -## About this Extension - -This extension communicates changes in connector status and contract definitions to -an [IDS Broker](https://catalog.test.mobility-dataspace.eu/). - -It registers / unregisters each EDC Connector on startup / shutdown. It also communicates all contract definition to the -Broker on creation / deletion. It does not communicate contract definitions created with restrictive policies such as -connector restrictions. - -## Why does this extension exist? - -A centralized catalog has many advantages like: - -- Have a look at available data assets, offered in a data space, before joining the data space as a participant -- See what data are offered by other participants, instead of fetching data catalogs manually - -## Getting Started - -Our MDS Community Edition EDC is built with both the clearing house and broker extensions and is ready to -be used in the Mobility Data Space (MDS). - -## Sequence Diagram - -[broker-extension.puml](docs/broker-extension.puml) - -EDC IDS Broker Extension Sequence Diagram - -### Supported Asset Properties - -The Broker Extension supports the following additional meta information to be sent to the broker: - -- id: 'asset:prop:id' -- name: 'asset:prop:name' -- contentType: 'asset:prop:contenttype' -- description: 'asset:prop:description' -- version: 'asset:prop:version' -- keywords: 'asset:prop:keywords' -- language: 'asset:prop:language' -- publisher: 'asset:prop:publisher' -- standardLicense: 'asset:prop:standardLicense' -- endpointDocumentation: 'asset:prop:endpointDocumentation' - -MDS-specific properties: - -- dataCategory: 'http://w3id.org/mds#dataCategory' -- dataSubcategory: 'http://w3id.org/mds#dataSubcategory' -- dataModel: 'http://w3id.org/mds#dataModel' -- geoReferenceMethod: 'http://w3id.org/mds#geoReferenceMethod' -- transportMode: 'http://w3id.org/mds#transportMode' - -## Configuration - -The Broker URL can be configured with the ENV var: - -```dotenv -EDC_BROKER_BASE_URL=https://broker.test.mobility-dataspace.eu -``` - -To disable the extension (per default enabled) you can use following ENV var: - -```dotenv -BROKER_CLIENT_EXTENSION_ENABLED=false -``` - -## License - -Apache License 2.0 - see [LICENSE](../../LICENSE) - -## Contact - -sovity GmbH - contact@sovity.de diff --git a/extensions/ids-broker-client/build.gradle.kts b/extensions/ids-broker-client/build.gradle.kts deleted file mode 100644 index 7c7620c6d..000000000 --- a/extensions/ids-broker-client/build.gradle.kts +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - `java-library` -} - -val edcVersion: String by project -val edcGroup: String by project -val jupiterVersion: String by project -val mockitoVersion: String by project -val assertj: String by project -val okHttpVersion: String by project - -dependencies { - implementation("${edcGroup}:control-plane-core:${edcVersion}") - implementation("${edcGroup}:ids-spi:${edcVersion}") - implementation("${edcGroup}:ids-api-multipart-dispatcher-v1:${edcVersion}") - implementation("${edcGroup}:ids-api-configuration:${edcVersion}") - implementation("${edcGroup}:ids-jsonld-serdes:${edcVersion}") - - implementation("com.squareup.okhttp3:okhttp:${okHttpVersion}") - - testImplementation("org.assertj:assertj-core:${assertj}") - testImplementation("org.junit.jupiter:junit-jupiter-api:${jupiterVersion}") - testImplementation("org.mockito:mockito-core:${mockitoVersion}") - testImplementation("org.mockito:mockito-core:${mockitoVersion}") - testImplementation("org.junit.jupiter:junit-jupiter-params:${jupiterVersion}") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${jupiterVersion}") -} - -tasks.getByName("test") { - useJUnitPlatform() -} - -tasks.register("prepareKotlinBuildScriptModel"){} - -val sovityEdcExtensionGroup: String by project -group = sovityEdcExtensionGroup - -publishing { - publications { - create(project.name) { - from(components["java"]) - } - } -} diff --git a/extensions/ids-broker-client/docs/broker-extension.png b/extensions/ids-broker-client/docs/broker-extension.png deleted file mode 100644 index d8cfac19678fbb603531bb495f71cdb3439e1df4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37693 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 EDC: Start EDC - EDC -> Broker: ConnectorUpdateMessage - activate Broker - Broker -> EDC: MessageProcessedNotificationMessage - deactivate Broker -else register assets - group pre-required - Actor -> EDC: Publish Asset - Actor -> EDC: Publish Policy - end - Actor -> EDC: Publish ContractDefinition - EDC -> Broker: ResourceUpdateMessage - activate Broker - Broker -> EDC: MessageProcessedNotificationMessage - deactivate Broker -else de-register assets - Actor -> EDC: Delete ContractDefinition - EDC -> Broker: ResourceUnavailableMessage - activate Broker - Broker -> EDC: MessageProcessedNotificationMessage - deactivate Broker -else unregister connector - Actor -> EDC: Stop EDC - EDC -> Broker: ConnectorUnavailableMessage - activate Broker - Broker -> EDC: MessageProcessedNotificationMessage - deactivate Broker -end -@enduml \ No newline at end of file diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/BrokerExtension.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/BrokerExtension.java deleted file mode 100644 index 3f641760f..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/BrokerExtension.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker; - -import de.fraunhofer.iais.eis.Artifact; -import de.fraunhofer.iais.eis.BaseConnector; -import de.fraunhofer.iais.eis.ConnectorEndpoint; -import de.fraunhofer.iais.eis.ConnectorUnavailableMessage; -import de.fraunhofer.iais.eis.ConnectorUpdateMessage; -import de.fraunhofer.iais.eis.QueryMessage; -import de.fraunhofer.iais.eis.Resource; -import de.fraunhofer.iais.eis.ResourceCatalog; -import de.fraunhofer.iais.eis.ResourceUnavailableMessage; -import de.fraunhofer.iais.eis.ResourceUpdateMessage; -import de.sovity.extension.broker.sender.QueryMessageRequestSender; -import de.sovity.extension.broker.sender.RegisterConnectorRequestSender; -import de.sovity.extension.broker.sender.RegisterResourceRequestSender; -import de.sovity.extension.broker.sender.UnregisterConnectorRequestSender; -import de.sovity.extension.broker.sender.UnregisterResourceRequestSender; -import de.sovity.extension.broker.sender.message.brokerdispatcher.IdsMultipartExtendedRemoteMessageDispatcher; -import de.sovity.extension.broker.serializer.MultiContextJsonLdSerializer; -import de.sovity.extension.broker.service.IdsBrokerService; -import de.sovity.extension.broker.service.IdsBrokerServiceImpl; -import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; -import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.IdsMultipartSender; -import org.eclipse.edc.protocol.ids.jsonld.JsonLd; -import org.eclipse.edc.protocol.ids.service.ConnectorServiceSettings; -import org.eclipse.edc.protocol.ids.spi.service.DynamicAttributeTokenService; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.runtime.metamodel.annotation.Setting; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.asset.AssetIndex; -import org.eclipse.edc.spi.event.EventRouter; -import org.eclipse.edc.spi.http.EdcHttpClient; -import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.Hostname; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.spi.types.TypeManager; -import org.jetbrains.annotations.NotNull; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class BrokerExtension implements ServiceExtension { - - public static final String BROKER_EXTENSION = "BrokerExtension"; - private static final String TYPE_MANAGER_SERIALIZER_KEY = "ids-broker"; - - private static final Map CONTEXT_MAP = Map.of( - "cat", "http://w3id.org/mds/data-categories#", - "ids", "https://w3id.org/idsa/core/", - "idsc", "https://w3id.org/idsa/code/"); - @Setting - public static final String BROKER_BASE_URL_SETTING = "edc.broker.base.url"; - - @Setting - private static final String EDC_CATALOG_URL = "edc.catalog.url"; - - @Setting - private static final String EDC_CONNECTOR_NAME = "edc.connector.name"; - - @Setting - private static final String EDC_IDS_ENDPOINT = "edc.ids.endpoint"; - - @Setting - private static final String EDC_IDS_DESCRIPTION = "edc.ids.description"; - - @Setting - private static final String POLICY_BROKER_BLACKLIST = "policy.broker.blacklist"; - - @Setting - private static final String BROKER_CLIENT_EXTENSION_ENABLED = "broker.client.extension.enabled"; - - @Inject - private RemoteMessageDispatcherRegistry dispatcherRegistry; - - @Inject - private Hostname hostname; - - @Inject - private EdcHttpClient edcHttpClient; - - @Inject - private DynamicAttributeTokenService dynamicAttributeTokenService; - - @Inject - private AssetIndex assetIndex; - - @Inject - private ContractDefinitionStore contractDefinitionStore; - - @Inject - private PolicyDefinitionStore policyDefinitionStore; - - @Inject - private EventRouter eventRouter; - - private IdsBrokerService idsBrokerService; - - private URL brokerBaseUrl; - - private Monitor monitor; - - private boolean isExtensionEnabled = true; - - @Override - public String name() { - return BROKER_EXTENSION; - } - - @Override - public void initialize(ServiceExtensionContext context) { - monitor = context.getMonitor(); - var extensionEnabled = context.getSetting(BROKER_CLIENT_EXTENSION_ENABLED, true); - - if (!extensionEnabled) { - isExtensionEnabled = false; - monitor.info("Broker client extension is disabled."); - return; - } - - monitor.info("Broker client extension is enabled."); - - brokerBaseUrl = readUrlFromSettings(context, BROKER_BASE_URL_SETTING); - var policyBrokerBlacklist = getPolicyBrokerBlacklist(context); - - - registerSerializerBrokerMessages(context); - registerBrokerMessageSenders(context); - - initializeIdsBrokerService( - context, - dispatcherRegistry, - hostname); - - var connectorServiceSettings = new ConnectorServiceSettings(context, context.getMonitor()); - - var eventSubscriber = new IdsBrokerServiceImpl( - dispatcherRegistry, - connectorServiceSettings, - hostname, - contractDefinitionStore, - policyDefinitionStore, - brokerBaseUrl, - assetIndex, - policyBrokerBlacklist, - monitor); - eventRouter.registerSync(eventSubscriber); //asynchronous dispatch - registerSync for synchronous dispatch - context.registerService(IdsBrokerService.class, eventSubscriber); - } - - private void initializeIdsBrokerService( - ServiceExtensionContext context, - RemoteMessageDispatcherRegistry dispatcherRegistry, - Hostname hostname) { - var connectorServiceSettings = new ConnectorServiceSettings(context, context.getMonitor()); - var policyBrokerBlacklist = getPolicyBrokerBlacklist(context); - idsBrokerService = new IdsBrokerServiceImpl( - dispatcherRegistry, - connectorServiceSettings, - hostname, - contractDefinitionStore, - policyDefinitionStore, - brokerBaseUrl, - assetIndex, - policyBrokerBlacklist, - monitor); - } - - @NotNull - private ArrayList getPolicyBrokerBlacklist(ServiceExtensionContext context) { - return new ArrayList<>(List.of(context.getSetting(POLICY_BROKER_BLACKLIST, "").split(","))); - } - - private URL readUrlFromSettings(ServiceExtensionContext context, String settingsPath) { - try { - var urlString = context.getSetting(settingsPath, null); - if (urlString == null && !EDC_CATALOG_URL.equals(settingsPath)) { - throw new EdcException(String.format("Could not initialize " + - "CatalogTransferExtension: " + - "No url specified using setting %s", settingsPath)); - } else if (urlString == null) { - return null; - } - - return new URL(urlString); - } catch (MalformedURLException e) { - throw new EdcException(String.format("Could not parse setting %s to Url", - settingsPath), e); - } - } - - private void registerSerializerBrokerMessages(ServiceExtensionContext context) { - var typeManager = context.getTypeManager(); - typeManager.registerContext(TYPE_MANAGER_SERIALIZER_KEY, JsonLd.getObjectMapper()); - registerCommonTypes(typeManager); - registerConnectorMessages(typeManager); - registerResourceMessages(typeManager); - registerQueryMessage(typeManager); - } - - private void registerQueryMessage(TypeManager typeManager) { - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, QueryMessage.class, - new MultiContextJsonLdSerializer<>(QueryMessage.class, CONTEXT_MAP)); - } - - private void registerCommonTypes(TypeManager typeManager) { - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, ResourceUpdateMessage.class, - new MultiContextJsonLdSerializer<>(ResourceUpdateMessage.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, Artifact.class, - new MultiContextJsonLdSerializer<>(Artifact.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, ResourceCatalog.class, - new MultiContextJsonLdSerializer<>(ResourceCatalog.class, CONTEXT_MAP)); - } - - private void registerResourceMessages(TypeManager typeManager) { - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, ResourceUpdateMessage.class, - new MultiContextJsonLdSerializer<>(ResourceUpdateMessage.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, - ResourceUnavailableMessage.class, - new MultiContextJsonLdSerializer<>(ResourceUnavailableMessage.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, Resource.class, - new MultiContextJsonLdSerializer<>(Resource.class, CONTEXT_MAP)); - } - - private void registerConnectorMessages(TypeManager typeManager) { - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, ConnectorUpdateMessage.class, - new MultiContextJsonLdSerializer<>(ConnectorUpdateMessage.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, BaseConnector.class, - new MultiContextJsonLdSerializer<>(BaseConnector.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, ConnectorEndpoint.class, - new MultiContextJsonLdSerializer<>(ConnectorEndpoint.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, - ConnectorUnavailableMessage.class, - new MultiContextJsonLdSerializer<>(ConnectorUnavailableMessage.class, CONTEXT_MAP)); - } - - private void registerBrokerMessageSenders(ServiceExtensionContext context) { - var httpClient = context.getService(EdcHttpClient.class); - var monitor = context.getMonitor(); - var typeManager = context.getTypeManager(); - var objectMapper = typeManager.getMapper(TYPE_MANAGER_SERIALIZER_KEY); - var connectorName = context.getSetting(EDC_CONNECTOR_NAME, "EDC"); - var endpoint = context.getSetting(EDC_IDS_ENDPOINT, "http://endpoint"); - var description = context.getSetting(EDC_IDS_DESCRIPTION, ""); - - var registerConnectorSender = new RegisterConnectorRequestSender(objectMapper, connectorName, endpoint, description); - var registerResourceSender = new RegisterResourceRequestSender(objectMapper); - var unregisterConnectorSender = new UnregisterConnectorRequestSender(); - var unregisterResourceSender = new UnregisterResourceRequestSender(); - var queryMessageRequestSender = new QueryMessageRequestSender(); - - var idsMultipartSender = new IdsMultipartSender(monitor, httpClient, dynamicAttributeTokenService, objectMapper); - var dispatcher = new IdsMultipartExtendedRemoteMessageDispatcher(idsMultipartSender); - dispatcher.register(registerConnectorSender); - dispatcher.register(registerResourceSender); - dispatcher.register(unregisterResourceSender); - dispatcher.register(queryMessageRequestSender); - dispatcher.register(unregisterConnectorSender); - dispatcherRegistry.register(dispatcher); - } - - @Override - public void start() { - if (!isExtensionEnabled) { - return; - } - - try { - idsBrokerService.registerConnectorAtBroker(brokerBaseUrl); - } catch (Exception e) { - monitor.severe(String.format("%s failed during startup: ", BROKER_EXTENSION), e); - } - } - - @Override - public void shutdown() { - if (!isExtensionEnabled) { - return; - } - - idsBrokerService.unregisterConnectorAtBroker(brokerBaseUrl); - } - - @Override - public void prepare() { - ServiceExtension.super.prepare(); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/QueryMessageRequestSender.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/QueryMessageRequestSender.java deleted file mode 100644 index b1f8dd340..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/QueryMessageRequestSender.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender; - -import de.fraunhofer.iais.eis.DynamicAttributeToken; -import de.fraunhofer.iais.eis.Message; -import de.fraunhofer.iais.eis.QueryLanguage; -import de.fraunhofer.iais.eis.QueryMessageBuilder; -import de.fraunhofer.iais.eis.QueryScope; -import de.fraunhofer.iais.eis.QueryTarget; -import de.fraunhofer.iais.eis.ResultMessageImpl; -import de.sovity.extension.broker.sender.message.QueryMessage; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.MultipartSenderDelegate; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.IdsMultipartParts; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.MultipartResponse; -import org.eclipse.edc.protocol.ids.spi.domain.IdsConstants; -import org.eclipse.edc.protocol.ids.util.CalendarUtil; - -import java.util.List; - -import static org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.util.ResponseUtil.parseMultipartStringResponse; -import static org.eclipse.edc.protocol.ids.jsonld.JsonLd.getObjectMapper; - -public class QueryMessageRequestSender implements MultipartSenderDelegate { - - private static final String SPARQL_QUERY = """ - PREFIX ids: - PREFIX rdfs: - PREFIX xsd: - PREFIX owl: - SELECT DISTINCT ?resultUri { - GRAPH ?g { - { - ?internalUri a ids:BaseConnector . - # binds are directly to cover "x a A, B ." cases. - BIND(ids:BaseConnector AS ?type) - BIND(?internalUri AS ?connector) - } - UNION - { - ?internalUri a ids:TrustedConnector . - BIND(ids:TrustedConnector AS ?type) - BIND(?internalUri AS ?connector) - } - UNION - { - ?internalUri a ids:Resource . - BIND(ids:Resource AS ?type) - # From Resource backwards to Connector - ?catalog ids:offeredResource ?internalUri . - ?connector ids:resourceCatalog ?catalog . - } - UNION - { - ?internalUri a ids:Representation . - BIND(ids:Representation AS ?type) - - # From Representation backwards to Connector - ?resource ids:representation ?internalUri . - ?catalog ids:offeredResource ?resource . - ?connector ids:resourceCatalog ?catalog . - } - UNION - { - ?internalUri a ids:Artifact . - - # From Artifact backwards to Connector - ?representation ids:instance ?internalUri . - ?resource ids:representation ?representation . - ?catalog ids:offeredResource ?resource . - ?connector ids:resourceCatalog ?catalog . - } - - ?internalUri ?predicate ?text . - FILTER ( isLiteral(?text)) . - - FILTER( REGEX(?text, "${fullTextQueryString}", "i") || REGEX(str(?uri), "${fullTextQueryString}", "i") ) - - # Get the Access Endpoint - ?connector ids:hasDefaultEndpoint ?endpoint . - ?endpoint ids:accessURL ?accessUrl . - - { - # if a renaming happened, show the original URI. - ?internalUri owl:sameAs ?uri . - } UNION { - # maybe this call is expensive. - FILTER(NOT EXISTS { ?internalUri owl:sameAs ?uri } ) - BIND(?internalUri AS ?uri) - } - - BIND(?uri AS ?resultUri) # keep it non-breaking - BIND(?text AS ?res) # keep it non-breaking - } - } - """; // LIMIT 50 OFFSET 0 - private static final String SPARQL_QUERY_FULL_TEXT_TEMPLATE = "${fullTextQueryString}"; - - @Override - public Message buildMessageHeader(QueryMessage queryMessage, - DynamicAttributeToken token) throws Exception { - - return new QueryMessageBuilder() - ._modelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._issued_(CalendarUtil.gregorianNow()) - ._securityToken_(token) - ._issuerConnector_(queryMessage.connectorBaseUrl()) - ._senderAgent_(queryMessage.connectorBaseUrl()) - ._queryLanguage_(QueryLanguage.SPARQL) - ._queryScope_(QueryScope.ALL) - ._recipientScope_(QueryTarget.BROKER) - .build(); - } - - @Override - public String buildMessagePayload(QueryMessage queryMessage) throws Exception { - return SPARQL_QUERY.replace(SPARQL_QUERY_FULL_TEXT_TEMPLATE, queryMessage.fullTextQueryString()); - } - - @Override - public MultipartResponse getResponseContent(IdsMultipartParts parts) throws Exception { - return parseMultipartStringResponse(parts, getObjectMapper()); - } - - @Override - public List> getAllowedResponseTypes() { - return List.of(ResultMessageImpl.class); - } - - @Override - public Class getMessageType() { - return QueryMessage.class; - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterConnectorRequestSender.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterConnectorRequestSender.java deleted file mode 100644 index 30469706e..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterConnectorRequestSender.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.fraunhofer.iais.eis.BaseConnectorBuilder; -import de.fraunhofer.iais.eis.ConnectorEndpointBuilder; -import de.fraunhofer.iais.eis.ConnectorUpdateMessageBuilder; -import de.fraunhofer.iais.eis.DynamicAttributeToken; -import de.fraunhofer.iais.eis.Message; -import de.fraunhofer.iais.eis.MessageProcessedNotificationMessageImpl; -import de.fraunhofer.iais.eis.ResourceCatalogBuilder; -import de.fraunhofer.iais.eis.SecurityProfile; -import de.fraunhofer.iais.eis.util.TypedLiteral; -import de.sovity.extension.broker.sender.message.RegisterConnectorMessage; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.MultipartSenderDelegate; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.IdsMultipartParts; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.MultipartResponse; -import org.eclipse.edc.protocol.ids.spi.domain.IdsConstants; -import org.eclipse.edc.protocol.ids.util.CalendarUtil; - -import java.net.URI; -import java.util.List; - -import static org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.util.ResponseUtil.parseMultipartStringResponse; -import static org.eclipse.edc.protocol.ids.jsonld.JsonLd.getObjectMapper; - -public class RegisterConnectorRequestSender implements MultipartSenderDelegate { - - public static final String DATA_ENDPOINT = "/data"; - private ObjectMapper objectMapper; - private String connectorName; - private String endpoint; - private String connectorDescription; - - public RegisterConnectorRequestSender(ObjectMapper objectMapper, - String connectorName, - String endpoint, - String connectorDescription) { - this.objectMapper = objectMapper; - this.connectorName = connectorName; - this.endpoint = endpoint; - this.connectorDescription = connectorDescription; - } - - @Override - public Message buildMessageHeader(RegisterConnectorMessage registerConnectorMessage, - DynamicAttributeToken token) throws Exception { - return new ConnectorUpdateMessageBuilder() - ._modelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._issued_(CalendarUtil.gregorianNow()) - ._securityToken_(token) - ._issuerConnector_(registerConnectorMessage.connectorBaseUrl()) - ._senderAgent_(registerConnectorMessage.connectorBaseUrl()) - ._affectedConnector_(registerConnectorMessage.connectorBaseUrl()) - .build(); - } - - @Override - public String buildMessagePayload(RegisterConnectorMessage registerConnectorMessage) throws Exception { - var accessUrl = String.format("%s%s", endpoint, DATA_ENDPOINT); - var connectorEndpoint = new ConnectorEndpointBuilder(new URI("http://endpointid")) - ._accessURL_(new URI(accessUrl)) - .build(); - var resourceCatalog = new ResourceCatalogBuilder() - .build(); - var baseConnector = new BaseConnectorBuilder(registerConnectorMessage.connectorBaseUrl()) - ._title_(new TypedLiteral(connectorName)) - ._curator_(registerConnectorMessage.curator()) - ._hasDefaultEndpoint_(connectorEndpoint) - ._description_(new TypedLiteral(connectorDescription, "en")) - ._resourceCatalog_(resourceCatalog) // has to be set, otherwise broker will crash - ._maintainer_(registerConnectorMessage.maintainer()) - ._outboundModelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._securityProfile_(SecurityProfile.BASE_SECURITY_PROFILE) - .build(); - return objectMapper.writeValueAsString(baseConnector); - } - - @Override - public MultipartResponse getResponseContent(IdsMultipartParts parts) throws Exception { - return parseMultipartStringResponse(parts, getObjectMapper()); - } - - @Override - public List> getAllowedResponseTypes() { - return List.of(MessageProcessedNotificationMessageImpl.class); - } - - @Override - public Class getMessageType() { - return RegisterConnectorMessage.class; - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterResourceRequestSender.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterResourceRequestSender.java deleted file mode 100644 index 26d510f5f..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/RegisterResourceRequestSender.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import de.fraunhofer.iais.eis.ConnectorEndpointBuilder; -import de.fraunhofer.iais.eis.DynamicAttributeToken; -import de.fraunhofer.iais.eis.IANAMediaTypeBuilder; -import de.fraunhofer.iais.eis.Language; -import de.fraunhofer.iais.eis.Message; -import de.fraunhofer.iais.eis.MessageProcessedNotificationMessageImpl; -import de.fraunhofer.iais.eis.RepresentationBuilder; -import de.fraunhofer.iais.eis.ResourceBuilder; -import de.fraunhofer.iais.eis.ResourceUpdateMessageBuilder; -import de.fraunhofer.iais.eis.util.TypedLiteral; -import de.sovity.extension.broker.sender.message.RegisterResourceMessage; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.MultipartSenderDelegate; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.IdsMultipartParts; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.MultipartResponse; -import org.eclipse.edc.protocol.ids.spi.domain.IdsConstants; -import org.eclipse.edc.protocol.ids.util.CalendarUtil; -import org.eclipse.edc.util.string.StringUtils; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.util.ResponseUtil.parseMultipartStringResponse; -import static org.eclipse.edc.protocol.ids.jsonld.JsonLd.getObjectMapper; - -public class RegisterResourceRequestSender implements MultipartSenderDelegate { - public static final String MDS_GEO_REFERENCE_METHOD = "http://w3id.org/mds#geoReferenceMethod"; - public static final String MDS_DATA_MODEL = "http://w3id.org/mds#dataModel"; - public static final String MDS_DATA_SUBCATEGORY = "http://w3id.org/mds#dataSubcategory"; - public static final String MDS_DATA_CATEGORY = "http://w3id.org/mds#dataCategory"; - public static final String MDS_TRANSPORT_MODE = "http://w3id.org/mds#transportMode"; - private ObjectMapper objectMapper; - - public RegisterResourceRequestSender(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - @Override - public Message buildMessageHeader(RegisterResourceMessage registerResourceMessage, - DynamicAttributeToken token) throws Exception { - return new ResourceUpdateMessageBuilder(registerResourceMessage.affectedResourceUri()) - ._modelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._issued_(CalendarUtil.gregorianNow()) - ._securityToken_(token) - ._issuerConnector_(registerResourceMessage.connectorBaseUrl()) - ._senderAgent_(registerResourceMessage.connectorBaseUrl()) - ._affectedResource_(registerResourceMessage.affectedResourceUri()) - .build(); - } - - @Override - public String buildMessagePayload(RegisterResourceMessage registerResourceMessage) throws Exception { - var assetTitle = getAssetTitle(registerResourceMessage); - var assetDescription = getAssetDescription(registerResourceMessage); - var language = Arrays.stream(Language.values()) - .filter(l -> l.getId().toString().equals(getAssetLanguage(registerResourceMessage))) - .findFirst() - .orElse(Language.EN); - var version = getAssetVersion(registerResourceMessage); - var keywords = getAssetKeywords(registerResourceMessage) - .stream() - .map(k -> new TypedLiteral(k, language.name())) - .toList(); - var mediaType = getAssetMediaType(registerResourceMessage); - var publisher = getAssetPublisher(registerResourceMessage); - var standardLicense = getAssetStandardLicense(registerResourceMessage); - var endpointDocumentation = getAssetEndpointDocumentation(registerResourceMessage); - var transportMode = getAssetTransportMode(registerResourceMessage); - var dataCategory = getAssetDataCategory(registerResourceMessage); - var dataSubcategory = getAssetDataSubcategory(registerResourceMessage); - var dataModel = getAssetDataModel(registerResourceMessage); - var geoReferenceMethod = getAssetGeoReferenceMethod(registerResourceMessage); - - var resource = new ResourceBuilder(registerResourceMessage.affectedResourceUri()) - ._title_(new TypedLiteral(assetTitle, language.name())) - ._description_(new TypedLiteral(assetDescription, language.name())) - ._language_(language) - ._version_(version) - ._keyword_(keywords) - ._publisher_(URI.create(publisher)) - ._standardLicense_(URI.create(standardLicense)) - ._representation_(new RepresentationBuilder() - ._language_(language) - ._mediaType_(new IANAMediaTypeBuilder()._filenameExtension_(mediaType).build()) - .build()) - ._resourceEndpoint_(List.of(new ConnectorEndpointBuilder() - ._endpointDocumentation_(URI.create(endpointDocumentation)) - ._accessURL_(registerResourceMessage.affectedResourceUri()) - .build())) - .build(); - - var json = (ObjectNode) objectMapper.readTree(objectMapper.writeValueAsString(resource)); - setTransportMode(json, transportMode); - setDataCategory(json, dataCategory); - setDataSubcategory(json, dataSubcategory); - setDataModel(json, dataModel); - setGeoReferenceMethod(json, geoReferenceMethod); - return objectMapper.writeValueAsString(json); - } - - private void setGeoReferenceMethod(ObjectNode json, String geoReferenceMethod) { - if (!StringUtils.isNullOrBlank(geoReferenceMethod)) { - json.set(MDS_GEO_REFERENCE_METHOD, buildStringProperty(geoReferenceMethod)); - } - } - - private void setDataModel(ObjectNode json, String dataModel) { - if (!StringUtils.isNullOrBlank(dataModel)) { - json.set(MDS_DATA_MODEL, buildStringProperty(dataModel)); - } - } - - private void setDataSubcategory(ObjectNode json, String dataSubcategory) { - if (!StringUtils.isNullOrBlank(dataSubcategory)) { - json.set(MDS_DATA_SUBCATEGORY, buildStringProperty(dataSubcategory)); - } - } - - private void setDataCategory(ObjectNode json, String dataCategory) { - if (!StringUtils.isNullOrBlank(dataCategory)) { - json.set(MDS_DATA_CATEGORY, buildStringProperty(dataCategory)); - } - } - - private void setTransportMode(ObjectNode json, String transportMode) { - if (!StringUtils.isNullOrBlank(transportMode)) { - json.set(MDS_TRANSPORT_MODE, buildStringProperty(transportMode)); - } - } - - private ObjectNode buildStringProperty(String property) { - var json = objectMapper.createObjectNode(); - json.put("@value", property); - json.put("@type", "http://www.w3.org/2001/XMLSchema#string"); - return json; - } - - private String getAssetGeoReferenceMethod(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, MDS_GEO_REFERENCE_METHOD); - } - - private String getAssetDataModel(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, MDS_DATA_MODEL); - } - - private String getAssetDataSubcategory(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, MDS_DATA_SUBCATEGORY); - } - - private String getAssetDataCategory(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, MDS_DATA_CATEGORY); - } - - private String getAssetTransportMode(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, MDS_TRANSPORT_MODE); - } - - private String getAssetEndpointDocumentation(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:endpointDocumentation"); - } - - private String getAssetStandardLicense(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:standardLicense"); - } - - private String getAssetPublisher(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:publisher"); - } - - private String getAssetLanguage(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:language"); - } - - private static List getAssetKeywords(RegisterResourceMessage registerResourceMessage) { - var keywords = getAssetProperty(registerResourceMessage, "asset:prop:keywords"); - return new ArrayList<>(Arrays.asList(keywords.split(","))); - } - - private static String getAssetMediaType(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:contenttype"); - } - - private static String getAssetDescription(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:description"); - } - - private static String getAssetTitle(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:name"); - } - - private static String getAssetVersion(RegisterResourceMessage registerResourceMessage) { - return getAssetProperty(registerResourceMessage, "asset:prop:version"); - } - - private static String getAssetProperty(RegisterResourceMessage registerResourceMessage, String property) { - var result = ""; - if (checkPropertyExists(registerResourceMessage, property)) { - result = registerResourceMessage.asset().getProperties().get(property).toString(); - } - return result; - } - - private static boolean checkPropertyExists(RegisterResourceMessage registerResourceMessage, String property) { - return registerResourceMessage.asset().getProperties().get(property) != null; - } - - @Override - public MultipartResponse getResponseContent(IdsMultipartParts parts) throws Exception { - return parseMultipartStringResponse(parts, getObjectMapper()); - } - - @Override - public List> getAllowedResponseTypes() { - return List.of(MessageProcessedNotificationMessageImpl.class); - } - - @Override - public Class getMessageType() { - return RegisterResourceMessage.class; - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterConnectorRequestSender.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterConnectorRequestSender.java deleted file mode 100644 index 60af73ecb..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterConnectorRequestSender.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender; - -import de.fraunhofer.iais.eis.ConnectorUnavailableMessageBuilder; -import de.fraunhofer.iais.eis.DynamicAttributeToken; -import de.fraunhofer.iais.eis.Message; -import de.fraunhofer.iais.eis.MessageProcessedNotificationMessageImpl; -import de.sovity.extension.broker.sender.message.UnregisterConnectorMessage; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.MultipartSenderDelegate; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.IdsMultipartParts; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.MultipartResponse; -import org.eclipse.edc.protocol.ids.spi.domain.IdsConstants; -import org.eclipse.edc.protocol.ids.util.CalendarUtil; - -import java.util.List; - -import static org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.util.ResponseUtil.parseMultipartStringResponse; -import static org.eclipse.edc.protocol.ids.jsonld.JsonLd.getObjectMapper; - -public class UnregisterConnectorRequestSender implements MultipartSenderDelegate { - - @Override - public Message buildMessageHeader(UnregisterConnectorMessage unregisterConnectorMessage, - DynamicAttributeToken token) throws Exception { - return new ConnectorUnavailableMessageBuilder() - ._modelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._issued_(CalendarUtil.gregorianNow()) - ._securityToken_(token) - ._issuerConnector_(unregisterConnectorMessage.connectorBaseUrl()) - ._senderAgent_(unregisterConnectorMessage.connectorBaseUrl()) - ._affectedConnector_(unregisterConnectorMessage.connectorBaseUrl()) - .build(); - } - - @Override - public String buildMessagePayload(UnregisterConnectorMessage request) throws Exception { - return null; - } - - @Override - public MultipartResponse getResponseContent(IdsMultipartParts parts) throws Exception { - return parseMultipartStringResponse(parts, getObjectMapper()); - } - - @Override - public List> getAllowedResponseTypes() { - return List.of(MessageProcessedNotificationMessageImpl.class); - } - - @Override - public Class getMessageType() { - return UnregisterConnectorMessage.class; - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterResourceRequestSender.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterResourceRequestSender.java deleted file mode 100644 index fae31cc2a..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/UnregisterResourceRequestSender.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender; - -import de.fraunhofer.iais.eis.DynamicAttributeToken; -import de.fraunhofer.iais.eis.Message; -import de.fraunhofer.iais.eis.MessageProcessedNotificationMessageImpl; -import de.fraunhofer.iais.eis.ResourceUnavailableMessageBuilder; -import de.sovity.extension.broker.sender.message.UnregisterResourceMessage; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.MultipartSenderDelegate; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.IdsMultipartParts; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.MultipartResponse; -import org.eclipse.edc.protocol.ids.spi.domain.IdsConstants; -import org.eclipse.edc.protocol.ids.util.CalendarUtil; - -import java.util.List; - -import static org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.util.ResponseUtil.parseMultipartStringResponse; -import static org.eclipse.edc.protocol.ids.jsonld.JsonLd.getObjectMapper; - -public class UnregisterResourceRequestSender implements MultipartSenderDelegate { - - public UnregisterResourceRequestSender() { - } - - @Override - public Message buildMessageHeader(UnregisterResourceMessage unregisterResourceMessage, - DynamicAttributeToken token) throws Exception { - return new ResourceUnavailableMessageBuilder() - ._modelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._issued_(CalendarUtil.gregorianNow()) - ._securityToken_(token) - ._issuerConnector_(unregisterResourceMessage.connectorBaseUrl()) - ._senderAgent_(unregisterResourceMessage.connectorBaseUrl()) - ._affectedResource_(unregisterResourceMessage.affectedResourceUri()) - .build(); - } - - @Override - public String buildMessagePayload(UnregisterResourceMessage unregisterResourceMessage) throws Exception { - return null; - } - - @Override - public MultipartResponse getResponseContent(IdsMultipartParts parts) throws Exception { - return parseMultipartStringResponse(parts, getObjectMapper()); - } - - @Override - public List> getAllowedResponseTypes() { - return List.of(MessageProcessedNotificationMessageImpl.class); - } - - @Override - public Class getMessageType() { - return UnregisterResourceMessage.class; - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/QueryMessage.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/QueryMessage.java deleted file mode 100644 index 5d974788b..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/QueryMessage.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message; - -import de.sovity.extension.broker.sender.message.brokerdispatcher.ExtendedMessageProtocol; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; - -import java.net.URI; -import java.net.URL; - -public record QueryMessage( - URL brokerUrl, - URI connectorBaseUrl, - String fullTextQueryString) implements RemoteMessage { - - @Override - public String getProtocol() { - return ExtendedMessageProtocol.IDS_EXTENDED_PROTOCOL; - } - - @Override - public String getConnectorAddress() { - return brokerUrl.toString(); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterConnectorMessage.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterConnectorMessage.java deleted file mode 100644 index 4efb61f45..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterConnectorMessage.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message; - -import de.sovity.extension.broker.sender.message.brokerdispatcher.ExtendedMessageProtocol; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; - -import java.net.URI; -import java.net.URL; - -public record RegisterConnectorMessage(URL brokerUrl, - // Broker seems only to accept connector ID's starting - // with http or https - URI connectorBaseUrl, - URI curator, - URI maintainer) implements RemoteMessage { - - @Override - public String getProtocol() { - return ExtendedMessageProtocol.IDS_EXTENDED_PROTOCOL; - } - - @Override - public String getConnectorAddress() { - return brokerUrl.toString(); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterResourceMessage.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterResourceMessage.java deleted file mode 100644 index a0b1db015..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/RegisterResourceMessage.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message; - -import de.sovity.extension.broker.sender.message.brokerdispatcher.ExtendedMessageProtocol; -import org.eclipse.edc.spi.types.domain.asset.Asset; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; - -import java.net.URI; -import java.net.URL; - -public record RegisterResourceMessage(URL brokerUrl, - // Broker seems only to accept connector ID's starting - // with http or https - URI connectorBaseUrl, - URI affectedResourceUri, - Asset asset) implements RemoteMessage { - - @Override - public String getProtocol() { - return ExtendedMessageProtocol.IDS_EXTENDED_PROTOCOL; - } - - @Override - public String getConnectorAddress() { - return brokerUrl.toString(); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterConnectorMessage.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterConnectorMessage.java deleted file mode 100644 index 49238229a..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterConnectorMessage.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message; - -import de.sovity.extension.broker.sender.message.brokerdispatcher.ExtendedMessageProtocol; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; - -import java.net.URI; -import java.net.URL; - -public record UnregisterConnectorMessage(URL brokerUrl, - // Broker seems only to accept connector ID's starting - // with http or https - URI connectorBaseUrl) implements RemoteMessage { - - @Override - public String getProtocol() { - return ExtendedMessageProtocol.IDS_EXTENDED_PROTOCOL; - } - - @Override - public String getConnectorAddress() { - return brokerUrl.toString(); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterResourceMessage.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterResourceMessage.java deleted file mode 100644 index 3fb75210d..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/UnregisterResourceMessage.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message; - -import de.sovity.extension.broker.sender.message.brokerdispatcher.ExtendedMessageProtocol; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; - -import java.net.URI; -import java.net.URL; - -public record UnregisterResourceMessage(URL brokerUrl, - // Broker seems only to accept connector ID's starting - // with http or https - URI connectorBaseUrl, - URI affectedResourceUri) implements RemoteMessage { - - @Override - public String getProtocol() { - return ExtendedMessageProtocol.IDS_EXTENDED_PROTOCOL; - } - - @Override - public String getConnectorAddress() { - return brokerUrl.toString(); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/ExtendedMessageProtocol.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/ExtendedMessageProtocol.java deleted file mode 100644 index a4315c1c2..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/ExtendedMessageProtocol.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message.brokerdispatcher; - -import org.eclipse.edc.protocol.ids.spi.types.MessageProtocol; - -public final class ExtendedMessageProtocol { - - private static final String EXTENDED_SUFFIX = "-extended"; - public static final String IDS_EXTENDED_PROTOCOL = String.format("%s%s", MessageProtocol.IDS_MULTIPART, EXTENDED_SUFFIX); - - private ExtendedMessageProtocol() { - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/IdsMultipartExtendedRemoteMessageDispatcher.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/IdsMultipartExtendedRemoteMessageDispatcher.java deleted file mode 100644 index 8ef456324..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/sender/message/brokerdispatcher/IdsMultipartExtendedRemoteMessageDispatcher.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.sender.message.brokerdispatcher; - -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.IdsMultipartRemoteMessageDispatcher; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.IdsMultipartSender; - -public class IdsMultipartExtendedRemoteMessageDispatcher extends IdsMultipartRemoteMessageDispatcher { - - public IdsMultipartExtendedRemoteMessageDispatcher(IdsMultipartSender idsMultipartSender) { - super(idsMultipartSender); - } - - @Override - public String protocol() { - return ExtendedMessageProtocol.IDS_EXTENDED_PROTOCOL; - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/serializer/MultiContextJsonLdSerializer.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/serializer/MultiContextJsonLdSerializer.java deleted file mode 100644 index 8a2508107..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/serializer/MultiContextJsonLdSerializer.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2022 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 - * sovity GmbH - Adaption and changes - * - */ - -package de.sovity.extension.broker.serializer; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; - -import java.io.IOException; -import java.net.URI; -import java.util.Map; - -/** - * Custom Jackson serializer for any {@link Object}. Adds type and context information to result object. - * - * @param The object that should be serialized. - */ -public class MultiContextJsonLdSerializer extends JsonSerializer { - private final Class type; - private final Object contextInformation; - - private static final ThreadLocal CURRENT_RECURSION_DEPTH = ThreadLocal.withInitial(() -> 0); - - public MultiContextJsonLdSerializer(Class type, Object contextInformation) { - this.type = type; - this.contextInformation = contextInformation; - } - - @Override - public void serialize(T value, JsonGenerator generator, SerializerProvider provider) throws IOException { - CURRENT_RECURSION_DEPTH.set(CURRENT_RECURSION_DEPTH.get() + 1); - - Map propertiesMap = null; - try { - var field = value.getClass().getDeclaredField("properties"); - field.setAccessible(true); - propertiesMap = (Map) field.get(value); - } catch (NoSuchFieldException | IllegalAccessException ignore) { - // empty - } - removeProperty(value, "properties"); - - // remove properties "comment" and "label" - removeProperty(value, "comment"); - removeProperty(value, "label"); - - generator.writeStartObject(); - - // write new object - var serializer = instantiateSerializerFromProvider(provider, type); - serializer.unwrappingSerializer(null).serialize(value, generator, provider); - - if (CURRENT_RECURSION_DEPTH.get() == 1) { - // context needed only once (for parent object) - generator.writeObjectField("@context", contextInformation); - } - - // add type property - var type = getTypeName(value.getClass()); - if (type != null) { - generator.writeObjectField("@type", type); - } - - // add custom properties as root properties (not in a separate "properties" map) - if (propertiesMap != null) { - for (var key : propertiesMap.keySet()) { - var val = propertiesMap.get(key); - if (val instanceof URI) { - generator.writeStringField(key, val.toString()); - } else { - generator.writeObjectField(key, val); - } - } - } - - generator.writeEndObject(); - - CURRENT_RECURSION_DEPTH.set(CURRENT_RECURSION_DEPTH.get() - 1); - } - - @Override - public void serializeWithType(T value, JsonGenerator gen, SerializerProvider provider, TypeSerializer ser) throws IOException { - serialize(value, gen, provider); - } - - private void removeProperty(Object value, String name) { - try { - var field = value.getClass().getDeclaredField(name); - field.setAccessible(true); - field.set(value, null); - } catch (NoSuchFieldException | IllegalAccessException ignore) { - // empty - } - } - - private String getTypeName(Class clazz) { - var typeName = clazz.getAnnotation(JsonTypeName.class); - if (typeName != null) { - var value = typeName.value(); - if (value == null) { - getTypeName(clazz.getSuperclass()); - } - return value; - } - return null; - } - - private JsonSerializer instantiateSerializerFromProvider(SerializerProvider provider, Class type) throws JsonMappingException { - var javaType = provider.constructType(type); - var beanDescription = provider.getConfig().introspect(javaType); - var staticTyping = provider.isEnabled(MapperFeature.USE_STATIC_TYPING); - return BeanSerializerFactory.instance.findBeanOrAddOnSerializer(provider, javaType, beanDescription, staticTyping); - } -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerService.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerService.java deleted file mode 100644 index 1b187e871..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerService.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.service; - -import org.eclipse.edc.spi.types.domain.asset.Asset; - -import java.net.URL; -import java.util.List; - -public interface IdsBrokerService { - - void registerConnectorAtBroker(URL brokerBaseUrl); - - void unregisterConnectorAtBroker(URL brokerBaseUrl); - - void registerResourceAtBroker(URL brokerBaseUrl, String resourceId, Asset asset); - - void unregisterResourceAtBroker(URL brokerBaseUrl, String resourceId); - - List findResourceIdsByQuery(URL brokerBaseUrl, String fullTextQueryString); - -} diff --git a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerServiceImpl.java b/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerServiceImpl.java deleted file mode 100644 index 196b7f733..000000000 --- a/extensions/ids-broker-client/src/main/java/de/sovity/extension/broker/service/IdsBrokerServiceImpl.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.broker.service; - -import de.sovity.extension.broker.sender.message.QueryMessage; -import de.sovity.extension.broker.sender.message.RegisterConnectorMessage; -import de.sovity.extension.broker.sender.message.RegisterResourceMessage; -import de.sovity.extension.broker.sender.message.UnregisterConnectorMessage; -import de.sovity.extension.broker.sender.message.UnregisterResourceMessage; -import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; -import org.eclipse.edc.connector.policy.spi.PolicyDefinition; -import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; -import org.eclipse.edc.policy.model.AtomicConstraint; -import org.eclipse.edc.policy.model.LiteralExpression; -import org.eclipse.edc.policy.model.Rule; -import org.eclipse.edc.protocol.ids.service.ConnectorServiceSettings; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.asset.AssetIndex; -import org.eclipse.edc.spi.event.Event; -import org.eclipse.edc.spi.event.EventSubscriber; -import org.eclipse.edc.spi.event.contractdefinition.ContractDefinitionCreated; -import org.eclipse.edc.spi.event.contractdefinition.ContractDefinitionDeleted; -import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.system.Hostname; -import org.eclipse.edc.spi.types.domain.asset.Asset; - -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; - -public class IdsBrokerServiceImpl implements IdsBrokerService, EventSubscriber { - - private static final String CONTEXT_BROKER_REGISTRATION = "BrokerRegistration"; - - private final RemoteMessageDispatcherRegistry dispatcherRegistry; - private final ConnectorServiceSettings connectorServiceSettings; - private final Hostname hostname; - - private final ContractDefinitionStore contractDefinitionStore; - - private final PolicyDefinitionStore policyDefinitionStore; - - private final URL brokerBaseUrl; - - private final AssetIndex assetIndex; - - private final List policyBrokerBlacklist; - - private final Monitor monitor; - - public IdsBrokerServiceImpl( - RemoteMessageDispatcherRegistry dispatcherRegistry, - ConnectorServiceSettings connectorServiceSettings, - Hostname hostname, - ContractDefinitionStore contractDefinitionStore, - PolicyDefinitionStore policyDefinitionStore, - URL brokerBaseUrl, - AssetIndex assetIndex, - List policyBrokerBlacklist, - Monitor monitor) { - this.dispatcherRegistry = dispatcherRegistry; - this.connectorServiceSettings = connectorServiceSettings; - this.hostname = hostname; - this.contractDefinitionStore = contractDefinitionStore; - this.policyDefinitionStore = policyDefinitionStore; - this.brokerBaseUrl = brokerBaseUrl; - this.assetIndex = assetIndex; - this.policyBrokerBlacklist = policyBrokerBlacklist; - this.monitor = monitor; - } - - @Override - public void registerConnectorAtBroker(URL brokerBaseUrl) { - try { - var brokerInfrastructureUrl = new URL(String.format("%s/infrastructure", - brokerBaseUrl)); - var connectorBaseUrl = new URI(String.format("http://%s/", hostname.get())); - var registerConnectorMessage = new RegisterConnectorMessage(brokerInfrastructureUrl, - connectorBaseUrl, - connectorServiceSettings.getCurator(), - connectorServiceSettings.getMaintainer()); - monitor.info("Registering Connector at Broker."); - dispatcherRegistry.send(Object.class, registerConnectorMessage, - () -> CONTEXT_BROKER_REGISTRATION); - - monitor.info("Registering existing contractdefinition assets at Broker."); - registerExistingResources(brokerBaseUrl); - } catch (MalformedURLException e) { - throw new EdcException("Could not build brokerInfrastructureUrl", e); - } catch (URISyntaxException e) { - throw new EdcException("Could not create connectorBaseUrl. Hostname can be set using:" + - " edc.hostname", e); - } - } - - private void registerExistingResources(URL brokerBaseUrl) { - var querySpec = new QuerySpec(); - var contractDefinitions = contractDefinitionStore.findAll(querySpec).toList(); - for (var contractDefinition : contractDefinitions) { - var assetHashmap = getAssetHashMap(contractDefinition.getId()); - for (var resourceId : assetHashmap.keySet()) { - var asset = assetHashmap.get(resourceId); - registerResourceAtBroker(brokerBaseUrl, resourceId, asset); - } - } - } - - @Override - public void unregisterConnectorAtBroker(URL brokerBaseUrl) { - try { - var brokerInfrastructureUrl = new URL(String.format("%s/infrastructure", - brokerBaseUrl)); - var connectorBaseUrl = new URI(String.format("http://%s/", hostname.get())); - var unregisterConnectorMessage = new UnregisterConnectorMessage(brokerInfrastructureUrl, connectorBaseUrl); - dispatcherRegistry.send(Object.class, unregisterConnectorMessage, () -> CONTEXT_BROKER_REGISTRATION); - monitor.info("Unregistering Connector at Broker."); - } catch (MalformedURLException e) { - throw new EdcException("Could not build brokerInfrastructureUrl", e); - } catch (URISyntaxException e) { - throw new EdcException("Could not create connectorBaseUrl. Hostname can be set using:" + - " edc.hostname", e); - } - } - - @Override - public void registerResourceAtBroker(URL brokerBaseUrl, String resourceId, Asset asset) { - try { - var resourceUriId = new URI(String.format("https://%1$s/catalog/%2$s", hostname.get(), resourceId)); - var brokerInfrastructureUrl = new URL(String.format("%s/infrastructure", - brokerBaseUrl)); - var connectorBaseUrl = new URI(String.format("http://%s/", hostname.get())); - - var registerResourceMessage = new RegisterResourceMessage( - brokerInfrastructureUrl, - connectorBaseUrl, - resourceUriId, - asset); - dispatcherRegistry.send(Object.class, registerResourceMessage, - () -> CONTEXT_BROKER_REGISTRATION); - } catch (MalformedURLException e) { - throw new EdcException("Could not build brokerInfrastructureUrl", e); - } catch (URISyntaxException e) { - throw new EdcException("Could not create connectorBaseUrl. Hostname can be set using:" + - " edc.hostname", e); - } catch (Exception e) { - throw new EdcException("Infrastructure Host Exception", e); - } - } - - @Override - public void unregisterResourceAtBroker(URL brokerBaseUrl, String resourceId) { - try { - var resourceUriId = new URI(resourceId); - var brokerInfrastructureUrl = new URL(String.format("%s/infrastructure", - brokerBaseUrl)); - var connectorBaseUrl = new URI(String.format("http://%s/", hostname.get())); - var unregisterResourceMessage = new UnregisterResourceMessage( - brokerInfrastructureUrl, - connectorBaseUrl, - resourceUriId); - dispatcherRegistry.send(Object.class, unregisterResourceMessage, - () -> CONTEXT_BROKER_REGISTRATION); - } catch (MalformedURLException e) { - throw new EdcException("Could not build brokerInfrastructureUrl", e); - } catch (URISyntaxException e) { - throw new EdcException("Could not create connectorBaseUrl. Hostname can be set using:" + - " edc.hostname", e); - } catch (Exception e) { - throw new EdcException("Infrastructure Host Exception", e); - } - } - - @Override - public List findResourceIdsByQuery(URL brokerBaseUrl, String fullTextQueryString) { - try { - var brokerInfrastructureUrl = new URL(String.format("%s/infrastructure", - brokerBaseUrl)); - var connectorBaseUrl = new URI(String.format("http://%s/", hostname.get())); - var queryMessage = new QueryMessage( - brokerInfrastructureUrl, - connectorBaseUrl, - fullTextQueryString); - var resultMessageCompletableFuture = dispatcherRegistry.send( - String.class, - queryMessage, - () -> CONTEXT_BROKER_REGISTRATION); - var idList = parseQueryResponse(resultMessageCompletableFuture.get()); - return idList.stream().filter(id -> id - .startsWith(String.format("https://%s/", hostname.get()))) - .collect(Collectors.toList()); - } catch (MalformedURLException e) { - throw new EdcException("Could not build brokerInfrastructureUrl", e); - } catch (URISyntaxException e) { - throw new EdcException("Could not create connectorBaseUrl. Hostname can be set using:" + - " edc.hostname", e); - } catch (ExecutionException | InterruptedException e) { - throw new EdcException("Failed to receive result message", e); - } catch (Exception e) { - throw new EdcException("Infrastructure Host Exception", e); - } - } - - public List parseQueryResponse(String content) { - var result = new ArrayList(); - var scanner = new Scanner(content); - var firstLine = true; - while (scanner.hasNextLine()) { - var line = scanner.nextLine(); - if (firstLine) { - firstLine = false; - } else { - line = line.replace("<", ""); - line = line.replace(">", ""); - result.add(line); - } - } - scanner.close(); - - return result; - } - - @Override - public void on(Event event) { - if (event instanceof ContractDefinitionCreated contractDefinitionCreated) { - var created = resolveCreatedAssets(contractDefinitionCreated); - addResourcesToBroker(created, brokerBaseUrl); - - } else if (event instanceof ContractDefinitionDeleted contractDefinitionDeleted) { - var deleted = resolveDeletedBrokerIds(contractDefinitionDeleted); - removeResourcesFromBroker(deleted, brokerBaseUrl); - } - } - - public HashMap getAssetHashMap(String contractDefinitionId) { - var contractDefinition = contractDefinitionStore.findById(contractDefinitionId); - - var resourceMap = new HashMap(); - var hasBrokerBlacklistedPolicy = checkForBlacklistedPolicy(contractDefinition); - - if (hasBrokerBlacklistedPolicy) { - monitor.info("Not publishing resource at broker due to possible policy breach."); - } else { - var assetsFromContractDefinition = getAssetsFromContractDefinition(contractDefinition); - for (var asset : assetsFromContractDefinition) { - var resourceId = String.format("%s-%s", - contractDefinition.getId(), - asset.getId()); - resourceMap.put(resourceId, asset); - } - } - return resourceMap; - } - - private List resolveDeletedBrokerIds(ContractDefinitionDeleted contractDefinitionDeleted) { - var eventPayload = contractDefinitionDeleted.getPayload(); - var contractDefinitionId = eventPayload.getContractDefinitionId(); - - return getDeletedBrokerIds(brokerBaseUrl, contractDefinitionId); - } - - private HashMap resolveCreatedAssets(ContractDefinitionCreated contractDefinitionCreated) { - var eventPayload = contractDefinitionCreated.getPayload(); - var contractDefinitionId = eventPayload.getContractDefinitionId(); - HashMap resourceMap = getAssetHashMap(contractDefinitionId); - - return resourceMap; - } - - private boolean checkForBlacklistedPolicy(ContractDefinition contractDefinition) { - var contractPolicyId = contractDefinition.getContractPolicyId(); - var accessPolicyId = contractDefinition.getAccessPolicyId(); - - var contractConstraints = getConstraints(policyDefinitionStore.findById(contractPolicyId)); - var accessConstraints = getConstraints(policyDefinitionStore.findById(accessPolicyId)); - return containsBlacklistedPolicy(contractConstraints) || - containsBlacklistedPolicy(accessConstraints); - } - - private List getConstraints(PolicyDefinition contractPolicy) { - if (contractPolicy == null) { - return List.of(); - } else { - return getConstraintsFromPolicy(contractPolicy); - } - } - - private List getConstraintsFromPolicy(PolicyDefinition contractPolicy) { - return contractPolicy - .getPolicy() - .getPermissions() - .stream() - .map(Rule::getConstraints) - .flatMap(List::stream) - .map(AtomicConstraint.class::cast) - .toList(); - } - - private boolean containsBlacklistedPolicy(List constraints) { - return constraints - .stream() - .map(AtomicConstraint::getLeftExpression) - .map(LiteralExpression.class::cast) - .map(LiteralExpression::getValue) - .anyMatch(policyBrokerBlacklist::contains); - } - - private List getAssetsFromContractDefinition(ContractDefinition contractDefinition) { - var querySpec = QuerySpec.Builder.newInstance() - .filter(new ArrayList<>(contractDefinition.getSelectorExpression().getCriteria())) - .build(); - return assetIndex.queryAssets(querySpec).toList(); - } - - private List getDeletedBrokerIds(URL brokerBaseUrl, String deletedContractDefinitionIds) { - var deletedResourceIds = new ArrayList(); - var resourceIdsByQuery = findResourceIdsByQuery(brokerBaseUrl, deletedContractDefinitionIds); - deletedResourceIds.addAll(resourceIdsByQuery); - - return deletedResourceIds; - } - - private void removeResourcesFromBroker( - List deletedBrokerResourceIds, - URL brokerBaseUrl) { - for (var deletedResourceId : deletedBrokerResourceIds) { - monitor.info(String.format("Removing resource %s from broker", deletedResourceId)); - unregisterResourceAtBroker( - brokerBaseUrl, - deletedResourceId); - } - } - - private void addResourcesToBroker( - Map resourceMap, - URL brokerBaseUrl) { - var createdResourceSet = new HashSet<>(resourceMap.keySet()); - - for (var createdResourceId : createdResourceSet) { - monitor.info(String.format("Registering resource %s at broker", createdResourceId)); - registerResourceAtBroker( - brokerBaseUrl, - createdResourceId, - resourceMap.get(createdResourceId)); - } - } -} diff --git a/extensions/ids-broker-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/ids-broker-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension deleted file mode 100644 index 8371a1c28..000000000 --- a/extensions/ids-broker-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ /dev/null @@ -1 +0,0 @@ -de.sovity.extension.broker.BrokerExtension \ No newline at end of file diff --git a/extensions/ids-clearinghouse-client/README.md b/extensions/ids-clearinghouse-client/README.md deleted file mode 100644 index 3d5166eb2..000000000 --- a/extensions/ids-clearinghouse-client/README.md +++ /dev/null @@ -1,53 +0,0 @@ - -
-
- - Logo - - -

EDC-Connector Extension:
IDS Clearing House Client Extension

- -

- Report Bug - · - Request Feature -

-
- -## About this Extension - -This extension communicates contract agreements and data transfers to an IDS Clearing House. - -On successful contract agreements / data transfers, the extension will send IDS LogMessages and expect a `201 Created` -HTTP response. - -## Why does this extension exist? - -Notary logging is a crucial part of dataspaces to ensure compliance and non-repudiation of data transfers. - -## Getting Started - -Our MDS Community Edition EDC is built with both the Clearing House and Broker extensions and is ready to -be used in the Mobility Data Space (MDS). - -## Configuration - -The Clearing House URL can be configured with the ENV var: - -```dotenv -EDC_CLEARINGHOUSE_LOG_URL=https://clearing.test.mobility-dataspace.eu/messages/log -``` - -To disable the extension (per default enabled) you can use following ENV var: - -```dotenv -CLEARINGHOUSE_CLIENT_EXTENSION_ENABLED=false -``` - -## License - -Apache License 2.0 - see [LICENSE](../../LICENSE) - -## Contact - -sovity GmbH - contact@sovity.de diff --git a/extensions/ids-clearinghouse-client/build.gradle.kts b/extensions/ids-clearinghouse-client/build.gradle.kts deleted file mode 100644 index dee304492..000000000 --- a/extensions/ids-clearinghouse-client/build.gradle.kts +++ /dev/null @@ -1,46 +0,0 @@ -plugins { - `java-library` - `maven-publish` -} - -val edcVersion: String by project -val edcGroup: String by project -val jupiterVersion: String by project -val mockitoVersion: String by project -val assertj: String by project -val okHttpVersion: String by project -val jsonVersion: String by project - -dependencies { - implementation("${edcGroup}:control-plane-core:${edcVersion}") - implementation("${edcGroup}:ids-spi:${edcVersion}") - implementation("${edcGroup}:ids-api-multipart-dispatcher-v1:${edcVersion}") - implementation("${edcGroup}:ids-api-configuration:${edcVersion}") - implementation("${edcGroup}:ids-jsonld-serdes:${edcVersion}") - implementation("${edcGroup}:http-spi:${edcVersion}") - - implementation("com.squareup.okhttp3:okhttp:${okHttpVersion}") - implementation("org.json:json:${jsonVersion}") - - testImplementation("org.assertj:assertj-core:${assertj}") - testImplementation("org.junit.jupiter:junit-jupiter-api:${jupiterVersion}") - testImplementation("org.mockito:mockito-core:${mockitoVersion}") - testImplementation("org.mockito:mockito-core:${mockitoVersion}") - testImplementation("org.junit.jupiter:junit-jupiter-params:${jupiterVersion}") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${jupiterVersion}") -} - -tasks.getByName("test") { - useJUnitPlatform() -} - -val sovityEdcExtensionGroup: String by project -group = sovityEdcExtensionGroup - -publishing { - publications { - create(project.name) { - from(components["java"]) - } - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/ClearingHouseExtension.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/ClearingHouseExtension.java deleted file mode 100644 index f4bfd5ac4..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/ClearingHouseExtension.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.clearinghouse; - -import de.fraunhofer.iais.eis.Artifact; -import de.fraunhofer.iais.eis.LogMessage; -import de.sovity.extension.clearinghouse.sender.LogMessageSender; -import de.sovity.extension.clearinghouse.sender.message.clearingdispatcher.IdsMultipartClearingRemoteMessageDispatcher; -import de.sovity.extension.clearinghouse.serializer.MultiContextJsonLdSerializer; -import de.sovity.extension.clearinghouse.service.IdsClearingHouseService; -import de.sovity.extension.clearinghouse.service.IdsClearingHouseServiceImpl; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.protocol.ids.api.configuration.IdsApiConfiguration; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.IdsMultipartSender; -import org.eclipse.edc.protocol.ids.jsonld.JsonLd; -import org.eclipse.edc.protocol.ids.service.ConnectorServiceSettings; -import org.eclipse.edc.protocol.ids.spi.service.DynamicAttributeTokenService; -import org.eclipse.edc.protocol.ids.spi.transform.IdsTransformerRegistry; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.runtime.metamodel.annotation.Setting; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.event.EventRouter; -import org.eclipse.edc.spi.http.EdcHttpClient; -import org.eclipse.edc.spi.iam.IdentityService; -import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.Hostname; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.spi.types.TypeManager; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Map; - -public class ClearingHouseExtension implements ServiceExtension { - - public static final String CATALOG_TRANSFER_EXTENSION = "ClearingHouseExtension"; - private static final String TYPE_MANAGER_SERIALIZER_KEY = "ids-clearinghouse"; - - private static final Map CONTEXT_MAP = Map.of( - "cat", "http://w3id.org/mds/data-categories#", - "ids", "https://w3id.org/idsa/core/", - "idsc", "https://w3id.org/idsa/code/"); - @Setting - public static final String CLEARINGHOUSE_LOG_URL_SETTING = "edc.clearinghouse.log.url"; - - @Setting - private static final String CLEARINGHOUSE_CLIENT_EXTENSION_ENABLED = "clearinghouse.client.extension.enabled"; - - @Inject - private IdsApiConfiguration idsApiConfiguration; - - @Inject - private RemoteMessageDispatcherRegistry dispatcherRegistry; - - @Inject - private IdentityService identityService; - - @Inject - private IdsTransformerRegistry transformerRegistry; - - @Inject - private ContractNegotiationStore contractNegotiationStore; - - @Inject - private TransferProcessStore transferProcessStore; - - @Inject - private Hostname hostname; - - @Inject - private EdcHttpClient edcHttpClient; - - @Inject - private DynamicAttributeTokenService dynamicAttributeTokenService; - - @Inject - private EventRouter eventRouter; - - private IdsClearingHouseService idsClearingHouseService; - - private URL clearingHouseLogUrl; - private Monitor monitor; - - - @Override - public String name() { - return CATALOG_TRANSFER_EXTENSION; - } - - @Override - public void initialize(ServiceExtensionContext context) { - monitor = context.getMonitor(); - var extensionEnabled = context.getSetting(CLEARINGHOUSE_CLIENT_EXTENSION_ENABLED, false); - - if (!extensionEnabled) { - monitor.info("Clearinghouse client extension is disabled."); - return; - } - monitor.info("Clearinghouse client extension is enabled."); - - clearingHouseLogUrl = readUrlFromSettings(context, CLEARINGHOUSE_LOG_URL_SETTING); - - registerSerializerClearingHouseMessages(context); - registerClearingHouseMessageSenders(context); - - var connectorServiceSettings = new ConnectorServiceSettings(context, context.getMonitor()); - - registerEventSubscriber(context, connectorServiceSettings); - } - - private void registerEventSubscriber(ServiceExtensionContext context, - ConnectorServiceSettings connectorServiceSettings) { - var eventSubscriber = new IdsClearingHouseServiceImpl( - dispatcherRegistry, - connectorServiceSettings, - hostname, - clearingHouseLogUrl, - contractNegotiationStore, - transferProcessStore, - monitor); - - eventRouter.registerSync(eventSubscriber); //asynchronous dispatch - registerSync for synchronous dispatch - context.registerService(IdsClearingHouseService.class, eventSubscriber); - } - - private URL readUrlFromSettings(ServiceExtensionContext context, String settingsPath) { - try { - var urlString = context.getSetting(settingsPath, null); - if (urlString == null) { - throw new EdcException(String.format("Could not initialize " + - "ClearingHouseExtension: " + - "No url specified using setting %s", settingsPath)); - } - - return new URL(urlString); - } catch (MalformedURLException e) { - throw new EdcException(String.format("Could not parse setting %s to Url", - settingsPath), e); - } - } - - private void registerSerializerClearingHouseMessages(ServiceExtensionContext context) { - var typeManager = context.getTypeManager(); - typeManager.registerContext(TYPE_MANAGER_SERIALIZER_KEY, JsonLd.getObjectMapper()); - registerCommonTypes(typeManager); - } - - private void registerCommonTypes(TypeManager typeManager) { - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, Artifact.class, - new MultiContextJsonLdSerializer<>(Artifact.class, CONTEXT_MAP)); - typeManager.registerSerializer(TYPE_MANAGER_SERIALIZER_KEY, LogMessage.class, - new MultiContextJsonLdSerializer<>(LogMessage.class, CONTEXT_MAP)); - } - - private void registerClearingHouseMessageSenders(ServiceExtensionContext context) { - var httpClient = context.getService(EdcHttpClient.class); - var monitor = context.getMonitor(); - var typeManager = context.getTypeManager(); - var objectMapper = typeManager.getMapper(TYPE_MANAGER_SERIALIZER_KEY); - - var logMessageSender = new LogMessageSender(); - - var idsMultipartSender = new IdsMultipartSender(monitor, httpClient, dynamicAttributeTokenService, objectMapper); - var dispatcher = new IdsMultipartClearingRemoteMessageDispatcher(idsMultipartSender); - dispatcher.register(logMessageSender); - dispatcherRegistry.register(dispatcher); - } - - @Override - public void start() {} - - @Override - public void prepare() { - ServiceExtension.super.prepare(); - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/LogMessageSender.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/LogMessageSender.java deleted file mode 100644 index 1c66aca0b..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/LogMessageSender.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.clearinghouse.sender; - -import de.fraunhofer.iais.eis.DynamicAttributeToken; -import de.fraunhofer.iais.eis.LogMessageBuilder; -import de.fraunhofer.iais.eis.Message; -import de.fraunhofer.iais.eis.MessageProcessedNotificationMessageImpl; -import de.sovity.extension.clearinghouse.sender.message.LogMessage; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.MultipartSenderDelegate; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.IdsMultipartParts; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.response.MultipartResponse; -import org.eclipse.edc.protocol.ids.spi.domain.IdsConstants; -import org.eclipse.edc.protocol.ids.util.CalendarUtil; -import org.eclipse.edc.spi.EdcException; -import org.json.JSONObject; - -import java.util.List; - -import static org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.util.ResponseUtil.parseMultipartStringResponse; -import static org.eclipse.edc.protocol.ids.jsonld.JsonLd.getObjectMapper; - -public class LogMessageSender implements MultipartSenderDelegate { - - public LogMessageSender() { - } - - @Override - public Message buildMessageHeader(LogMessage logMessage, - DynamicAttributeToken token) throws Exception { - return new LogMessageBuilder() - ._modelVersion_(IdsConstants.INFORMATION_MODEL_VERSION) - ._issued_(CalendarUtil.gregorianNow()) - ._securityToken_(token) - ._issuerConnector_(logMessage.connectorBaseUrl()) - ._senderAgent_(logMessage.connectorBaseUrl()) - .build(); - } - - @Override - public String buildMessagePayload(LogMessage logMessage) throws Exception { - if (logMessage.eventToLog() instanceof ContractAgreement contractAgreement) { - return buildContractAgreementPayload(contractAgreement); - } else if (logMessage.eventToLog() instanceof TransferProcess transferProcess) { - return buildTransferProcessPayload(transferProcess); - } else { - throw new EdcException(String.format("ObjectType %s not supported in LogMessageSender", - logMessage.eventToLog().getClass())); - } - } - - @Override - public MultipartResponse getResponseContent(IdsMultipartParts parts) throws Exception { - return parseMultipartStringResponse(parts, getObjectMapper()); - } - - @Override - public List> getAllowedResponseTypes() { - return List.of(MessageProcessedNotificationMessageImpl.class); - } - - @Override - public Class getMessageType() { - return LogMessage.class; - } - - private String buildContractAgreementPayload(ContractAgreement contractAgreement) { - var jo = new JSONObject(); - jo.put("AgreementId", contractAgreement.getId()); - jo.put("AssetId", contractAgreement.getAssetId()); - jo.put("ContractStartDate", contractAgreement.getContractStartDate()); - jo.put("ContractEndDate", contractAgreement.getContractEndDate()); - jo.put("ContractSigningDate", contractAgreement.getContractSigningDate()); - jo.put("ConsumerAgentId", contractAgreement.getConsumerAgentId()); - jo.put("ProviderAgentId", contractAgreement.getProviderAgentId()); - return jo.toString(); - } - - private String buildTransferProcessPayload(TransferProcess transferProcess) { - var jo = new JSONObject(); - jo.put("transferProcessId", transferProcess.getId()); - var dataRequest = transferProcess.getDataRequest(); - jo.put("contractId", dataRequest.getContractId()); - jo.put("connectorId", dataRequest.getConnectorId()); - return jo.toString(); - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/LogMessage.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/LogMessage.java deleted file mode 100644 index ddc85fe22..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/LogMessage.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.sovity.extension.clearinghouse.sender.message; - -import de.sovity.extension.clearinghouse.sender.message.clearingdispatcher.ExtendedMessageProtocolClearing; -import org.eclipse.edc.spi.types.domain.message.RemoteMessage; - -import java.net.URI; -import java.net.URL; - -public record LogMessage(URL clearingHouseLogUrl, - URI connectorBaseUrl, - Object eventToLog) implements RemoteMessage { - @Override - public String getProtocol() { - return ExtendedMessageProtocolClearing.IDS_EXTENDED_PROTOCOL_CLEARING; - } - - @Override - public String getConnectorAddress() { - return clearingHouseLogUrl.toString(); - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/ExtendedMessageProtocolClearing.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/ExtendedMessageProtocolClearing.java deleted file mode 100644 index e85ee22d0..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/ExtendedMessageProtocolClearing.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.clearinghouse.sender.message.clearingdispatcher; - -import org.eclipse.edc.protocol.ids.spi.types.MessageProtocol; - -public final class ExtendedMessageProtocolClearing { - - private static final String EXTENDED_SUFFIX = "-extended-clearing"; - public static final String IDS_EXTENDED_PROTOCOL_CLEARING = String.format("%s%s", MessageProtocol.IDS_MULTIPART, EXTENDED_SUFFIX); - - private ExtendedMessageProtocolClearing() { - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/IdsMultipartClearingRemoteMessageDispatcher.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/IdsMultipartClearingRemoteMessageDispatcher.java deleted file mode 100644 index a67ca08cd..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/sender/message/clearingdispatcher/IdsMultipartClearingRemoteMessageDispatcher.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.clearinghouse.sender.message.clearingdispatcher; - -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.IdsMultipartRemoteMessageDispatcher; -import org.eclipse.edc.protocol.ids.api.multipart.dispatcher.sender.IdsMultipartSender; - -public class IdsMultipartClearingRemoteMessageDispatcher extends IdsMultipartRemoteMessageDispatcher { - - public IdsMultipartClearingRemoteMessageDispatcher(IdsMultipartSender idsMultipartSender) { - super(idsMultipartSender); - } - - @Override - public String protocol() { - return ExtendedMessageProtocolClearing.IDS_EXTENDED_PROTOCOL_CLEARING; - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/serializer/MultiContextJsonLdSerializer.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/serializer/MultiContextJsonLdSerializer.java deleted file mode 100644 index bed1cbd57..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/serializer/MultiContextJsonLdSerializer.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2022 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 - * sovity GmbH - Adaption and changes - * - */ - -package de.sovity.extension.clearinghouse.serializer; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.jsontype.TypeSerializer; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; - -import java.io.IOException; -import java.net.URI; -import java.util.Map; - -/** - * Custom Jackson serializer for any {@link Object}. Adds type and context information to result object. - * - * @param The object that should be serialized. - */ -public class MultiContextJsonLdSerializer extends JsonSerializer { - private final Class type; - private final Object contextInformation; - - private static final ThreadLocal CURRENT_RECURSION_DEPTH = ThreadLocal.withInitial(() -> 0); - - public MultiContextJsonLdSerializer(Class type, Object contextInformation) { - this.type = type; - this.contextInformation = contextInformation; - } - - @Override - public void serialize(T value, JsonGenerator generator, SerializerProvider provider) throws IOException { - CURRENT_RECURSION_DEPTH.set(CURRENT_RECURSION_DEPTH.get() + 1); - - Map propertiesMap = null; - try { - var field = value.getClass().getDeclaredField("properties"); - field.setAccessible(true); - propertiesMap = (Map) field.get(value); - } catch (NoSuchFieldException | IllegalAccessException ignore) { - // empty - } - removeProperty(value, "properties"); - - // remove properties "comment" and "label" - removeProperty(value, "comment"); - removeProperty(value, "label"); - - generator.writeStartObject(); - - // write new object - var serializer = instantiateSerializerFromProvider(provider, type); - serializer.unwrappingSerializer(null).serialize(value, generator, provider); - - if (CURRENT_RECURSION_DEPTH.get() == 1) { - // context needed only once (for parent object) - generator.writeObjectField("@context", contextInformation); - } - - // add type property - var type = getTypeName(value.getClass()); - if (type != null) { - generator.writeObjectField("@type", type); - } - - // add custom properties as root properties (not in a separate "properties" map) - if (propertiesMap != null) { - for (var key : propertiesMap.keySet()) { - var val = propertiesMap.get(key); - if (val instanceof URI) { - generator.writeStringField(key, val.toString()); - } else { - generator.writeObjectField(key, val); - } - } - } - - generator.writeEndObject(); - - CURRENT_RECURSION_DEPTH.set(CURRENT_RECURSION_DEPTH.get() - 1); - } - - @Override - public void serializeWithType(T value, JsonGenerator gen, SerializerProvider provider, TypeSerializer ser) throws IOException { - serialize(value, gen, provider); - } - - private void removeProperty(Object value, String name) { - try { - var field = value.getClass().getDeclaredField(name); - field.setAccessible(true); - field.set(value, null); - } catch (NoSuchFieldException | IllegalAccessException ignore) { - // empty - } - } - - private String getTypeName(Class clazz) { - var typeName = clazz.getAnnotation(JsonTypeName.class); - if (typeName != null) { - var value = typeName.value(); - if (value == null) { - getTypeName(clazz.getSuperclass()); - } - return value; - } - return null; - } - - private JsonSerializer instantiateSerializerFromProvider(SerializerProvider provider, Class type) throws JsonMappingException { - var javaType = provider.constructType(type); - var beanDescription = provider.getConfig().introspect(javaType); - var staticTyping = provider.isEnabled(MapperFeature.USE_STATIC_TYPING); - return BeanSerializerFactory.instance.findBeanOrAddOnSerializer(provider, javaType, beanDescription, staticTyping); - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseService.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseService.java deleted file mode 100644 index 49ffb9d91..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseService.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.clearinghouse.service; - -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; - -import java.net.URL; - -public interface IdsClearingHouseService { - - void logContractAgreement(ContractAgreement contractAgreement, - URL clearingHouseLogUrl); - - void logTransferProcess(TransferProcess transferProcess, - URL clearingHouseLogUrl); -} diff --git a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseServiceImpl.java b/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseServiceImpl.java deleted file mode 100644 index 669c485ff..000000000 --- a/extensions/ids-clearinghouse-client/src/main/java/de/sovity/extension/clearinghouse/service/IdsClearingHouseServiceImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ -package de.sovity.extension.clearinghouse.service; - -import de.sovity.extension.clearinghouse.sender.message.LogMessage; -import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; -import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; -import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; -import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; -import org.eclipse.edc.protocol.ids.service.ConnectorServiceSettings; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.event.Event; -import org.eclipse.edc.spi.event.EventSubscriber; -import org.eclipse.edc.spi.event.contractnegotiation.ContractNegotiationConfirmed; -import org.eclipse.edc.spi.event.transferprocess.TransferProcessCompleted; -import org.eclipse.edc.spi.message.RemoteMessageDispatcherRegistry; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.Hostname; - -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.UUID; - -public class IdsClearingHouseServiceImpl implements IdsClearingHouseService, EventSubscriber { - - private static final String CONTEXT_CLEARINGHOUSE = "ClearingHouse"; - - private final RemoteMessageDispatcherRegistry dispatcherRegistry; - private final ConnectorServiceSettings connectorServiceSettings; - private final URI connectorBaseUrl; - private final URL clearingHouseLogUrl; - private final ContractNegotiationStore contractNegotiationStore; - private final TransferProcessStore transferProcessStore; - private final Monitor monitor; - - public IdsClearingHouseServiceImpl( - RemoteMessageDispatcherRegistry dispatcherRegistry, - ConnectorServiceSettings connectorServiceSettings, - Hostname hostname, - URL clearingHouseLogUrl, - ContractNegotiationStore contractNegotiationStore, - TransferProcessStore transferProcessStore, - Monitor monitor) { - this.dispatcherRegistry = dispatcherRegistry; - this.connectorServiceSettings = connectorServiceSettings; - this.clearingHouseLogUrl = clearingHouseLogUrl; - this.contractNegotiationStore = contractNegotiationStore; - this.transferProcessStore = transferProcessStore; - this.monitor = monitor; - - try { - connectorBaseUrl = getConnectorBaseUrl(hostname); - } catch (URISyntaxException e) { - throw new EdcException("Could not create connectorBaseUrl. Hostname can be set using:" + - " edc.hostname", e); - } - } - - @Override - public void logContractAgreement(ContractAgreement contractAgreement, URL clearingHouseLogUrl) { - monitor.info("Logging contract agreement to ClearingHouse"); - var logMessage = new LogMessage(clearingHouseLogUrl, connectorBaseUrl, contractAgreement); - dispatcherRegistry.send(Object.class, logMessage, () -> CONTEXT_CLEARINGHOUSE); - } - - @Override - public void logTransferProcess(TransferProcess transferProcess, URL clearingHouseLogUrl) { - monitor.info("Logging transferprocess to ClearingHouse"); - var logMessage = new LogMessage(clearingHouseLogUrl, connectorBaseUrl, transferProcess); - dispatcherRegistry.send(Object.class, logMessage, () -> CONTEXT_CLEARINGHOUSE); - } - - @Override - public void on(Event event) { - try { - if (event instanceof ContractNegotiationConfirmed contractNegotiationConfirmed) { - var contractAgreement = resolveContractAgreement(contractNegotiationConfirmed); - var pid = UUID.nameUUIDFromBytes(contractAgreement.getId().getBytes()).toString(); - var extendedUrl = new URL(clearingHouseLogUrl + "/" + pid); - logContractAgreement(contractAgreement, extendedUrl); - } else if (event instanceof TransferProcessCompleted transferProcessCompleted) { - var transferProcess = resolveTransferProcess(transferProcessCompleted); - var pid = UUID.nameUUIDFromBytes(transferProcess.getId().getBytes()).toString(); - var extendedUrl = new URL(clearingHouseLogUrl + "/" + pid); - logTransferProcess(transferProcess, extendedUrl); - } - } catch (Exception e) { - throw new EdcException("Could not create extended clearinghouse url."); - } - } - - private ContractAgreement resolveContractAgreement(ContractNegotiationConfirmed contractNegotiationConfirmed) { - var eventPayload = contractNegotiationConfirmed.getPayload(); - var contractNegotiationId = eventPayload.getContractNegotiationId(); - var contractNegotiation = contractNegotiationStore.find(contractNegotiationId); - return contractNegotiation.getContractAgreement(); - } - - private TransferProcess resolveTransferProcess(TransferProcessCompleted transferProcessCompleted) { - var eventPayload = transferProcessCompleted.getPayload(); - var transferProcessId = eventPayload.getTransferProcessId(); - return transferProcessStore.find(transferProcessId); - } - - private URI getConnectorBaseUrl(Hostname hostname) throws URISyntaxException { - return new URI(String.format("http://%s/", hostname.get())); - } -} diff --git a/extensions/ids-clearinghouse-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/ids-clearinghouse-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension deleted file mode 100644 index 3f95593f1..000000000 --- a/extensions/ids-clearinghouse-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ /dev/null @@ -1 +0,0 @@ -de.sovity.extension.clearinghouse.ClearingHouseExtension \ No newline at end of file diff --git a/extensions/last-commit-info/build.gradle.kts b/extensions/last-commit-info/build.gradle.kts index c0e3f9671..7eb43cca6 100644 --- a/extensions/last-commit-info/build.gradle.kts +++ b/extensions/last-commit-info/build.gradle.kts @@ -1,6 +1,8 @@ val edcVersion: String by project val edcGroup: String by project val restAssured: String by project +val mockitoVersion: String by project +val lombokVersion: String by project plugins { `java-library` @@ -8,8 +10,8 @@ plugins { } dependencies { - annotationProcessor("org.projectlombok:lombok:1.18.28") - compileOnly("org.projectlombok:lombok:1.18.28") + annotationProcessor("org.projectlombok:lombok:${lombokVersion}") + compileOnly("org.projectlombok:lombok:${lombokVersion}") api("${edcGroup}:core-spi:${edcVersion}") api("${edcGroup}:control-plane-spi:${edcVersion}") @@ -19,13 +21,15 @@ dependencies { implementation("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0") implementation("jakarta.validation:jakarta.validation-api:3.0.2") - testAnnotationProcessor("org.projectlombok:lombok:1.18.28") - testCompileOnly("org.projectlombok:lombok:1.18.28") + testAnnotationProcessor("org.projectlombok:lombok:${lombokVersion}") + testCompileOnly("org.projectlombok:lombok:${lombokVersion}") testImplementation("${edcGroup}:control-plane-core:${edcVersion}") testImplementation("${edcGroup}:junit:${edcVersion}") testImplementation("${edcGroup}:http:${edcVersion}") testImplementation("io.rest-assured:rest-assured:${restAssured}") + testImplementation("${edcGroup}:data-plane-selector-core:${edcVersion}") + testImplementation("org.mockito:mockito-core:${mockitoVersion}") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") } diff --git a/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java b/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java index 242e83794..661ed0828 100644 --- a/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java +++ b/extensions/last-commit-info/src/test/java/de/sovity/edc/extension/version/controller/LastCommitInfoTest.java @@ -15,8 +15,11 @@ package de.sovity.edc.extension.version.controller; import io.restassured.http.ContentType; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,6 +29,7 @@ import static io.restassured.RestAssured.given; import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -33,6 +37,11 @@ class LastCommitInfoTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); + extension.registerServiceMock( + DataPlaneInstanceStore.class, + mock(DataPlaneInstanceStore.class)); extension.setConfiguration(Map.of( "web.http.port", String.valueOf(getFreePort()), "web.http.path", "/api", diff --git a/extensions/policy-always-true/build.gradle.kts b/extensions/policy-always-true/build.gradle.kts index 09d746fd9..0b1fc415f 100644 --- a/extensions/policy-always-true/build.gradle.kts +++ b/extensions/policy-always-true/build.gradle.kts @@ -1,5 +1,6 @@ val edcVersion: String by project val edcGroup: String by project +val mockitoVersion: String by project plugins { `java-library` @@ -14,6 +15,8 @@ dependencies { testImplementation("${edcGroup}:control-plane-core:${edcVersion}") testImplementation("${edcGroup}:junit:${edcVersion}") + testImplementation("${edcGroup}:data-plane-selector-core:${edcVersion}") + testImplementation("org.mockito:mockito-core:${mockitoVersion}") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") } diff --git a/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java b/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java index 590e81078..1cefc56b6 100644 --- a/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java +++ b/extensions/policy-always-true/src/test/java/de/sovity/edc/extension/policy/AlwaysTruePolicyExtensionTest.java @@ -14,15 +14,18 @@ package de.sovity.edc.extension.policy; -import org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionService; +import org.eclipse.edc.connector.contract.spi.offer.ContractDefinitionResolver; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; import org.eclipse.edc.connector.policy.spi.PolicyDefinition; import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.spi.agent.ParticipantAgent; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -30,19 +33,29 @@ import static de.sovity.edc.extension.policy.AlwaysTruePolicyConstants.POLICY_DEFINITION_ID; import static java.util.Objects.requireNonNull; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) class AlwaysTruePolicyExtensionTest { + @BeforeEach + void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock( + DataPlaneInstanceStore.class, + mock(DataPlaneInstanceStore.class)); + } + @Test - void alwaysTruePolicyDef(PolicyEngine policyEngine, PolicyDefinitionService policyDefinitionService) { + void alwaysTruePolicyDef(PolicyEngine policyEngine, + PolicyDefinitionService policyDefinitionService) { // arrange var alwaysTrue = alwaysTruePolicy(policyDefinitionService); // act var result = policyEngine.evaluate( - ContractDefinitionService.CATALOGING_SCOPE, + ContractDefinitionResolver.CATALOGING_SCOPE, alwaysTrue.getPolicy(), participantAgent() ); diff --git a/extensions/postgres-flyway/build.gradle.kts b/extensions/postgres-flyway/build.gradle.kts index ccc27be66..7b2a6ab18 100644 --- a/extensions/postgres-flyway/build.gradle.kts +++ b/extensions/postgres-flyway/build.gradle.kts @@ -2,6 +2,7 @@ val edcVersion: String by project val edcGroup: String by project val flywayVersion: String by project val postgresVersion: String by project +val lombokVersion: String by project plugins { `java-library` @@ -9,6 +10,9 @@ plugins { } dependencies { + annotationProcessor("org.projectlombok:lombok:${lombokVersion}") + compileOnly("org.projectlombok:lombok:${lombokVersion}") + implementation("${edcGroup}:core-spi:${edcVersion}") implementation("${edcGroup}:sql-core:${edcVersion}") @@ -17,6 +21,7 @@ dependencies { implementation("${edcGroup}:data-plane-instance-store-sql:${edcVersion}") implementation("${edcGroup}:sql-pool-apache-commons:${edcVersion}") implementation("${edcGroup}:transaction-local:${edcVersion}") + implementation("org.postgresql:postgresql:${postgresVersion}") implementation("org.flywaydb:flyway-core:${flywayVersion}") diff --git a/extensions/postgres-flyway/src/main/resources/migration/consumer/V1__m8-consumer-sample-data.sql b/extensions/postgres-flyway/src/main/resources/migration/consumer/V1__m8-consumer-sample-data.sql new file mode 100644 index 000000000..d273f49f0 --- /dev/null +++ b/extensions/postgres-flyway/src/main/resources/migration/consumer/V1__m8-consumer-sample-data.sql @@ -0,0 +1,97 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 11.20 +-- Dumped by pg_dump version 11.20 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Data for Name: edc_asset; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_asset_dataaddress; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_asset_property; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_contract_agreement; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_contract_agreement (agr_id, provider_agent_id, consumer_agent_id, signing_date, start_date, end_date, asset_id, policy) VALUES ('test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', 'urn:connector:provider', 'urn:connector:consumer', 1687179323, 1687179321, 1718715321, 'urn:artifact:test:1.0', '{"permissions":[{"edctype":"dataspaceconnector:permission","uid":null,"target":"urn:artifact:test:1.0","action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2022-05-31T22:00:00.000Z"},"operator":"GEQ"},{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2030-06-30T22:00:00.000Z"},"operator":"LT"}],"duties":[]}],"prohibitions":[],"obligations":[],"extensibleProperties":{},"inheritsFrom":null,"assigner":null,"assignee":null,"target":"urn:artifact:test:1.0","@type":{"@policytype":"set"}}'); + + +-- +-- Data for Name: edc_contract_definitions; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_lease; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_contract_negotiation; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_contract_negotiation (id, correlation_id, counterparty_id, counterparty_address, protocol, type, state, state_count, state_timestamp, error_detail, agreement_id, contract_offers, trace_context, lease_id, created_at, updated_at) VALUES ('6ae57214-b6ea-42b0-adaa-ad64ce6c883c', NULL, 'my-connector', 'http://edc:11003/api/v1/ids/data', 'ids-multipart', 0, 1200, 1, 1687179323356, NULL, 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '[{"id":"test-contract-definition:bda8b77d-07f0-4fcd-a941-4f068b71f574","policy":{"permissions":[{"edctype":"dataspaceconnector:permission","uid":null,"target":"urn:artifact:test:1.0","action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2022-05-31T22:00:00.000Z"},"operator":"GEQ"},{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2030-06-30T22:00:00.000Z"},"operator":"LT"}],"duties":[]}],"prohibitions":[],"obligations":[],"extensibleProperties":{},"inheritsFrom":null,"assigner":null,"assignee":null,"target":"urn:artifact:test:1.0","@type":{"@policytype":"set"}},"asset":{"id":"urn:artifact:test:1.0","createdAt":1687179321833,"properties":{"asset:prop:id":"urn:artifact:test:1.0"}},"provider":"urn:connector:provider","consumer":"urn:connector:consumer","offerStart":null,"offerEnd":null,"contractStart":"2023-06-19T12:55:21.833454574Z","contractEnd":"2024-06-18T12:55:21.833454574Z"}]', '{}', NULL, 1687179321839, 1687179323356); + + +-- +-- Data for Name: edc_data_plane_instance; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_transfer_process; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_transfer_process (transferprocess_id, type, state, state_count, state_time_stamp, created_at, trace_context, error_detail, resource_manifest, provisioned_resource_set, content_data_address, deprovisioned_resources, lease_id, updated_at, transferprocess_properties) VALUES ('3499e4f0-1f8c-4ae6-8ca3-82812586b80f', 'CONSUMER', 800, 1, 1687179352248, 1687179350848, '{}', NULL, '{"definitions":[]}', NULL, NULL, '[]', NULL, 1687179352248, '{}'); +INSERT INTO public.edc_transfer_process (transferprocess_id, type, state, state_count, state_time_stamp, created_at, trace_context, error_detail, resource_manifest, provisioned_resource_set, content_data_address, deprovisioned_resources, lease_id, updated_at, transferprocess_properties) VALUES ('3c7606fd-e3e3-453a-bc38-e2fd6293acc8', 'CONSUMER', 800, 1, 1687179374739, 1687179373229, '{}', NULL, '{"definitions":[]}', NULL, NULL, '[]', NULL, 1687179374739, '{}'); +INSERT INTO public.edc_transfer_process (transferprocess_id, type, state, state_count, state_time_stamp, created_at, trace_context, error_detail, resource_manifest, provisioned_resource_set, content_data_address, deprovisioned_resources, lease_id, updated_at, transferprocess_properties) VALUES ('683098a6-0ed0-4b1a-bf19-f1b0dc67f682', 'CONSUMER', 800, 1, 1687179378080, 1687179375831, '{}', NULL, '{"definitions":[]}', NULL, NULL, '[]', NULL, 1687179378080, '{}'); + + +-- +-- Data for Name: edc_data_request; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_data_request (datarequest_id, process_id, connector_address, protocol, connector_id, asset_id, contract_id, data_destination, managed_resources, properties, transfer_type, transfer_process_id) VALUES ('e213fc10-f61a-4aa0-80f8-7c581651f543', '3499e4f0-1f8c-4ae6-8ca3-82812586b80f', 'http://edc:11003/api/v1/ids/data', 'ids-multipart', 'consumer', 'urn:artifact:test:1.0', 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '{"properties":{"baseUrl":"https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a","method":"POST","type":"HttpData"}}', false, '{}', '{"contentType":"application/octet-stream","isFinite":true}', '3499e4f0-1f8c-4ae6-8ca3-82812586b80f'); +INSERT INTO public.edc_data_request (datarequest_id, process_id, connector_address, protocol, connector_id, asset_id, contract_id, data_destination, managed_resources, properties, transfer_type, transfer_process_id) VALUES ('34b587d1-9a1a-4bc2-a499-24a0e6975b97', '3c7606fd-e3e3-453a-bc38-e2fd6293acc8', 'http://edc:11003/api/v1/ids/data', 'ids-multipart', 'consumer', 'urn:artifact:test:1.0', 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '{"properties":{"baseUrl":"https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a","method":"POST","type":"HttpData"}}', false, '{}', '{"contentType":"application/octet-stream","isFinite":true}', '3c7606fd-e3e3-453a-bc38-e2fd6293acc8'); +INSERT INTO public.edc_data_request (datarequest_id, process_id, connector_address, protocol, connector_id, asset_id, contract_id, data_destination, managed_resources, properties, transfer_type, transfer_process_id) VALUES ('5e4cb5c8-fc8e-4231-ba86-bc5dbf7b5015', '683098a6-0ed0-4b1a-bf19-f1b0dc67f682', 'http://edc:11003/api/v1/ids/data', 'ids-multipart', 'consumer', 'urn:artifact:test:1.0', 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '{"properties":{"baseUrl":"https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a","method":"POST","type":"HttpData"}}', false, '{}', '{"contentType":"application/octet-stream","isFinite":true}', '683098a6-0ed0-4b1a-bf19-f1b0dc67f682'); + + +-- +-- Data for Name: edc_policydefinitions; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_policydefinitions (policy_id, permissions, prohibitions, duties, extensible_properties, inherits_from, assigner, assignee, target, policy_type, created_at) VALUES ('always-true', '[{"edctype":"dataspaceconnector:permission","uid":null,"target":null,"action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"ALWAYS_TRUE"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"true"},"operator":"EQ"}],"duties":[]}]', '[]', '[]', '{}', NULL, NULL, NULL, NULL, '{"@policytype":"set"}', 1687179132887); + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/extensions/postgres-flyway/src/main/resources/migration/default/V3__MS8-to-0.2.0.sql b/extensions/postgres-flyway/src/main/resources/migration/default/V3__MS8-to-0.2.0.sql new file mode 100644 index 000000000..370cb5201 --- /dev/null +++ b/extensions/postgres-flyway/src/main/resources/migration/default/V3__MS8-to-0.2.0.sql @@ -0,0 +1,98 @@ +-- +-- Copyright (c) 2023 sovity GmbH +-- +-- 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: +-- sovity GmbH - Update Tables From MS8 to 0.1.0 EDC +-- +-- + +-- Assets +alter table edc_asset_property add column property_is_private boolean; + +-- Update Asset IDs +ALTER TABLE edc_asset_dataaddress DROP CONSTRAINT edc_asset_dataaddress_asset_id_fk_fkey; +ALTER TABLE edc_asset_property DROP CONSTRAINT edc_asset_property_asset_id_fk_fkey; +UPDATE edc_asset SET asset_id = REPLACE(REPLACE(asset_id, 'urn:artifact:', ''), ':', '-'); +UPDATE edc_asset_dataaddress SET asset_id_fk = REPLACE(REPLACE(asset_id_fk, 'urn:artifact:', ''), ':', '-'); +UPDATE edc_asset_property SET asset_id_fk = REPLACE(REPLACE(asset_id_fk, 'urn:artifact:', ''), ':', '-'); +ALTER TABLE edc_asset_dataaddress ADD CONSTRAINT edc_asset_dataaddress_asset_id_fk_fkey FOREIGN KEY (asset_id_fk) REFERENCES edc_asset (asset_id) ON DELETE CASCADE; +ALTER TABLE edc_asset_property ADD CONSTRAINT edc_asset_property_asset_id_fk_fkey FOREIGN KEY (asset_id_fk) REFERENCES edc_asset (asset_id) ON DELETE CASCADE; + +UPDATE edc_asset_property SET property_name = 'https://w3id.org/edc/v0.0.1/ns/id', property_value=asset_id_fk WHERE property_name = 'asset:prop:id'; + +-- Contract Negotiations +alter table edc_contract_negotiation drop constraint provider_correlation_id; +alter table edc_contract_negotiation alter column "type" type varchar using ''; +alter table edc_contract_negotiation add column callback_addresses json; + +-- Contract Definitions +alter table edc_contract_definitions rename column selector_expression to assets_selector; +alter table edc_contract_definitions drop column validity; + +-- remove criteria parent +UPDATE edc_contract_definitions +SET assets_selector = assets_selector->'criteria' +WHERE assets_selector::jsonb ? 'criteria'; + +-- fix asset_id_operands +create or replace function migrate_json(criteria_json_array_element jsonb) returns jsonb as +$$ +declare + fixed_operand_right_list jsonb; + r record; +begin + fixed_operand_right_list = jsonb_build_array(); + if jsonb_typeof(criteria_json_array_element -> 'operandRight') = 'array' then + for r in (select jsonb_array_elements(criteria_json_array_element -> 'operandRight') operand_right_element) + loop + fixed_operand_right_list = fixed_operand_right_list || + (replace( + replace( + r.operand_right_element::text, + 'urn:artifact:', ''), + ':', '-'))::jsonb; + end loop; + criteria_json_array_element = jsonb_set( + criteria_json_array_element, + '{operandLeft}', + '"https://w3id.org/edc/v0.0.1/ns/id"' + ); + return jsonb_set( + criteria_json_array_element, + '{operandRight}', + fixed_operand_right_list, + false); + else + return criteria_json_array_element; + end if; +end; +$$ language plpgsql; + +UPDATE edc_contract_definitions +SET assets_selector = co.criteria_edited +FROM (SELECT cd.contract_definition_id, + jsonb_agg( + migrate_json(elems) + )::json as criteria_edited + FROM edc_contract_definitions cd, + jsonb_array_elements(cd.assets_selector::jsonb) elems + WHERE elems ->> 'operandLeft' = 'asset:prop:id' + GROUP BY cd.contract_definition_id) co +WHERE edc_contract_definitions.contract_definition_id = co.contract_definition_id; + +drop function if exists migrate_json(criteria_json_array_element jsonb); + +-- Transfer Processes +alter table edc_transfer_process rename column transferprocess_properties to private_properties; +alter table edc_transfer_process add column callback_addresses json; + +-- Data Request +alter table edc_data_request drop column if exists managed_resources; +alter table edc_data_request drop column if exists properties; +alter table edc_data_request drop column if exists transfer_type; diff --git a/extensions/postgres-flyway/src/main/resources/migration/provider/V1__m8-provider-sample-data.sql b/extensions/postgres-flyway/src/main/resources/migration/provider/V1__m8-provider-sample-data.sql new file mode 100644 index 000000000..18899e7e2 --- /dev/null +++ b/extensions/postgres-flyway/src/main/resources/migration/provider/V1__m8-provider-sample-data.sql @@ -0,0 +1,404 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 11.20 +-- Dumped by pg_dump version 11.20 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Data for Name: edc_asset; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_asset (asset_id, created_at) VALUES ('urn:artifact:test:1.0', 1687179246852); + + +-- +-- Data for Name: edc_asset_dataaddress; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_asset_dataaddress (asset_id_fk, properties) VALUES ('urn:artifact:test:1.0', '{"baseUrl":"https://google.de","method":"GET","type":"HttpData"}'); + + +-- +-- Data for Name: edc_asset_property; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:curatorOrganizationName', 'Example GmbH', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'http://w3id.org/mds#transportMode', 'Road', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:contenttype', 'application/json', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:version', '1.0', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'http://w3id.org/mds#geoReferenceMethod', 'Geo reference method', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:id', 'urn:artifact:test:1.0', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'http://w3id.org/mds#dataModel', 'Data Model', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'http://w3id.org/mds#dataSubcategory', 'Accidents', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:language', 'https://w3id.org/idsa/code/EN', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:keywords', 'keyword1, keyword2', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:name', 'test', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:description', 'My Asset Description', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'http://w3id.org/mds#dataCategory', 'Traffic Information', 'java.lang.String'); +INSERT INTO public.edc_asset_property (asset_id_fk, property_name, property_value, property_type) VALUES ('urn:artifact:test:1.0', 'asset:prop:originator', 'http://edc:11003/api/v1/ids/data', 'java.lang.String'); + + +-- +-- Data for Name: edc_contract_agreement; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_contract_agreement (agr_id, provider_agent_id, consumer_agent_id, signing_date, start_date, end_date, asset_id, policy) VALUES ('test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', 'urn:connector:provider', 'urn:connector:consumer', 1687179323, 1687179321, 1718715321, 'urn:artifact:test:1.0', '{"permissions":[{"edctype":"dataspaceconnector:permission","uid":null,"target":"urn:artifact:test:1.0","action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2022-05-31T22:00:00.000Z"},"operator":"GEQ"},{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2030-06-30T22:00:00.000Z"},"operator":"LT"}],"duties":[]}],"prohibitions":[],"obligations":[],"extensibleProperties":{},"inheritsFrom":null,"assigner":null,"assignee":null,"target":"urn:artifact:test:1.0","@type":{"@policytype":"set"}}'); + + +-- +-- Data for Name: edc_contract_definitions; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_contract_definitions (contract_definition_id, access_policy_id, contract_policy_id, selector_expression, created_at, validity) VALUES ('test-contract-definition', 'test-policy', 'test-policy', '{"criteria":[{"operandLeft":"asset:prop:id","operator":"in","operandRight":["urn:artifact:test:1.0"]}]}', 1687179311116, 31536000); + + +-- +-- Data for Name: edc_lease; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179352120, 60000, 'cc05bbad-f14c-4535-a7d3-b325abdeb880'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179374498, 60000, '7dd7fcd3-1a16-45cd-adbb-cd9ee0c29179'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179377748, 60000, 'd84fdcbc-68e2-45e7-abfb-08a934bfc7bf'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179412585, 60000, 'e4090d26-e4ad-4904-a607-f09ac0ead113'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179434938, 60000, '6c827ac6-b2d9-421a-9fb7-2aee912f6201'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179438139, 60000, '61f5cbe0-3e5f-47e5-b380-6d38e837dd41'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179472614, 60000, 'a54e77c3-d4f5-4e1e-95d2-ecf20b35690b'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179495026, 60000, 'e74d448a-01c1-43a1-8a29-317c9df02f6f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179498197, 60000, 'dfbfa882-4a3f-40e9-877e-1df0eb5c7f52'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179533325, 60000, '75828490-2941-46f5-8212-6c426a50f3fc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179555885, 60000, '53161b93-9908-4706-b700-8f7d71d7ec7f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179559131, 60000, '3b06890f-a8df-4e37-a7f7-2b5553bad295'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179594147, 60000, 'a9fc8e45-9fe6-4ae8-a8b5-02ec77cf604d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179616551, 60000, '09c682c7-9da5-4cdd-8302-130959c5cbfb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179619718, 60000, 'e926b88d-10fc-4208-88ee-7d7515c99b5e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179654778, 60000, '209bbc07-342e-4e8d-92d0-5fbce1c84d77'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179677075, 60000, '7504587d-8285-4974-af25-a520b85ea898'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179680194, 60000, 'f3918081-7f1f-4950-aff9-d9ffb1307c10'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179715560, 60000, 'b5318c29-e20a-4b2c-a3e9-51a2d6832154'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179737964, 60000, 'ef69129c-7421-4f59-9acf-3e4a16ed43dd'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179741122, 60000, 'ebb79f3f-60e9-4d9f-99ec-23540152aa2d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179776223, 60000, '93da0650-2fcc-4b9b-b3e3-548b99f62ed2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179798729, 60000, 'f9db359a-5c65-4819-aa10-bcf80197cfac'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179801954, 60000, 'af11e842-653f-439c-a087-aec85f52d200'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179837172, 60000, '65639e3b-a249-4744-8a33-43e3edb0f7da'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179859314, 60000, '019f5064-ca7f-4e81-ac04-feddfe1ac98f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179862523, 60000, '01eb0eed-ba15-49cd-ac0a-1a7f3246552b'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179897822, 60000, '29381279-a53b-4421-8451-5efbce0bf4af'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179920182, 60000, '8f9938fd-bb6d-4e81-b4a5-df7f1647b1f9'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179923415, 60000, '223b7c40-16f7-4f81-acb0-3b5167d29659'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179958133, 60000, '7f6cb370-e648-4a04-8edd-86becbefbfea'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179980534, 60000, 'f5f532f5-c864-4c1f-b85a-3b36ba6d7008'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687179983684, 60000, 'ba660240-15b9-48b0-94bf-3ea7fbb7f309'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180019074, 60000, '0fd58bb1-db83-4441-9534-e4d1fa92dfb2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180040609, 60000, '8beae9c7-fff0-4c48-92f9-3d39315d67fc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180043862, 60000, '9f3a47d8-e5d6-40b1-9fa5-1044e71bbec6'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180079144, 60000, 'e4a1a0f3-89e1-4efd-8333-6b153da040d7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180101647, 60000, 'f4fcbbfd-5d8e-42c6-90be-01504e96207b'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180104810, 60000, '68de6bdc-f9aa-4740-adfc-6f512800e031'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180139966, 60000, 'ddd6c3be-8f7a-4cfa-a53e-08edbe9ee9f5'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180162424, 60000, '6c26804e-89b4-4bb9-a95f-ed0df36d46ce'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180165637, 60000, 'b93a1fb8-5f0e-4bc1-be13-cc47e6a08f6d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180200875, 60000, '5422709b-3ee9-44c8-9cfa-0786743324fc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180223066, 60000, 'faab9989-9545-4ac1-917d-e5af6e1e8ed9'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180226243, 60000, '893ba877-118d-4743-8a6d-f49a00dc723a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180261393, 60000, '3c384b59-0de2-4e4d-ac09-0596f1018c36'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180283934, 60000, '3819508d-f9d6-4119-92ad-d0d242699f74'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180287024, 60000, '9fb0d809-96e9-4c90-8bb2-5fdcfbd5ff7e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180322044, 60000, '71288bb2-d807-40e3-9a54-24b963bf28d3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180344513, 60000, 'f64e3905-3ffa-48aa-a475-54d15cd6d0af'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180347674, 60000, '4fea3add-22da-4b6d-b57d-d9566b88f234'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180382939, 60000, 'd331b297-74e3-4d9d-8f68-7852ee686686'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180405294, 60000, '5241855c-df67-4c2d-9df1-fed3fbe0f39a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180408544, 60000, '326305d5-bc29-4887-9b38-7e7a2efee0e8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180443640, 60000, 'e2e17ec8-c121-4b9d-88c6-5405d3cf752c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180466104, 60000, '4bb5a85a-16c1-4c7b-8dfa-24949fdc5994'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180469364, 60000, '7673b3ff-4018-4008-8bb6-f5a661256b3f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180504209, 60000, 'a476eae2-e4b9-4f0d-8b1d-dccad5b0ac85'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180526375, 60000, 'e768c175-abc4-40f2-9545-72ecbb1bba7e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180529584, 60000, '3b7a35ca-8ec1-4404-af1a-e6a4a981b0d9'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180565005, 60000, '7bd28e19-7331-4c51-8f9a-dc7083e939ab'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180586758, 60000, 'b453ff25-d2c6-4982-b7dd-3cf41b6106e2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180590096, 60000, 'b4b1c00f-06ac-486b-8db0-4ffe5e2469a0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180625486, 60000, '9be3fe6b-764e-4005-bcc3-58cde79e7f5c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180647030, 60000, 'bdee315a-4e85-450b-91ef-83e2591060ca'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180650199, 60000, 'c9232ae4-f951-4308-93d8-10f52a6573a2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180686536, 60000, '716d548c-29f9-4476-83aa-612e76740fd2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180708099, 60000, '905d211c-dab3-4ac5-a4dc-454c8fc6a1ca'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180710230, 60000, '3649c9c0-7c85-41c0-86c7-977f86c21ae7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180746644, 60000, 'c9d311d4-2fff-4af6-be74-022208085e82'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180768212, 60000, '0a8b39ad-12ae-41c8-b8c6-e0d941c6a5e3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180770344, 60000, '53c97ca2-f986-42f3-b101-b15d363a89b3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180807634, 60000, 'a029840e-3973-4b35-95ce-3817a4b8f5b8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180828893, 60000, '6c409fd1-502f-4634-98ff-37e5aa2d9b0d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180831076, 60000, 'c69bd663-7f72-4efd-adcc-6a00b1be0b4d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180868087, 60000, 'f1a03536-8293-49c9-a1ec-9f5f8150e859'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180889435, 60000, '37928944-ef9d-4bfb-a52e-af6c6454d874'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180891555, 60000, '8c432e4a-f3c1-4a9a-b4e4-8515efa3744f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180928629, 60000, '6e75a714-0730-403a-a3b3-aae259585404'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180949884, 60000, '1fcb040d-23b2-415c-88e5-b64e37b160bb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180951992, 60000, '967f1e32-4355-4b13-b069-acb35e9493a9'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687180989214, 60000, 'bc575250-b9c3-43d4-891d-e23705f1567c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181010604, 60000, '2f6c78f5-2aa1-4d3b-9759-b46d67e468c6'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181012754, 60000, '07acacbc-3a8e-49d2-bbd0-4bd044931403'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181050094, 60000, '43105eed-bbd2-4db4-8987-b25adbc56dba'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181071404, 60000, 'e03e451c-8311-4922-8ce6-25a0b945ee01'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181073514, 60000, '69e7c627-f4af-44b9-b73e-bc0974eab8a4'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181110850, 60000, 'ee669b0f-9cb2-4ec4-b4c2-dc938da466ef'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181131938, 60000, 'bbb95833-9b7d-40fc-a09e-d86963abe80d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181134045, 60000, 'ca21cba9-7983-46f6-a4c0-bf46643292c7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181171637, 60000, '2753fada-69f9-4e1b-9512-a6d3335ae813'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181192091, 60000, '2c6e2c52-cc35-41d2-a9ae-8f35fa9adeb4'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181194276, 60000, '0190886c-2e97-4fc8-a23c-519706de6757'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181231744, 60000, '307df5b3-4cc6-4f51-9894-431185f7213a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181253077, 60000, '45e7eec2-782d-4fd1-8785-7693ca0c0ca3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181255213, 60000, 'c3faae35-40be-447e-93e5-6497f433bf3d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181292404, 60000, 'c1d74e18-faaa-4a5a-bfe0-8ad91acffefd'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181313854, 60000, '7bdd595c-2e75-4883-bf32-058645ac3e6e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181316130, 60000, '3521e77f-dfc7-4e4d-95c4-70875ef28d53'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181352420, 60000, '968d8ee7-3467-4d13-9ab6-ea90762e298e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181374024, 60000, 'ade80af1-3475-4736-95e1-802077b33ae6'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181376234, 60000, 'db35b302-9b57-4a12-9325-1da7e9bc2c7a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181412474, 60000, 'a599d165-1ec0-4c35-9b1e-beae9bc13c75'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181434814, 60000, '08aa45c8-9558-4b59-b2c9-d92b70bc4b43'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181437003, 60000, '3ecb3c96-8dd1-48e1-bdf9-72dce3d04551'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181473392, 60000, '3281a8d3-2350-4789-ab70-fc330103efbc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181495705, 60000, '03593af5-d8da-41c9-9288-cbee86de2c3f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181497882, 60000, 'b4776d26-7706-4802-b94a-9df8ead31cdb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181534375, 60000, '7ba3193c-0421-4f2b-b632-8ea75dfb113a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181556094, 60000, '1de79c66-681a-4d28-ab87-b51034d222f4'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181558177, 60000, '1b206786-28cf-49c1-91af-f8cc47b956f0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181594591, 60000, '98322b9d-6196-4db7-8217-29d61be89e19'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181616157, 60000, '8a1c71a1-1300-4dbd-994a-d165d80bfdc5'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181618363, 60000, 'b8d51f56-5bc9-4c3e-9551-413c17dcb214'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181654934, 60000, '46581dc9-3300-469f-83ce-7891da5f5efb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181676335, 60000, '1089f76a-e508-422b-bcbf-9512e07dd8b2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181678463, 60000, '4e5c2df5-0a52-4c16-93fb-b22a7b411d90'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181714955, 60000, '62108594-12d4-4071-a05b-6e861a0c4eb6'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181736647, 60000, 'f694ee5a-99d7-45f5-8063-76de9d6afea5'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181738751, 60000, 'a47bf45c-c83b-451f-9ccd-3f5634fd8a2c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181775364, 60000, 'e7e6089e-dfbf-4505-9253-4577717f9b76'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181796876, 60000, '1fbb5b0c-c0c4-4469-b5b0-03cb3252dc47'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181799091, 60000, '4146e90b-1524-4e6d-9fd4-43e13f5e7204'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181835414, 60000, 'f3a9b320-014a-4720-acb6-25715cec6b17'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181856924, 60000, 'c86c138a-b602-47fb-97fc-0b742ec16da4'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181860153, 60000, 'd304a163-b051-48e7-8f75-e845ca95c54b'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181895677, 60000, '800f444d-8a50-4065-9c7b-0885bf010da7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181918023, 60000, '4ce94eea-4d18-436f-a834-d450b4bbc283'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181920175, 60000, 'f4ca2036-98ec-4885-bf30-a1fcb595b4e0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181956408, 60000, '7c1f8eea-fe36-4931-9b6d-3ae162053c46'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181978516, 60000, '1e033b4d-ae82-4058-9f02-b70a564fd1f0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687181980708, 60000, '2d09e2dd-490a-43af-845e-62edd7dddc8e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182016708, 60000, '684d6660-d93c-4653-adfc-832c12c83a7e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182039262, 60000, '0e946393-c191-4039-8ac0-6e42d40c72da'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182041384, 60000, 'efd8ae2a-ca14-41df-bee2-7f15aa9488a0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182076894, 60000, '95de2fe7-8164-41c9-a180-25c85efa5acd'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182099343, 60000, '6601b27c-2b04-44f0-b560-1b07f2cc0e1d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182101544, 60000, '7b996473-3d74-4d66-9d58-db9ef4c4dc5e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182137711, 60000, '305c012b-3cc1-4386-9fcd-b97eaf9ebead'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182160312, 60000, '6bfce472-a5db-4e6b-86ae-3feb34f76567'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182162464, 60000, '8697149d-a476-4161-9a05-527320818e5a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182197801, 60000, '92f17be2-3878-4a32-a3f0-138249de4b96'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182220328, 60000, '4bec86d3-bb76-4810-b442-d7458034c93a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182222535, 60000, '3b8f9394-5a52-4db4-b301-b5a794f25ebe'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182258165, 60000, 'de8dc27d-cc7e-4afd-8155-04c1e5ccef77'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182280723, 60000, '01a3287e-8629-4bd7-bab8-7e9a53ac3f7a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182282912, 60000, '5634a87d-c942-4425-b20e-0761ead0c5fb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182319180, 60000, 'e4b87f47-f820-41cc-8f65-90e26db071e7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182341697, 60000, 'aafb44dc-f6d4-45b5-a7dc-e46f5ed678c2'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182343912, 60000, 'e4369e55-9142-4a2e-8600-c562a00d2a62'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182379505, 60000, '9acfb1cb-0a64-4650-a7a6-08b9bbe88b47'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182401988, 60000, '99891d67-8ecc-4553-9da9-bd21dc038f75'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182404188, 60000, 'dda72386-8c98-453c-bccd-956d60779be7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182439676, 60000, 'c391dc7f-cef0-4198-8e86-8ac960da5b62'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182462236, 60000, 'ee005d92-7679-4c06-a48a-d6d8bb2e0bf9'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182464444, 60000, '71f70b6e-b316-4216-bca9-2fc414e7af0c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182499915, 60000, '447a3db4-875f-4093-bd85-68bf8d004c3c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182522319, 60000, 'e645f660-5d00-4f4d-9a1b-172e948b0c44'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182524474, 60000, '78217435-0163-445b-9418-8ba64b416e5f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182560006, 60000, '25a9189f-dec0-48e2-8ba5-24bf28ab8450'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182582519, 60000, 'a5b63cf8-14ed-46d8-8751-63c0bb6af098'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182584702, 60000, '9b921107-567e-4f60-8db1-4d3e4d735329'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182620076, 60000, '760fe7db-5224-4abb-b68e-70e65f6370b5'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182642625, 60000, '67d78294-52f4-499b-a852-4039324c727c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182644854, 60000, '952fda3a-ae3e-442c-b1d9-b846034fca2f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182680277, 60000, 'e0a7b08f-66e9-42cd-ae2f-7332749601a7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182703045, 60000, 'f383bd87-60c7-4180-afe1-f9c2dc50c108'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182705209, 60000, 'c2985f79-df57-4de6-9773-329999a5951a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182740544, 60000, 'e422687d-efd5-4b1e-8974-99259e9f4ce6'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182763120, 60000, 'cf7e33e0-ae45-47c3-a370-9062068040e3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182765299, 60000, '6f87df60-dfec-4caa-96c6-365cd9dc4533'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182801495, 60000, '02fd444e-f20c-4f53-8f86-e164749bd18b'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182824174, 60000, '72642ec8-0adf-4ecd-99de-53fa94bf8ff1'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182826204, 60000, 'c61f7113-40a6-46d7-84cf-24124de5a636'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182861548, 60000, '65e682f2-176e-442d-a4bc-6bbd69dc17ca'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182884225, 60000, 'da439836-8337-4665-8a14-042533cd986c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182886285, 60000, 'da6031a0-f4eb-485c-aa99-7354f5f199fa'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182921823, 60000, '5bdbee09-9b39-4a35-a73f-65220f16cd60'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182944532, 60000, 'ff6f4ea7-8cfd-4dea-81e4-14b3ff3f1194'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182946732, 60000, '66cf8e54-5606-4bdf-9e29-0e611083de63'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687182982384, 60000, '57fa9220-6233-414e-b295-0d7876683977'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183004894, 60000, '1036c606-523c-47cb-9747-8c0f00528bda'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183007072, 60000, 'b02b25f4-32c5-4d5a-8493-2d4a9ccb13c0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183043316, 60000, '4dd73b47-97aa-4781-8fde-26123c7fcbfb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183064904, 60000, '6d7adb44-eedd-4508-bb53-a72ac99de97d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183067087, 60000, '3d6236ad-b863-481d-a681-d7e29ea99421'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183104083, 60000, 'e56e2a4b-1ea9-4333-ae47-68229b51a0bf'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183125484, 60000, 'f9ad6d7b-664e-4b94-a4f3-91b9f5b63966'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183127696, 60000, '6a69c200-1c72-4143-a2a1-1b9a5fc42400'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183164634, 60000, 'c430300f-ed20-4d28-a65c-d00c0959822a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183186072, 60000, 'bcd32459-4fed-4360-9c49-ad94a4391e49'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183188224, 60000, '5507b772-e59f-47db-b89e-62962710c7c0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183225674, 60000, '76fdba32-a73d-4a1d-b5fe-101b6ae9ac1a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183247005, 60000, '303161db-2ac8-4a20-8e9d-12ec20915322'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183249086, 60000, '8a062d22-cb62-4529-8622-7a4e1e81f466'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183286358, 60000, 'da4afb4a-8322-4512-89bb-f3da65964b2d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183307538, 60000, '8921f601-9fe3-452c-bc9a-ae1439ec32dd'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183309663, 60000, '74f0a76b-7536-40b3-a7c4-d188bee2a795'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183346399, 60000, 'a1643e36-8a9b-4825-a060-7715459184cd'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183367596, 60000, '0a6fb455-03d9-41c8-97a0-74957f167492'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183369669, 60000, '374e9415-0edb-4901-801a-9cce2194ba3c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183407016, 60000, 'e1a1c867-9c9b-43a0-8747-23f396bab81e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183428584, 60000, 'b59951fb-01ec-469e-9943-4a06bd7fd679'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183430670, 60000, 'dd247d2e-5e2c-4c41-8c73-8255f9732ce8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183467094, 60000, '42a4d62f-063b-4f3f-9f2f-e716d223bec8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183489534, 60000, '8c749058-5d74-4bc1-865a-115fb47fa407'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183491634, 60000, 'edea183f-ca9a-41fb-ab28-4a318d517112'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183528154, 60000, '3f8fa237-beae-4c2a-8d44-a5c6dca80123'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183549679, 60000, '799c8dd3-4e74-4572-bd45-0c139a31b649'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183551733, 60000, 'f70e7eee-1ff2-4b5f-92ce-2cf089d9e5bc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183588953, 60000, '84a5e1e1-6ff1-4d3a-85b2-608271f2e41e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183610504, 60000, '91e5c30b-5cf4-44e5-818a-d4eddd4ddb8a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183612704, 60000, '23d04061-4023-4913-aae7-40e95a08359a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183649263, 60000, 'e4e31f6e-d09a-46bb-af8c-86aab4d707bc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183670787, 60000, 'f3e20ef5-8c0f-4781-810e-be55cb2295c0'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183672903, 60000, 'ca54a548-e3a0-46a4-b1a9-6f891c35d33e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183710311, 60000, '7c3ab765-d195-4827-8c7f-cb2f73d517df'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183731638, 60000, '2941b143-6b42-4edc-88a5-b0f919a8dca3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183733780, 60000, 'b6d6ee6d-202a-4886-8922-bb750f152b10'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183770575, 60000, '9fae1dad-9236-491e-8776-c0c7ccc59f50'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183792109, 60000, 'bb52e40a-8927-4670-b6f6-a553507a14fe'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183794273, 60000, '18d7704f-76cc-4cc9-881a-44b8a66b65dc'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183830956, 60000, '45a471de-3ee7-41da-92c5-118a9902093c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183852617, 60000, 'df281038-8d9d-480c-afd5-1206d1898431'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183854791, 60000, '8a2fc43a-26f6-4c5c-b5f1-607eb20b4e68'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183891351, 60000, 'f0154f7b-4de6-42c2-bc8f-f18a2929ccec'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183912927, 60000, '66def1d2-1867-45f6-b840-7ddb48690d3a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183915132, 60000, 'cbfb4bbf-c143-49be-9341-ab8dde4863bb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183951526, 60000, '8be9be22-c342-4295-8775-1675c413609c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183973112, 60000, '970e6389-69ec-49d8-bbda-f06fc2ccb115'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687183975249, 60000, '3ab68bf0-d108-4369-afdc-2c213b118151'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184012378, 60000, '254e5c8b-ba28-4335-b97d-4cd148fc72af'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184033690, 60000, '39e60cf5-3f29-4059-a4ac-ead7b015cffb'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184035854, 60000, '0ae08eb5-0fc6-4d06-b656-402989ab0739'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184073404, 60000, '0aab1825-dfb3-4d8f-b200-835f053dee5d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184093946, 60000, 'c615a5f7-91de-4956-805e-10b64e80137d'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184096144, 60000, 'f9194643-4c63-482c-90d3-26aafada35b7'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184133784, 60000, '4ea532b8-ad67-456e-b87c-1f1418757c7e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184154219, 60000, 'ac43cf83-afcb-4bab-bd41-2601f49e5840'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184156384, 60000, '01d9c4e6-5b3a-428e-be21-83d71efd0c39'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184194099, 60000, '9f538886-8550-4532-9af1-d4dcb27a9d21'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184214346, 60000, '827bd6a7-88b2-4c77-b3d7-ec7275f9b593'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184216443, 60000, '8da8344c-4b14-467c-bb12-6cccea708f66'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184254117, 60000, 'b1fb567e-09eb-4e64-bc41-86f14e375e4f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184274677, 60000, 'c7c557b3-15ed-406b-9c50-03a7b66a3110'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184276812, 60000, 'de7eab16-c52e-4b7d-9f72-89ba6ac4f60c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184314324, 60000, 'f575d40e-6d99-48fa-9ea3-499e7f66d8e8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184335694, 60000, '2cac624e-6667-4e88-8c83-6474464a0c57'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184337826, 60000, '76de1061-66dc-400c-9d2b-da038951e316'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184374477, 60000, 'a953bf98-02cb-4a0d-ba09-c5b2fca6ff39'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184395987, 60000, 'd52eb52f-2ccd-45b0-b289-bfb7d3784324'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184398075, 60000, '30de81e3-288f-4748-a2e9-745e7c7643ff'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184434803, 60000, '8df5b27c-a083-45c5-ac27-6599c5d98de1'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184456216, 60000, '0d952261-23d9-4e52-bee9-5682dae84004'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184458392, 60000, '14966161-5c5d-41c6-9d4b-a27daacb0bf8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184495143, 60000, '7e4f337c-3a10-4057-8dae-79206dd5ba51'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184516619, 60000, 'f19a02f2-74a7-4f51-beeb-66371f92a00b'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184518746, 60000, '1c13664e-0495-4cd2-99eb-f1e7b58b9bc8'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184555671, 60000, '462a3b62-7096-4095-987d-d401d5230867'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184577533, 60000, '5cea4ccb-9a81-4cf1-936c-7e3a8bc3f53c'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184579686, 60000, '4dcfbf50-c0db-4801-b27c-f179053a7d86'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184616224, 60000, '1f2fd751-ce1a-4c87-8050-6f98c80e6fa3'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184637864, 60000, 'a356e971-77c4-49d0-9398-07d6c1b7a39a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184639984, 60000, '53c93dea-ecdb-4d59-b088-e6c398324824'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184676406, 60000, '5c7efe1b-48f6-499b-a62a-fdde37879942'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184697880, 60000, '3084b1e5-7723-491c-abbe-8519cc132523'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184700142, 60000, '26cee2a3-bc4c-4233-8eab-5b19a096bf35'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184736693, 60000, 'a3000b47-0e3a-4139-8c46-3dab4931b8af'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184757988, 60000, '7f8e39e4-d22d-42e6-833c-f3f7902aad8e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184760157, 60000, 'fb655394-63e2-4538-8e7c-cc6566867b04'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184796885, 60000, 'db22c02a-c599-4568-93da-10b89ef329da'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184818453, 60000, 'e4ae2470-76e8-46c1-9271-04130f659acd'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184820583, 60000, '8f5d3b74-25ba-4a4b-ba65-28a823048c82'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184857031, 60000, 'eecbf973-4e04-47d5-becc-843332d8326a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184879395, 60000, 'be750e5e-0d68-4a93-b06d-f8f62a8f3c5f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184881506, 60000, '815667f6-2199-447a-b735-c4b294e8900a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184917905, 60000, '26038ab7-5c1d-4fc4-86ae-a58047a4002f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184939464, 60000, 'b6291957-bccf-4959-bcfb-0344c9282a8a'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184941664, 60000, 'a688058f-37fd-46df-a78b-ca76951f1520'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687184978595, 60000, '0a76dfa1-97e8-41e6-8c19-b4c38e19aa71'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185000164, 60000, 'ee283f1a-c440-49c7-ba57-2da12edc7a5e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185002331, 60000, '22865691-2e38-49fc-a603-c508aae540c5'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185038763, 60000, 'bb377646-af8d-4964-bb4a-66e841825fe5'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185060453, 60000, '97f8e4f0-4c6e-44bc-8724-907d7d5bc985'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185062687, 60000, 'a3201ec9-9913-41e2-8a3a-1fa934e3e78e'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185099324, 60000, 'c56e6cce-54b0-4ed9-ab4c-318dce3e9193'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185120937, 60000, '1e512206-84d7-4a19-8d5c-532e0b95e52f'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185123056, 60000, '273927e8-a242-4027-a5e6-00b0abde3526'); +INSERT INTO public.edc_lease (leased_by, leased_at, lease_duration, lease_id) VALUES ('example-connector', 1687185159511, 60000, '7a2d4bd5-1493-40c0-8624-abbf096cf9fe'); + + +-- +-- Data for Name: edc_contract_negotiation; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_contract_negotiation (id, correlation_id, counterparty_id, counterparty_address, protocol, type, state, state_count, state_timestamp, error_detail, agreement_id, contract_offers, trace_context, lease_id, created_at, updated_at) VALUES ('a2edd577-845a-4ccd-967f-21858aaaf245', '6ae57214-b6ea-42b0-adaa-ad64ce6c883c', 'urn:connector:example-connector', 'http://edc2:11003/api/v1/ids/data', 'ids-multipart', 1, 1200, 1, 1687179323478, NULL, 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '[{"id":"test-contract-definition:bda8b77d-07f0-4fcd-a941-4f068b71f574","policy":{"permissions":[{"edctype":"dataspaceconnector:permission","uid":null,"target":"urn:artifact:test:1.0","action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2022-05-31T22:00:00.000Z"},"operator":"GEQ"},{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2030-06-30T22:00:00.000Z"},"operator":"LT"}],"duties":[]}],"prohibitions":[],"obligations":[],"extensibleProperties":{},"inheritsFrom":null,"assigner":null,"assignee":null,"target":"urn:artifact:test:1.0","@type":{"@policytype":"set"}},"asset":{"id":"urn:artifact:test:1.0","createdAt":1687179246852,"properties":{"asset:prop:curatorOrganizationName":"Example GmbH","http://w3id.org/mds#transportMode":"Road","asset:prop:contenttype":"application/json","asset:prop:version":"1.0","http://w3id.org/mds#geoReferenceMethod":"Geo reference method","asset:prop:id":"urn:artifact:test:1.0","http://w3id.org/mds#dataModel":"Data Model","http://w3id.org/mds#dataSubcategory":"Accidents","asset:prop:language":"https://w3id.org/idsa/code/EN","asset:prop:keywords":"keyword1, keyword2","asset:prop:name":"test","asset:prop:description":"My Asset Description","http://w3id.org/mds#dataCategory":"Traffic Information","asset:prop:originator":"http://edc:11003/api/v1/ids/data"}},"provider":"urn:connector:provider","consumer":"urn:connector:consumer","offerStart":null,"offerEnd":null,"contractStart":"2023-06-19T12:55:21.833Z","contractEnd":"2024-06-18T12:55:21.833Z"}]', '{}', NULL, 1687179322690, 1687179323478); + + +-- +-- Data for Name: edc_data_plane_instance; Type: TABLE DATA; Schema: public; Owner: edc +-- + + + +-- +-- Data for Name: edc_transfer_process; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_transfer_process (transferprocess_id, type, state, state_count, state_time_stamp, created_at, trace_context, error_detail, resource_manifest, provisioned_resource_set, content_data_address, deprovisioned_resources, lease_id, updated_at, transferprocess_properties) VALUES ('398ece7e-3c60-4766-a392-4e950f0bbf5a', 'PROVIDER', 600, 1, 1687179374487, 1687179373706, '{}', NULL, '{"definitions":[]}', NULL, '{"properties":{"baseUrl":"https://google.de","method":"GET","type":"HttpData"}}', '[]', '1e512206-84d7-4a19-8d5c-532e0b95e52f', 1687179374487, '{}'); +INSERT INTO public.edc_transfer_process (transferprocess_id, type, state, state_count, state_time_stamp, created_at, trace_context, error_detail, resource_manifest, provisioned_resource_set, content_data_address, deprovisioned_resources, lease_id, updated_at, transferprocess_properties) VALUES ('7d85d66a-b755-4a10-9a15-c94719913d42', 'PROVIDER', 600, 1, 1687179377740, 1687179377033, '{}', NULL, '{"definitions":[]}', NULL, '{"properties":{"baseUrl":"https://google.de","method":"GET","type":"HttpData"}}', '[]', '273927e8-a242-4027-a5e6-00b0abde3526', 1687179377740, '{}'); +INSERT INTO public.edc_transfer_process (transferprocess_id, type, state, state_count, state_time_stamp, created_at, trace_context, error_detail, resource_manifest, provisioned_resource_set, content_data_address, deprovisioned_resources, lease_id, updated_at, transferprocess_properties) VALUES ('679b517e-dbaa-4e07-a1c6-9b8ec5d4fe1d', 'PROVIDER', 600, 1, 1687179352109, 1687179351221, '{}', NULL, '{"definitions":[]}', NULL, '{"properties":{"baseUrl":"https://google.de","method":"GET","type":"HttpData"}}', '[]', '7a2d4bd5-1493-40c0-8624-abbf096cf9fe', 1687179352109, '{}'); + + +-- +-- Data for Name: edc_data_request; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_data_request (datarequest_id, process_id, connector_address, protocol, connector_id, asset_id, contract_id, data_destination, managed_resources, properties, transfer_type, transfer_process_id) VALUES ('e213fc10-f61a-4aa0-80f8-7c581651f543', '679b517e-dbaa-4e07-a1c6-9b8ec5d4fe1d', 'http://edc2:11003/api/v1/ids/data', 'ids-multipart', 'urn:connector:example-connector', 'urn:artifact:test:1.0', 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '{"properties":{"baseUrl":"https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a","method":"POST","type":"HttpData"}}', true, '{}', '{"contentType":"application/octet-stream","isFinite":true}', '679b517e-dbaa-4e07-a1c6-9b8ec5d4fe1d'); +INSERT INTO public.edc_data_request (datarequest_id, process_id, connector_address, protocol, connector_id, asset_id, contract_id, data_destination, managed_resources, properties, transfer_type, transfer_process_id) VALUES ('34b587d1-9a1a-4bc2-a499-24a0e6975b97', '398ece7e-3c60-4766-a392-4e950f0bbf5a', 'http://edc2:11003/api/v1/ids/data', 'ids-multipart', 'urn:connector:example-connector', 'urn:artifact:test:1.0', 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '{"properties":{"baseUrl":"https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a","method":"POST","type":"HttpData"}}', true, '{}', '{"contentType":"application/octet-stream","isFinite":true}', '398ece7e-3c60-4766-a392-4e950f0bbf5a'); +INSERT INTO public.edc_data_request (datarequest_id, process_id, connector_address, protocol, connector_id, asset_id, contract_id, data_destination, managed_resources, properties, transfer_type, transfer_process_id) VALUES ('5e4cb5c8-fc8e-4231-ba86-bc5dbf7b5015', '7d85d66a-b755-4a10-9a15-c94719913d42', 'http://edc2:11003/api/v1/ids/data', 'ids-multipart', 'urn:connector:example-connector', 'urn:artifact:test:1.0', 'test-contract-definition:2160b70f-d65e-4861-af88-f29b16f3fa7b', '{"properties":{"baseUrl":"https://webhook.site/e542f69e-ff0a-4771-af18-0900a399137a","method":"POST","type":"HttpData"}}', true, '{}', '{"contentType":"application/octet-stream","isFinite":true}', '7d85d66a-b755-4a10-9a15-c94719913d42'); + + +-- +-- Data for Name: edc_policydefinitions; Type: TABLE DATA; Schema: public; Owner: edc +-- + +INSERT INTO public.edc_policydefinitions (policy_id, permissions, prohibitions, duties, extensible_properties, inherits_from, assigner, assignee, target, policy_type, created_at) VALUES ('always-true', '[{"edctype":"dataspaceconnector:permission","uid":null,"target":null,"action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"ALWAYS_TRUE"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"true"},"operator":"EQ"}],"duties":[]}]', '[]', '[]', '{}', NULL, NULL, NULL, NULL, '{"@policytype":"set"}', 1687179132836); +INSERT INTO public.edc_policydefinitions (policy_id, permissions, prohibitions, duties, extensible_properties, inherits_from, assigner, assignee, target, policy_type, created_at) VALUES ('test-policy', '[{"edctype":"dataspaceconnector:permission","uid":null,"target":null,"action":{"type":"USE","includedIn":null,"constraint":null},"assignee":null,"assigner":null,"constraints":[{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2022-05-31T22:00:00.000Z"},"operator":"GEQ"},{"edctype":"AtomicConstraint","leftExpression":{"edctype":"dataspaceconnector:literalexpression","value":"POLICY_EVALUATION_TIME"},"rightExpression":{"edctype":"dataspaceconnector:literalexpression","value":"2030-06-30T22:00:00.000Z"},"operator":"LT"}],"duties":[]}]', '[]', '[]', '{}', NULL, NULL, NULL, NULL, '{"@policytype":"set"}', 1687179288561); + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/extensions/wrapper/client-example/src/main/resources/application.properties b/extensions/wrapper/client-example/src/main/resources/application.properties index ce096eb34..f7abcc5bf 100644 --- a/extensions/wrapper/client-example/src/main/resources/application.properties +++ b/extensions/wrapper/client-example/src/main/resources/application.properties @@ -1,4 +1,17 @@ -client-example.management-api-url=http://localhost:11002/api/v1/management +# +# Copyright (c) 2023 sovity GmbH +# +# 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: +# sovity GmbH - init +# + +client-example.management-api-url=http://localhost:11002/api/management/v2 client-example.management-api-key=ApiKeyDefaultValue client-example.test-connection=true %test.client-example.test-connection=false diff --git a/extensions/wrapper/client-ts/README.md b/extensions/wrapper/client-ts/README.md index 7da1b992f..2983c0be3 100644 --- a/extensions/wrapper/client-ts/README.md +++ b/extensions/wrapper/client-ts/README.md @@ -36,7 +36,7 @@ Configure your EDC Client and use endpoints of our API Wrapper Extension: ```typescript const edcClient: EdcClient = buildEdcClient({ - managementApiUrl: 'http://localhost:11002/api/v1/management', + managementApiUrl: 'http://localhost:11002/api/management/v2', managementApiKey: 'ApiKeyDefaultValue', }); diff --git a/extensions/wrapper/client/README.md b/extensions/wrapper/client/README.md index 0df315685..1ef187817 100644 --- a/extensions/wrapper/client/README.md +++ b/extensions/wrapper/client/README.md @@ -44,7 +44,7 @@ import de.sovity.edc.client.gen.model.KpiResult; */ public class WrapperClientExample { - public static final String CONNECTOR_ENDPOINT = "http://localhost:11002/api/v1/management"; + public static final String CONNECTOR_ENDPOINT = "http://localhost:11002/api/management/v2"; public static final String CONNECTOR_API_KEY = "..."; public static void main(String[] args) { diff --git a/extensions/wrapper/client/build.gradle.kts b/extensions/wrapper/client/build.gradle.kts index 13d642add..4ab600e62 100644 --- a/extensions/wrapper/client/build.gradle.kts +++ b/extensions/wrapper/client/build.gradle.kts @@ -2,6 +2,8 @@ val edcVersion: String by project val edcGroup: String by project val restAssured: String by project val assertj: String by project +val mockitoVersion: String by project +val lombokVersion: String by project plugins { @@ -35,15 +37,19 @@ dependencies { implementation("jakarta.annotation:jakarta.annotation-api:1.3.5") // Lombok - compileOnly("org.projectlombok:lombok:1.18.28") - annotationProcessor("org.projectlombok:lombok:1.18.28") + compileOnly("org.projectlombok:lombok:${lombokVersion}") + annotationProcessor("org.projectlombok:lombok:${lombokVersion}") testImplementation("${edcGroup}:control-plane-core:${edcVersion}") testImplementation("${edcGroup}:junit:${edcVersion}") testImplementation("${edcGroup}:http:${edcVersion}") + testImplementation("${edcGroup}:json-ld-spi:${edcVersion}") + testImplementation("${edcGroup}:dsp-http-spi:${edcVersion}") testImplementation(project(":extensions:wrapper:wrapper")) testImplementation("io.rest-assured:rest-assured:${restAssured}") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") + testImplementation("${edcGroup}:data-plane-selector-core:${edcVersion}") + testImplementation("org.mockito:mockito-core:${mockitoVersion}") testImplementation("org.assertj:assertj-core:${assertj}") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") } diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/ContractAgreementTransferApiServiceTest.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/ContractAgreementTransferApiServiceTest.java index 9b3ada976..899cd03de 100644 --- a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/ContractAgreementTransferApiServiceTest.java +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/ContractAgreementTransferApiServiceTest.java @@ -19,10 +19,15 @@ import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; +import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -31,16 +36,20 @@ import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) class ContractAgreementTransferApiServiceTest { private static final String DATA_SINK = "http://my-data-sink/api/stuff"; - private static final String COUNTER_PARTY_ADDRESS = "http://some-other-connector/api/v1/ids/data"; + private static final String COUNTER_PARTY_ADDRESS = + "http://some-other-connector/api/v1/ids/data"; @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(TestUtils.createConfiguration(Map.of())); } @@ -63,7 +72,7 @@ void startTransferProcessForAgreementId( "type", "HttpData", "baseUrl", DATA_SINK ), - Map.of("some", "prop") + Map.of("privateProperty", "privateValue") ), null ); @@ -72,17 +81,17 @@ void startTransferProcessForAgreementId( var result = client.uiApi().initiateTransfer(request); // then - var transferProcess = transferProcessStore.find(result.getId()); + var transferProcess = transferProcessStore.findById(result.getId()); assertThat(transferProcess).isNotNull(); - assertThat(transferProcess.getProperties()).containsAllEntriesOf(Map.of( - "some", "prop" + assertThat(transferProcess.getPrivateProperties()).containsAllEntriesOf(Map.of( + "privateProperty", "privateValue" )); var dataRequest = transferProcess.getDataRequest(); assertThat(dataRequest.getContractId()).isEqualTo(contractId); assertThat(dataRequest.getConnectorAddress()).isEqualTo(COUNTER_PARTY_ADDRESS); assertThat(dataRequest.getDataDestination().getProperties()).containsAllEntriesOf(Map.of( - "type", "HttpData", + "https://w3id.org/edc/v0.0.1/ns/type", "HttpData", "baseUrl", DATA_SINK )); } @@ -92,23 +101,38 @@ private ContractNegotiation createContractNegotiation( String counterPartyAddress, String agreementId ) { + var assetId = UUID.randomUUID().toString(); var agreement = ContractAgreement.Builder.newInstance() .id(agreementId) - .providerAgentId(UUID.randomUUID().toString()) - .consumerAgentId(UUID.randomUUID().toString()) - .assetId(UUID.randomUUID().toString()) - .policy(Policy.Builder.newInstance().build()) + .providerId(UUID.randomUUID().toString()) + .consumerId(UUID.randomUUID().toString()) + .assetId(assetId) + .policy(getPolicy()) .build(); var negotiation = ContractNegotiation.Builder.newInstance() .id(UUID.randomUUID().toString()) .counterPartyId(UUID.randomUUID().toString()) .counterPartyAddress(counterPartyAddress) - .protocol("protocol") + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) .contractAgreement(agreement) + .contractOffer(createContractOffer(assetId)) + .state(ContractNegotiationStates.FINALIZED.code()) .build(); store.save(negotiation); return negotiation; } + + private Policy getPolicy() { + return Policy.Builder.newInstance().build(); + } + + private ContractOffer createContractOffer(String assetId) { + return ContractOffer.Builder.newInstance() + .id(UUID.randomUUID().toString()) + .assetId(assetId) + .policy(getPolicy()) + .build(); + } } diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java index 316c2508e..c95ec7d96 100644 --- a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/GetTransferProcessAssetApiServiceTest.java @@ -17,8 +17,11 @@ import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.spi.asset.AssetService; import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; +import org.eclipse.edc.spi.types.domain.asset.Asset; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -29,6 +32,7 @@ import static de.sovity.edc.client.TransferProcessTestUtils.createConsumingTransferProcesses; import static de.sovity.edc.client.TransferProcessTestUtils.createProvidingTransferProcesses; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -36,6 +40,8 @@ class GetTransferProcessAssetApiServiceTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(TestUtils.createConfiguration(Map.of())); } @@ -54,7 +60,7 @@ void testProviderTransferProcess(ContractNegotiationStore negotiationStore, //assert assertThat(providerAssetResult.getAssetId()).isEqualTo(TransferProcessTestUtils.VALID_ASSET_ID); - assertThat(providerAssetResult.getProperties().get("asset:prop:name")).isEqualTo(TransferProcessTestUtils.ASSET_NAME); + assertThat(providerAssetResult.getProperties().get(Asset.PROPERTY_NAME)).isEqualTo(TransferProcessTestUtils.ASSET_NAME); } @Test diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java index fc846e7d0..f483e8eba 100644 --- a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferHistoryPageApiServiceTest.java @@ -17,8 +17,10 @@ import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.spi.asset.AssetService; import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -31,6 +33,7 @@ import static de.sovity.edc.client.gen.model.TransferHistoryEntry.DirectionEnum.CONSUMING; import static de.sovity.edc.client.gen.model.TransferHistoryEntry.DirectionEnum.PROVIDING; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -38,6 +41,8 @@ class TransferHistoryPageApiServiceTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(TestUtils.createConfiguration(Map.of())); } diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java index 4f64c790d..6f86b1dd9 100644 --- a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/TransferProcessTestUtils.java @@ -1,13 +1,28 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.client; import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; import org.eclipse.edc.connector.spi.asset.AssetService; import org.eclipse.edc.connector.transfer.spi.store.TransferProcessStore; import org.eclipse.edc.connector.transfer.spi.types.DataRequest; import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; import org.eclipse.edc.spi.types.domain.DataAddress; import org.eclipse.edc.spi.types.domain.asset.Asset; import org.jetbrains.annotations.NotNull; @@ -73,7 +88,7 @@ private static DataAddress getDataAddress() { private static void createAsset(AssetService assetStore, DataAddress dataAddress, String assetId, String assetName) throws ParseException { var asset = Asset.Builder.newInstance() .id(assetId) - .property("asset:prop:name", assetName) + .property(Asset.PROPERTY_NAME, assetName) .createdAt(dateFormatterToLong("2023-06-01")) .build(); @@ -84,15 +99,13 @@ private static ContractAgreement createContractAgreement( String agreementId, String assetId ) { - var agreement = ContractAgreement.Builder.newInstance() + return ContractAgreement.Builder.newInstance() .id(agreementId) - .providerAgentId(UUID.randomUUID().toString()) - .consumerAgentId(UUID.randomUUID().toString()) + .providerId(UUID.randomUUID().toString()) + .consumerId(UUID.randomUUID().toString()) .assetId(assetId) .policy(Policy.Builder.newInstance().build()) .build(); - - return agreement; } private static void createContractNegotiation( @@ -105,10 +118,11 @@ private static void createContractNegotiation( .id(UUID.randomUUID().toString()) .counterPartyId(UUID.randomUUID().toString()) .counterPartyAddress(counterPartyAddress) - .protocol("protocol") + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) .contractAgreement(agreement) .type(type) .correlationId(UUID.randomUUID().toString()) + .state(ContractNegotiationStates.FINALIZED.code()) .build(); store.save(negotiation); diff --git a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/UseCaseClientTest.java b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/UseCaseClientTest.java index e4c312207..3cd068851 100644 --- a/extensions/wrapper/client/src/test/java/de/sovity/edc/client/UseCaseClientTest.java +++ b/extensions/wrapper/client/src/test/java/de/sovity/edc/client/UseCaseClientTest.java @@ -14,8 +14,10 @@ package de.sovity.edc.client; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -23,6 +25,7 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -30,6 +33,8 @@ class UseCaseClientTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(TestUtils.createConfiguration(Map.of())); } diff --git a/extensions/wrapper/wrapper-common-api/build.gradle.kts b/extensions/wrapper/wrapper-common-api/build.gradle.kts index 37e9b1ebf..b4856c153 100644 --- a/extensions/wrapper/wrapper-common-api/build.gradle.kts +++ b/extensions/wrapper/wrapper-common-api/build.gradle.kts @@ -1,11 +1,13 @@ +val lombokVersion: String by project + plugins { `java-library` `maven-publish` } dependencies { - annotationProcessor("org.projectlombok:lombok:1.18.28") - compileOnly("org.projectlombok:lombok:1.18.28") + annotationProcessor("org.projectlombok:lombok:${lombokVersion}") + compileOnly("org.projectlombok:lombok:${lombokVersion}") api("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0") api("jakarta.validation:jakarta.validation-api:3.0.2") diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java index 531682db9..c5fdf4265 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.ext.wrapper.api.common.model; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/CriterionDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/CriterionDto.java new file mode 100644 index 000000000..ef6e9b5b2 --- /dev/null +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/CriterionDto.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + +package de.sovity.edc.ext.wrapper.api.common.model; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CriterionDto { + + @NotNull(message = "operandLeft cannot be null") + private Object operandLeft; + @NotNull(message = "operator cannot be null") + private String operator; + private Object operandRight; +} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionDto.java index 0132cc6fd..66b3458ce 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionDto.java @@ -1,11 +1,25 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.ext.wrapper.api.common.model; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.List; + /** * Expression constraints for policies. * diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java index eef592193..3bed746f3 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.ext.wrapper.api.common.model; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java index 41a3451b3..4bcd46a9e 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.ext.wrapper.api.common.model; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/extensions/wrapper/wrapper-ee-api/build.gradle.kts b/extensions/wrapper/wrapper-ee-api/build.gradle.kts index e3e4924da..16348fd04 100644 --- a/extensions/wrapper/wrapper-ee-api/build.gradle.kts +++ b/extensions/wrapper/wrapper-ee-api/build.gradle.kts @@ -1,11 +1,13 @@ +val lombokVersion: String by project + plugins { `java-library` `maven-publish` } dependencies { - annotationProcessor("org.projectlombok:lombok:1.18.28") - compileOnly("org.projectlombok:lombok:1.18.28") + annotationProcessor("org.projectlombok:lombok:${lombokVersion}") + compileOnly("org.projectlombok:lombok:${lombokVersion}") api("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0") api("jakarta.validation:jakarta.validation-api:3.0.2") diff --git a/extensions/wrapper/wrapper-ee-api/src/main/java/de/sovity/edc/ext/wrapper/api/ee/EnterpriseEditionResourceImpl.java b/extensions/wrapper/wrapper-ee-api/src/main/java/de/sovity/edc/ext/wrapper/api/ee/EnterpriseEditionResourceImpl.java index bc5e7d76a..798fc46fb 100644 --- a/extensions/wrapper/wrapper-ee-api/src/main/java/de/sovity/edc/ext/wrapper/api/ee/EnterpriseEditionResourceImpl.java +++ b/extensions/wrapper/wrapper-ee-api/src/main/java/de/sovity/edc/ext/wrapper/api/ee/EnterpriseEditionResourceImpl.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.ext.wrapper.api.ee; import de.sovity.edc.ext.wrapper.api.ee.model.ConnectorLimits; diff --git a/extensions/wrapper/wrapper/build.gradle.kts b/extensions/wrapper/wrapper/build.gradle.kts index 3b9f04b95..5e7e4405f 100644 --- a/extensions/wrapper/wrapper/build.gradle.kts +++ b/extensions/wrapper/wrapper/build.gradle.kts @@ -2,6 +2,8 @@ val edcVersion: String by project val edcGroup: String by project val restAssured: String by project val assertj: String by project +val mockitoVersion: String by project +val lombokVersion: String by project plugins { `java-library` @@ -12,15 +14,15 @@ plugins { } dependencies { - annotationProcessor("org.projectlombok:lombok:1.18.28") - compileOnly("org.projectlombok:lombok:1.18.28") + annotationProcessor("org.projectlombok:lombok:${lombokVersion}") + compileOnly("org.projectlombok:lombok:${lombokVersion}") implementation("${edcGroup}:api-core:${edcVersion}") implementation("${edcGroup}:management-api-configuration:${edcVersion}") + implementation("${edcGroup}:dsp-http-spi:${edcVersion}") implementation(project(":extensions:wrapper:wrapper-common-api")) implementation(project(":extensions:wrapper:wrapper-ee-api")) api("${edcGroup}:contract-definition-api:${edcVersion}") - api("${edcGroup}:asset-api:${edcVersion}") api("${edcGroup}:control-plane-spi:${edcVersion}") api("${edcGroup}:core-spi:${edcVersion}") api("${edcGroup}:policy-definition-api:${edcVersion}") @@ -40,9 +42,10 @@ dependencies { testImplementation("${edcGroup}:http:${edcVersion}") testImplementation(project(":extensions:policy-always-true")) testImplementation("io.rest-assured:rest-assured:${restAssured}") + testImplementation("${edcGroup}:data-plane-selector-core:${edcVersion}") + testImplementation("org.mockito:mockito-core:${mockitoVersion}") testImplementation("org.assertj:assertj-core:${assertj}") testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") - testImplementation("org.mockito:mockito-core:5.4.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java index 43b96f7bb..99d173395 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper; -import org.eclipse.edc.api.transformer.DtoTransformerRegistry; import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; @@ -48,8 +47,6 @@ public class WrapperExtension implements ServiceExtension { @Inject private ContractNegotiationStore contractNegotiationStore; @Inject - private DtoTransformerRegistry dtoTransformerRegistry; - @Inject private ManagementApiConfiguration dataManagementApiConfiguration; @Inject private PolicyDefinitionStore policyDefinitionStore; @@ -74,18 +71,18 @@ public void initialize(ServiceExtensionContext context) { var objectMapper = typeManager.getMapper(); var wrapperExtensionContext = WrapperExtensionContextBuilder.buildContext( + context, assetIndex, assetService, contractAgreementService, contractDefinitionStore, contractNegotiationService, contractNegotiationStore, - dtoTransformerRegistry, objectMapper, policyDefinitionStore, policyEngine, - transferProcessService, - transferProcessStore + transferProcessStore, + transferProcessService ); wrapperExtensionContext.jaxRsResources().forEach(resource -> diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java index c06ee6147..81dff76d9 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java @@ -25,7 +25,6 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.TransferRequestBuilder; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractAgreementUtils; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractNegotiationUtils; -import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.TransformerRegistryUtils; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageApiService; import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageAssetFetcherService; import de.sovity.edc.ext.wrapper.api.usecase.UseCaseResource; @@ -34,7 +33,6 @@ import de.sovity.edc.ext.wrapper.api.usecase.services.PolicyMappingService; import de.sovity.edc.ext.wrapper.api.usecase.services.SupportedPolicyApiService; import lombok.NoArgsConstructor; -import org.eclipse.edc.api.transformer.DtoTransformerRegistry; import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; @@ -46,6 +44,7 @@ import org.eclipse.edc.policy.engine.spi.PolicyEngine; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.spi.system.ServiceExtensionContext; import java.util.List; @@ -62,48 +61,54 @@ public class WrapperExtensionContextBuilder { public static WrapperExtensionContext buildContext( + ServiceExtensionContext serviceExtensionContext, AssetIndex assetIndex, AssetService assetService, ContractAgreementService contractAgreementService, ContractDefinitionStore contractDefinitionStore, ContractNegotiationService contractNegotiationService, ContractNegotiationStore contractNegotiationStore, - DtoTransformerRegistry dtoTransformerRegistry, ObjectMapper objectMapper, PolicyDefinitionStore policyDefinitionStore, PolicyEngine policyEngine, - TransferProcessService transferProcessService, - TransferProcessStore transferProcessStore + TransferProcessStore transferProcessStore, + TransferProcessService transferProcessService ) { // UI API var transferProcessStateService = new TransferProcessStateService(); - var contractAgreementPageCardBuilder = new ContractAgreementPageCardBuilder( - transferProcessStateService); + var contractAgreementPageCardBuilder = + new ContractAgreementPageCardBuilder( + transferProcessStateService); var contractAgreementDataFetcher = new ContractAgreementDataFetcher( contractAgreementService, contractNegotiationStore, - transferProcessService + transferProcessService, + assetIndex ); var contractAgreementApiService = new ContractAgreementPageApiService( contractAgreementDataFetcher, contractAgreementPageCardBuilder ); - var transferHistoryPageApiService = new TransferHistoryPageApiService(assetService, contractAgreementService, contractNegotiationStore, - transferProcessService, transferProcessStateService); - var transferHistoryPageAssetFetcherService = new TransferHistoryPageAssetFetcherService(assetService, transferProcessService); - var transformerRegistryUtils = new TransformerRegistryUtils(dtoTransformerRegistry); + var transferHistoryPageApiService = new TransferHistoryPageApiService( + assetService, + contractAgreementService, + contractNegotiationStore, + transferProcessService, + transferProcessStateService); + var transferHistoryPageAssetFetcherService = new TransferHistoryPageAssetFetcherService( + assetService, + transferProcessService); var contractNegotiationUtils = new ContractNegotiationUtils(contractNegotiationService); var contractAgreementUtils = new ContractAgreementUtils(contractAgreementService); var transferRequestBuilder = new TransferRequestBuilder( objectMapper, contractAgreementUtils, contractNegotiationUtils, - transformerRegistryUtils + serviceExtensionContext.getConnectorId() ); var contractAgreementTransferApiService = new ContractAgreementTransferApiService( transferRequestBuilder, - transferProcessService, - transformerRegistryUtils + transferProcessService ); var uiResource = new UiResource( contractAgreementApiService, @@ -123,7 +128,7 @@ public static WrapperExtensionContext buildContext( var supportedPolicyApiService = new SupportedPolicyApiService(policyEngine); var policyMappingService = new PolicyMappingService(); var offeringService = new OfferingService(assetIndex, policyDefinitionStore, - contractDefinitionStore, dtoTransformerRegistry, policyMappingService); + contractDefinitionStore, policyMappingService); var useCaseResource = new UseCaseResource(kpiApiService, supportedPolicyApiService, offeringService); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java index f5e8917e9..0e57b9ca4 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java @@ -24,10 +24,15 @@ import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageAssetFetcherService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.api.model.IdResponseDto; +import org.eclipse.edc.api.model.IdResponse; @Path("wrapper/ui") @Tag(name = "UI", description = "EDC UI API Endpoints") @@ -52,7 +57,7 @@ public ContractAgreementPage contractAgreementEndpoint() { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Operation(description = "Initiate a Transfer Process") - public IdResponseDto initiateTransfer( + public IdResponse initiateTransfer( ContractAgreementTransferRequest contractAgreementTransferRequest ) { return contractAgreementTransferApiService.initiateTransfer( diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTransferRequestParams.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTransferRequestParams.java index 30d5eac4e..eae21a9e6 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTransferRequestParams.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/ContractAgreementTransferRequestParams.java @@ -36,6 +36,6 @@ public class ContractAgreementTransferRequestParams { @Schema(description = "Data Sink / Data Address", requiredMode = Schema.RequiredMode.REQUIRED) private Map dataSinkProperties; - @Schema(description = "Additional properties to add to the transfer process, e.g. for parameterized HTTP Data Sources.", requiredMode = Schema.RequiredMode.REQUIRED) - private Map properties; + @Schema(description = "Additional private properties to add to the transfer process, which are not passed to the consumer", requiredMode = Schema.RequiredMode.REQUIRED) + private Map privateProperties; } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/ContractAgreementTransferApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/ContractAgreementTransferApiService.java index 21e9296f7..bec35b6c9 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/ContractAgreementTransferApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/ContractAgreementTransferApiService.java @@ -16,35 +16,29 @@ import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferRequest; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.TransferRequestBuilder; -import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.TransformerRegistryUtils; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.api.model.IdResponseDto; +import org.eclipse.edc.api.model.IdResponse; import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; -import org.eclipse.edc.connector.transfer.spi.types.DataRequest; import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; import org.jetbrains.annotations.NotNull; -import java.time.Clock; - import static org.eclipse.edc.web.spi.exception.ServiceResultHandler.exceptionMapper; @RequiredArgsConstructor public class ContractAgreementTransferApiService { private final TransferRequestBuilder transferRequestBuilder; private final TransferProcessService transferProcessService; - private final TransformerRegistryUtils transformerRegistryUtils; @NotNull - public IdResponseDto initiateTransfer( + public IdResponse initiateTransfer( ContractAgreementTransferRequest request ) { - var transferRequestDto = transferRequestBuilder.buildTransferRequestDto(request); - var dataRequest = transformerRegistryUtils.transformOrThrow(transferRequestDto, DataRequest.class); - var transferProcessId = transferProcessService.initiateTransfer(dataRequest) - .orElseThrow(exceptionMapper(TransferProcess.class, transferRequestDto.getId())); - return IdResponseDto.Builder.newInstance() - .id(transferProcessId) - .createdAt(Clock.systemUTC().millis()) + var transferRequest = transferRequestBuilder.buildTransferRequest(request); + var transferProcess = transferProcessService.initiateTransfer(transferRequest) + .orElseThrow(exceptionMapper(TransferProcess.class, transferRequest.getId())); + return IdResponse.Builder.newInstance() + .id(transferProcess.getId()) + .createdAt(transferProcess.getCreatedAt()) .build(); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementDataFetcher.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementDataFetcher.java index cf9cedcfd..27739895d 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementDataFetcher.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementDataFetcher.java @@ -14,19 +14,24 @@ package de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services; +import de.sovity.edc.ext.wrapper.utils.MapUtils; import lombok.RequiredArgsConstructor; import org.eclipse.edc.connector.contract.spi.negotiation.store.ContractNegotiationStore; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; +import org.eclipse.edc.connector.spi.asset.AssetService; import org.eclipse.edc.connector.spi.contractagreement.ContractAgreementService; import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; +import org.eclipse.edc.spi.asset.AssetIndex; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.types.domain.asset.Asset; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; @@ -35,6 +40,7 @@ public class ContractAgreementDataFetcher { private final ContractAgreementService contractAgreementService; private final ContractNegotiationStore contractNegotiationStore; private final TransferProcessService transferProcessService; + private final AssetIndex assetIndex; /** * Fetches all contract agreements as {@link ContractAgreementData}s. @@ -44,6 +50,7 @@ public class ContractAgreementDataFetcher { @NotNull public List getContractAgreements() { var agreements = getAllContractAgreements(); + var assets = getAllAssets(); var negotiations = getAllContractNegotiations().stream() .filter(it -> it.getContractAgreement() != null) @@ -56,13 +63,17 @@ public List getContractAgreements() { return agreements.stream() .flatMap(agreement -> negotiations.getOrDefault(agreement.getId(), List.of()).stream() .map(negotiation -> { - var asset = findAssetInNegotiation(agreement, negotiation); + var asset = MapUtils.associateBy(assets, Asset::getId).get(agreement.getAssetId()); var contractTransfers = transfers.getOrDefault(agreement.getId(), List.of()); return new ContractAgreementData(agreement, negotiation, asset, contractTransfers); })) .toList(); } + private List getAllAssets() { + return assetIndex.queryAssets(QuerySpec.max()).collect(Collectors.toList()); + } + @NotNull private List getAllContractNegotiations() { return contractNegotiationStore.queryNegotiations(QuerySpec.max()).toList(); @@ -77,16 +88,4 @@ private List getAllContractAgreements() { private List getAllTransferProcesses() { return transferProcessService.query(QuerySpec.max()).getContent().toList(); } - - @NotNull - private Asset findAssetInNegotiation(ContractAgreement agreement, ContractNegotiation negotiation) { - // Agreements have a single assetId - // The negotiation has multiple contract offers - // Find the asset from the contract offers - return negotiation.getContractOffers().stream() - .map(ContractOffer::getAsset) - .filter(it -> agreement.getAssetId().equals(it.getId())) - .findFirst() - .orElseGet(() -> Asset.Builder.newInstance().id(agreement.getAssetId()).build()); - } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementPageCardBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementPageCardBuilder.java index c79bfa461..28d5be1f2 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementPageCardBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/ContractAgreementPageCardBuilder.java @@ -33,6 +33,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.edc.connector.contract.spi.types.agreement.ContractAgreement; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiation; +import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.spi.types.domain.asset.Asset; @@ -57,8 +58,6 @@ public ContractAgreementCard buildContractAgreementCard( card.setCounterPartyAddress(negotiation.getCounterPartyAddress()); card.setCounterPartyId(negotiation.getCounterPartyId()); card.setContractSigningDate(utcSecondsToOffsetDateTime(agreement.getContractSigningDate())); - card.setContractStartDate(utcSecondsToOffsetDateTime(agreement.getContractStartDate())); - card.setContractEndDate(utcSecondsToOffsetDateTime(agreement.getContractEndDate())); card.setAsset(buildAssetDto(asset)); card.setContractPolicy(buildPolicyDto(agreement.getPolicy())); card.setTransferProcesses(buildTransferProcesses(transferProcesses)); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferProcessStateService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferProcessStateService.java index 01585024e..b2903614a 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferProcessStateService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferProcessStateService.java @@ -59,7 +59,7 @@ public boolean isRunning(int code) { * @return if running */ public boolean isError(int code) { - return code < 0; + return TransferProcessStates.TERMINATING.code() == code || TransferProcessStates.TERMINATED.code() == code; } @NotNull diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferRequestBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferRequestBuilder.java index bc18eaf33..814d27637 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferRequestBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/TransferRequestBuilder.java @@ -17,18 +17,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferRequest; import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferRequestParams; -import de.sovity.edc.ext.wrapper.api.ui.model.ContractAgreementTransferRequestType; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractAgreementUtils; import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractNegotiationUtils; -import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.TransformerRegistryUtils; -import jakarta.ws.rs.core.MediaType; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; -import org.eclipse.edc.connector.api.management.asset.model.DataAddressDto; -import org.eclipse.edc.connector.api.management.transferprocess.model.TransferRequestDto; -import org.eclipse.edc.connector.transfer.spi.types.TransferType; +import org.eclipse.edc.connector.transfer.spi.types.TransferRequest; +import org.eclipse.edc.protocol.dsp.spi.types.HttpMessageProtocol; import org.eclipse.edc.spi.types.domain.DataAddress; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -39,23 +36,19 @@ public class TransferRequestBuilder { private final ObjectMapper objectMapper; private final ContractAgreementUtils contractAgreementUtils; private final ContractNegotiationUtils contractNegotiationUtils; - private final TransformerRegistryUtils transformerRegistryUtils; + private final String connectorId; - public TransferRequestDto buildTransferRequestDto( + public TransferRequest buildTransferRequest( ContractAgreementTransferRequest request ) { Objects.requireNonNull(request.getType(), "type"); return switch (request.getType()) { - case PARAMS_ONLY -> buildTransferRequestDto(request.getParams()); - case CUSTOM_JSON -> parseTransferRequestDtoJson(request); - default -> throw new IllegalArgumentException("Unhandled %s: %s".formatted( - ContractAgreementTransferRequestType.class.getSimpleName(), - request.getType() - )); + case PARAMS_ONLY -> buildTransferRequest(request.getParams()); + case CUSTOM_JSON -> parseTransferRequestJson(request); }; } - private TransferRequestDto buildTransferRequestDto( + private TransferRequest buildTransferRequest( ContractAgreementTransferRequestParams params ) { var contractId = params.getContractAgreementId(); @@ -63,33 +56,26 @@ private TransferRequestDto buildTransferRequestDto( var negotiation = contractNegotiationUtils.findByContractAgreementIdOrThrow(contractId); var address = buildDataAddress(params.getDataSinkProperties()); - var transferType = TransferType.Builder.transferType() - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .isFinite(true) - .build(); - - return TransferRequestDto.Builder.newInstance() - .connectorAddress(negotiation.getCounterPartyAddress()) + return TransferRequest.Builder.newInstance() .id(UUID.randomUUID().toString()) + .protocol(HttpMessageProtocol.DATASPACE_PROTOCOL_HTTP) + .connectorAddress(negotiation.getCounterPartyAddress()) + .connectorId(connectorId) .contractId(contractId) - .dataDestination(address) - .managedResources(false) - .properties(params.getProperties()) - .transferType(transferType) - .protocol("ids-multipart") - .connectorId("consumer") .assetId(agreement.getAssetId()) + .dataDestination(address) + .privateProperties(params.getPrivateProperties()) + .callbackAddresses(List.of()) .build(); } @SneakyThrows - private TransferRequestDto parseTransferRequestDtoJson(ContractAgreementTransferRequest request) { - return objectMapper.readValue(request.getCustomJson(), TransferRequestDto.class); + private TransferRequest parseTransferRequestJson(ContractAgreementTransferRequest request) { + return objectMapper.readValue(request.getCustomJson(), TransferRequest.class); } @SneakyThrows private DataAddress buildDataAddress(Map dataAddressProperties) { - var dto = DataAddressDto.Builder.newInstance().properties(dataAddressProperties).build(); - return transformerRegistryUtils.transformOrThrow(dto, DataAddress.class); + return DataAddress.Builder.newInstance().properties(dataAddressProperties).build(); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/utils/TransformerRegistryUtils.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/utils/TransformerRegistryUtils.java deleted file mode 100644 index 0f6cfd701..000000000 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/contracts/services/utils/TransformerRegistryUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2023 sovity GmbH - * - * 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: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils; - -import lombok.RequiredArgsConstructor; -import org.eclipse.edc.api.transformer.DtoTransformerRegistry; -import org.eclipse.edc.web.spi.exception.InvalidRequestException; - -@RequiredArgsConstructor -public class TransformerRegistryUtils { - - private final DtoTransformerRegistry transformerRegistry; - - public R transformOrThrow(T input, Class outputClazz) { - var result = transformerRegistry.transform(input, outputClazz); - if (result.failed()) { - throw new InvalidRequestException(result.getFailureMessages()); - } - - return result.getContent(); - } -} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java index f775b7919..782c35e59 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/transferhistory/TransferHistoryPageAssetFetcherService.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * 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: + * sovity GmbH - init + */ + package de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory; import de.sovity.edc.ext.wrapper.api.common.model.AssetDto; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/AssetEntryDto.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/AssetEntryDto.java new file mode 100644 index 000000000..b35e11624 --- /dev/null +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/AssetEntryDto.java @@ -0,0 +1,24 @@ +package de.sovity.edc.ext.wrapper.api.usecase.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.Map; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class AssetEntryDto { + @Schema(requiredMode = RequiredMode.REQUIRED) + private String assetRequestId; + private Map assetRequestProperties; + @Schema(description = "At least a property 'type' must be set", requiredMode = RequiredMode.REQUIRED) + private Map dataAddressProperties; +} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/ContractDefinitionRequestDto.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/ContractDefinitionRequestDto.java new file mode 100644 index 000000000..4f9261631 --- /dev/null +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/ContractDefinitionRequestDto.java @@ -0,0 +1,36 @@ +package de.sovity.edc.ext.wrapper.api.usecase.model; + +import de.sovity.edc.ext.wrapper.api.common.model.CriterionDto; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder(toBuilder = true) +public class ContractDefinitionRequestDto { + + /** + * Default validity is set to one year. + */ + private static final long DEFAULT_VALIDITY = TimeUnit.DAYS.toSeconds(365); + + private String id; + @NotNull(message = "accessPolicyId cannot be null") + private String accessPolicyId; + @NotNull(message = "contractPolicyId cannot be null") + private String contractPolicyId; + @Valid + @NotNull(message = "criteria cannot be null") + private List assetsSelector; + +} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CreateOfferingDto.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CreateOfferingDto.java index d9b439131..5aff7b096 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CreateOfferingDto.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/CreateOfferingDto.java @@ -6,8 +6,6 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import org.eclipse.edc.connector.api.management.asset.model.AssetEntryDto; -import org.eclipse.edc.connector.api.management.contractdefinition.model.ContractDefinitionRequestDto; /** * DTO containing all data necessary for creating an offer. @@ -21,6 +19,7 @@ @NoArgsConstructor @Schema(description = "Necessary data for creating an offer") public class CreateOfferingDto { + private AssetEntryDto assetEntry; private PolicyDefinitionRequestDto policyDefinitionRequest; private ContractDefinitionRequestDto contractDefinitionRequest; diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingService.java index 673290180..d9bade1c8 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingService.java @@ -1,16 +1,18 @@ package de.sovity.edc.ext.wrapper.api.usecase.services; +import de.sovity.edc.ext.wrapper.api.usecase.model.AssetEntryDto; +import de.sovity.edc.ext.wrapper.api.usecase.model.ContractDefinitionRequestDto; import de.sovity.edc.ext.wrapper.api.usecase.model.CreateOfferingDto; import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyDefinitionRequestDto; import lombok.RequiredArgsConstructor; -import org.eclipse.edc.api.transformer.DtoTransformerRegistry; -import org.eclipse.edc.connector.api.management.asset.model.AssetEntryDto; -import org.eclipse.edc.connector.api.management.contractdefinition.model.ContractDefinitionRequestDto; +import lombok.extern.slf4j.Slf4j; import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; import org.eclipse.edc.connector.policy.spi.PolicyDefinition; import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.spi.persistence.EdcPersistenceException; +import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.types.domain.DataAddress; import org.eclipse.edc.spi.types.domain.asset.Asset; import org.eclipse.edc.web.spi.exception.InvalidRequestException; @@ -21,12 +23,12 @@ * @author tim.dahlmanns@isst.fraunhofer.de */ @RequiredArgsConstructor +@Slf4j public class OfferingService { private final AssetIndex assetIndex; private final PolicyDefinitionStore policyDefinitionStore; private final ContractDefinitionStore contractDefinitionStore; - private final DtoTransformerRegistry dtoTransformerRegistry; private final PolicyMappingService policyMappingService; /** @@ -38,13 +40,19 @@ public class OfferingService { public void create(CreateOfferingDto dto) { validateInput(dto); - var asset = transformAsset(dto.getAssetEntry()); - var dataAddress = transformDataAddress(dto.getAssetEntry()); - var policy = transformPolicy(dto.getPolicyDefinitionRequest()); - var contractDefinition = transformContractDefinition(dto - .getContractDefinitionRequest()); - - persist(asset, dataAddress, policy, contractDefinition); + try { + var asset = transformAsset(dto.getAssetEntry()); + var dataAddress = transformDataAddress(dto.getAssetEntry()); + var policy = transformPolicy(dto.getPolicyDefinitionRequest()); + var contractDefinition = transformContractDefinition(dto + .getContractDefinitionRequest()); + persist(asset, dataAddress, policy, contractDefinition); + } catch (EdcPersistenceException e) { + throw e; + } catch (Exception e) { + log.error("Error transforming DTOs: " + e.getMessage(), e); + throw new InvalidRequestException(e.getMessage()); + } } private void validateInput(CreateOfferingDto dto) { @@ -60,13 +68,16 @@ private void validateInput(CreateOfferingDto dto) { } private Asset transformAsset(AssetEntryDto dto) { - return dtoTransformerRegistry.transform(dto.getAsset(), Asset.class) - .orElseThrow(failure -> new InvalidRequestException(failure.getFailureDetail())); + return Asset.Builder.newInstance() + .id(dto.getAssetRequestId()) + .properties(dto.getAssetRequestProperties()) + .build(); } private DataAddress transformDataAddress(AssetEntryDto dto) { - return dtoTransformerRegistry.transform(dto.getDataAddress(), DataAddress.class) - .orElseThrow(failure -> new InvalidRequestException(failure.getFailureDetail())); + return DataAddress.Builder.newInstance() + .properties(dto.getDataAddressProperties()) + .build(); } private PolicyDefinition transformPolicy(PolicyDefinitionRequestDto dto) { @@ -83,20 +94,29 @@ private PolicyDefinition transformPolicy(PolicyDefinitionRequestDto dto) { } private ContractDefinition transformContractDefinition(ContractDefinitionRequestDto dto) { - return dtoTransformerRegistry.transform(dto, ContractDefinition.class) - .orElseThrow(failure -> new InvalidRequestException(failure.getFailureDetail())); + return ContractDefinition.Builder.newInstance() + .id(dto.getId()) + .contractPolicyId(dto.getContractPolicyId()) + .accessPolicyId(dto.getAccessPolicyId()) + .assetsSelector(dto.getAssetsSelector().stream() + .map(criterionDto -> new Criterion( + criterionDto.getOperandLeft(), + criterionDto.getOperator(), + criterionDto.getOperandRight())).toList() + ) + .build(); } private void persist(Asset asset, DataAddress dataAddress, PolicyDefinition policyDefinition, - ContractDefinition contractDefinition) { + ContractDefinition contractDefinition) { try { - assetIndex.accept(asset, dataAddress); - policyDefinitionStore.save(policyDefinition); + assetIndex.create(asset, dataAddress); + policyDefinitionStore.create(policyDefinition); contractDefinitionStore.save(contractDefinition); } catch (Exception e) { // Persist all or none (deleteById methods do not fail if ID not found) assetIndex.deleteById(asset.getId()); - policyDefinitionStore.deleteById(policyDefinition.getId()); + policyDefinitionStore.delete(policyDefinition.getId()); contractDefinitionStore.deleteById(contractDefinition.getId()); throw e; } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/MapUtils.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/MapUtils.java index cd3f690b8..63456c96b 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/MapUtils.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/utils/MapUtils.java @@ -17,8 +17,10 @@ import lombok.NoArgsConstructor; import lombok.NonNull; +import java.util.Collection; import java.util.Map; import java.util.function.Function; +import java.util.stream.Collectors; import static java.util.stream.Collectors.toMap; @@ -28,4 +30,10 @@ public class MapUtils { public static Map mapValues(@NonNull Map map, @NonNull Function valueMapper) { return map.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> valueMapper.apply(e.getValue()))); } + + public static Map associateBy(Collection collection, Function keyExtractor) { + return collection.stream().collect(Collectors.toMap(keyExtractor, Function.identity(), (a, b) -> { + throw new IllegalStateException("Duplicate key %s.".formatted(keyExtractor.apply(a))); + })); + } } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/ContractAgreementPageTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/ContractAgreementPageTest.java index fc178ab3e..92aec78bd 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/ContractAgreementPageTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/ContractAgreementPageTest.java @@ -25,6 +25,7 @@ import org.eclipse.edc.connector.transfer.spi.types.DataRequest; import org.eclipse.edc.connector.transfer.spi.types.TransferProcess; import org.eclipse.edc.connector.transfer.spi.types.TransferProcessStates; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.policy.model.Action; @@ -33,6 +34,8 @@ import org.eclipse.edc.policy.model.Operator; import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.asset.AssetIndex; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.eclipse.edc.spi.types.domain.DataAddress; import org.eclipse.edc.spi.types.domain.asset.Asset; import org.junit.jupiter.api.BeforeEach; @@ -44,6 +47,8 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; +import java.util.Map; +import java.util.UUID; import static de.sovity.edc.ext.wrapper.TestUtils.createConfiguration; import static de.sovity.edc.ext.wrapper.TestUtils.givenManagementEndpoint; @@ -52,10 +57,15 @@ import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.core.IsEqual.equalTo; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) class ContractAgreementPageTest { + + private static final int CONTRACT_DEFINITION_ID = 1; + private static final String ASSET_ID = UUID.randomUUID().toString(); + LocalDate today = LocalDate.parse("2019-04-01"); ZonedDateTime todayAsZonedDateTime = today.atStartOfDay(ZoneId.systemDefault()); long todayEpochMillis = todayAsZonedDateTime.toInstant().toEpochMilli(); @@ -63,6 +73,8 @@ class ContractAgreementPageTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(createConfiguration()); } @@ -78,12 +90,16 @@ ValidatableResponse whenContractAgreementEndpoint() { @Test void testContractAgreementPage( ContractNegotiationStore contractNegotiationStore, - TransferProcessStore transferProcessStore + TransferProcessStore transferProcessStore, + AssetIndex assetIndex ) { - contractNegotiationStore.save(contractDefinition(1)); + assetIndex.create(asset(ASSET_ID)).orElseThrow(storeFailure -> new RuntimeException("Failed to create asset")); + contractNegotiationStore.save(contractDefinition(CONTRACT_DEFINITION_ID)); - transferProcessStore.save(transferProcess(1, 1, TransferProcessStates.COMPLETED.code())); + transferProcessStore.updateOrCreate(transferProcess(1, 1, TransferProcessStates.COMPLETED.code())); + whenContractAgreementEndpoint() + .assertThat().extract().response().body().prettyPrint(); whenContractAgreementEndpoint() .assertThat() .body("contractAgreements", hasSize(1)) @@ -93,11 +109,9 @@ void testContractAgreementPage( .body("contractAgreements[0].counterPartyAddress", equalTo("http://other-connector")) .body("contractAgreements[0].counterPartyId", equalTo("urn:connector:other-connector")) .body("contractAgreements[0].contractSigningDate", equalTo(todayPlusDays(0))) - .body("contractAgreements[0].contractStartDate", equalTo(todayPlusDays(0))) - .body("contractAgreements[0].contractEndDate", equalTo(todayPlusDays(2))) - .body("contractAgreements[0].asset.assetId", equalTo("my-asset-1")) + .body("contractAgreements[0].asset.assetId", equalTo(ASSET_ID)) .body("contractAgreements[0].asset.createdAt", equalTo(todayPlusDays(0))) - .body("contractAgreements[0].asset.properties.\"asset:prop:id\"", equalTo("my-asset-1")) + .body("contractAgreements[0].asset.properties['https://w3id.org/edc/v0.0.1/ns/id']", equalTo(ASSET_ID)) .body("contractAgreements[0].asset.properties.some-property", equalTo("X")) .body("contractAgreements[0].transferProcesses", hasSize(1)) .body("contractAgreements[0].transferProcesses[0].transferProcessId", equalTo("my-transfer-1-1")) @@ -108,6 +122,13 @@ void testContractAgreementPage( .body("contractAgreements[0].transferProcesses[0].errorMessage", equalTo("my-error-message-1")); } + private DataAddress dataAddress() { + return DataAddress.Builder.newInstance() + .type("HttpData") + .properties(Map.of("baseUrl", "http://some-url")) + .build(); + } + private TransferProcess transferProcess(int contract, int transfer, int code) { var dataRequest = DataRequest.Builder.newInstance() .contractId("my-contract-agreement-" + contract) @@ -132,36 +153,24 @@ private TransferProcess transferProcess(int contract, int transfer, int code) { private ContractNegotiation contractDefinition(int contract) { var agreement = ContractAgreement.Builder.newInstance() .id("my-contract-agreement-" + contract) - .assetId("my-asset-" + contract) + .assetId(ASSET_ID) .contractSigningDate(todayEpochSeconds) - .contractStartDate(todayAsZonedDateTime.toInstant().getEpochSecond()) - .contractEndDate(todayAsZonedDateTime.plusDays(2L * contract).toInstant().getEpochSecond()) - .providerAgentId("idk") - .consumerAgentId("idk") .policy(alwaysTrue()) + .providerId(URI.create("http://other-connector").toString()) + .consumerId(URI.create("http://my-connector").toString()) .build(); // Contract Negotiations can contain multiple Contract Offers (?) // Test this var irrelevantOffer = ContractOffer.Builder.newInstance() .id("my-contract-offer-" + contract + "-irrelevant") - .asset(asset(contract + "-irrelevant")) - .contractStart(todayAsZonedDateTime.minusDays(contract)) - .contractEnd(todayAsZonedDateTime.plusDays(contract)) - .consumer(URI.create("http://other-connector")) - .offerStart(todayAsZonedDateTime.minusDays(2L * contract)) - .offerEnd(todayAsZonedDateTime.plusDays(2L * contract)) + .assetId(asset(contract + "-irrelevant").getId()) .policy(alwaysTrue()) .build(); var offer = ContractOffer.Builder.newInstance() .id("my-contract-offer-" + contract) - .asset(asset(String.valueOf(contract))) - .contractStart(todayAsZonedDateTime) - .contractEnd(todayAsZonedDateTime.plusDays(2L * contract)) - .consumer(URI.create("http://other-connector")) - .offerStart(todayAsZonedDateTime.minusDays(2L * contract)) - .offerEnd(todayAsZonedDateTime.plusDays(2L * contract)) + .assetId(ASSET_ID) .policy(alwaysTrue()) .build(); @@ -177,11 +186,12 @@ private ContractNegotiation contractDefinition(int contract) { .build(); } - private Asset asset(String suffix) { + private Asset asset(String assetId) { return Asset.Builder.newInstance() - .id("my-asset-" + suffix) + .id(assetId) .property("some-property", "X") .createdAt(todayEpochMillis) + .dataAddress(dataAddress()) .build(); } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/services/TransferProcessStateServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/services/TransferProcessStateServiceTest.java index 46ee733f4..b1ce75c30 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/services/TransferProcessStateServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/services/TransferProcessStateServiceTest.java @@ -33,10 +33,10 @@ void setup() { @Test void testError() { - int code = TransferProcessStates.ERROR.code(); + int code = TransferProcessStates.TERMINATED.code(); var result = transferProcessStateService.buildTransferProcessState(code); assertThat(result.getCode()).isEqualTo(code); - assertThat(result.getName()).isEqualTo("ERROR"); + assertThat(result.getName()).isEqualTo("TERMINATED"); assertThat(result.getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.ERROR); } @@ -68,15 +68,6 @@ void testDeprovisioning() { assertThat(result.getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.OK); } - @Test - void testCustomError() { - int code = -100; - var result = transferProcessStateService.buildTransferProcessState(code); - assertThat(result.getCode()).isEqualTo(code); - assertThat(result.getName()).isEqualTo("CUSTOM"); - assertThat(result.getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.ERROR); - } - @Test void testCustomRunning() { int code = 299; diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java index 70b4a3ca6..ace4fddad 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/KpiApiTest.java @@ -16,8 +16,11 @@ import io.restassured.http.ContentType; import io.restassured.response.ValidatableResponse; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,6 +28,7 @@ import static de.sovity.edc.ext.wrapper.TestUtils.createConfiguration; import static de.sovity.edc.ext.wrapper.TestUtils.givenManagementEndpoint; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -32,6 +36,8 @@ class KpiApiTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(createConfiguration()); } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/OfferingResourceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/OfferingResourceTest.java index 21cff4186..0c48221a9 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/OfferingResourceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/OfferingResourceTest.java @@ -6,8 +6,10 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import io.restassured.http.ContentType; import io.restassured.response.ValidatableResponse; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -19,6 +21,7 @@ import static de.sovity.edc.ext.wrapper.TestUtils.createConfiguration; import static de.sovity.edc.ext.wrapper.TestUtils.givenManagementEndpoint; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -42,6 +45,8 @@ static void init() throws IOException { @BeforeEach void setUp(EdcExtension extension) throws JsonProcessingException { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(createConfiguration()); contractOffer = (ObjectNode) MAPPER.readTree(contractOfferValid.toString()); } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java index 5b6897e30..45d383813 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/SupportedPolicyApiTest.java @@ -16,8 +16,11 @@ import io.restassured.http.ContentType; import io.restassured.response.ValidatableResponse; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; +import org.eclipse.edc.spi.protocol.ProtocolWebhook; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,6 +28,7 @@ import static de.sovity.edc.ext.wrapper.TestUtils.createConfiguration; import static de.sovity.edc.ext.wrapper.TestUtils.givenManagementEndpoint; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; @ApiTest @ExtendWith(EdcExtension.class) @@ -32,6 +36,8 @@ class SupportedPolicyApiTest { @BeforeEach void setUp(EdcExtension extension) { + extension.registerServiceMock(ProtocolWebhook.class, mock(ProtocolWebhook.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); extension.setConfiguration(createConfiguration()); } @@ -48,6 +54,6 @@ static ValidatableResponse whenSupportedPolicyFunctions() { void supportedPolicies() { whenSupportedPolicyFunctions() .assertThat() - .body(equalTo("[\"ALWAYS_TRUE\"]")); + .body(equalTo("[\"ALWAYS_TRUE\",\"https://w3id.org/edc/v0.0.1/ns/inForceDate\"]")); } } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingServiceTest.java index e1ea69200..00e380cb5 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/services/OfferingServiceTest.java @@ -1,27 +1,11 @@ package de.sovity.edc.ext.wrapper.api.usecase.services; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Map; - import de.sovity.edc.ext.wrapper.api.common.model.PermissionDto; import de.sovity.edc.ext.wrapper.api.common.model.PolicyDto; +import de.sovity.edc.ext.wrapper.api.usecase.model.AssetEntryDto; +import de.sovity.edc.ext.wrapper.api.usecase.model.ContractDefinitionRequestDto; import de.sovity.edc.ext.wrapper.api.usecase.model.CreateOfferingDto; import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyDefinitionRequestDto; -import org.eclipse.edc.api.transformer.DtoTransformerRegistry; -import org.eclipse.edc.connector.api.management.asset.model.AssetEntryDto; -import org.eclipse.edc.connector.api.management.asset.model.AssetRequestDto; -import org.eclipse.edc.connector.api.management.asset.model.DataAddressDto; -import org.eclipse.edc.connector.api.management.contractdefinition.model.ContractDefinitionRequestDto; import org.eclipse.edc.connector.contract.spi.offer.store.ContractDefinitionStore; import org.eclipse.edc.connector.contract.spi.types.offer.ContractDefinition; import org.eclipse.edc.connector.policy.spi.store.PolicyDefinitionStore; @@ -29,21 +13,32 @@ import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.spi.asset.AssetIndex; -import org.eclipse.edc.spi.asset.AssetSelectorExpression; import org.eclipse.edc.spi.persistence.EdcPersistenceException; -import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.spi.types.domain.DataAddress; import org.eclipse.edc.spi.types.domain.asset.Asset; import org.eclipse.edc.web.spi.exception.InvalidRequestException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.ArrayList; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + class OfferingServiceTest { private final AssetIndex assetIndex = mock(AssetIndex.class); private final PolicyDefinitionStore policyDefinitionStore = mock(PolicyDefinitionStore.class); - private final ContractDefinitionStore contractDefinitionStore = mock(ContractDefinitionStore.class); - private final DtoTransformerRegistry dtoTransformerRegistry = mock(DtoTransformerRegistry.class); + private final ContractDefinitionStore contractDefinitionStore = mock( + ContractDefinitionStore.class); private final PolicyMappingService policyMappingService = mock(PolicyMappingService.class); private OfferingService offeringService; @@ -60,24 +55,20 @@ class OfferingServiceTest { @BeforeEach void setUp() { this.offeringService = new OfferingService(assetIndex, policyDefinitionStore, - contractDefinitionStore, dtoTransformerRegistry, policyMappingService); + contractDefinitionStore, policyMappingService); - this.assetEntryDto = assetEntryDto(); + this.assetEntryDto = assetDto(); this.asset = asset(); this.dataAddress = dataAddress(); this.policyDefinitionDto = policyDefinitionDto(); this.policy = policy(); this.contractDefinitionDto = contractDefinitionDto(); this.contractDefinition = contractDefinition(); - this.createOfferingDto = new CreateOfferingDto(assetEntryDto, policyDefinitionDto, contractDefinitionDto); - - when(dtoTransformerRegistry.transform(assetEntryDto.getAsset(), Asset.class)) - .thenReturn(Result.success(asset)); - when(dtoTransformerRegistry.transform(assetEntryDto.getDataAddress(), DataAddress.class)) - .thenReturn(Result.success(dataAddress)); - when(dtoTransformerRegistry.transform(contractDefinitionDto, ContractDefinition.class)) - .thenReturn(Result.success(contractDefinition)); - when(policyMappingService.policyDtoToPolicy(policyDefinitionDto.getPolicy())).thenReturn(policy); + this.createOfferingDto = new CreateOfferingDto(assetEntryDto, policyDefinitionDto, + contractDefinitionDto); + + when(policyMappingService.policyDtoToPolicy(policyDefinitionDto.getPolicy())).thenReturn( + policy); } @Test @@ -86,8 +77,9 @@ void create_validInput_createResource() { offeringService.create(createOfferingDto); // assert - verify(assetIndex, times(1)).accept(asset, dataAddress); - verify(policyDefinitionStore, times(1)).save(argThat(def -> + verify(assetIndex, times(1)).create(argThat(def -> asset.getId().equals(def.getId())), + argThat(def -> dataAddress.getType().equals(def.getType()))); + verify(policyDefinitionStore, times(1)).create(argThat(def -> policy.equals(def.getPolicy()) && policyDefinitionDto.getId().equals(def.getId()))); verify(contractDefinitionStore, times(1)).save(contractDefinition); } @@ -95,23 +87,7 @@ void create_validInput_createResource() { @Test void create_assetTransformationFails_throwException() { // arrange - when(dtoTransformerRegistry.transform(assetEntryDto.getAsset(), Asset.class)) - .thenReturn(Result.failure("error")); - - // act && assert - assertThatThrownBy(() -> offeringService.create(createOfferingDto)) - .isInstanceOf(InvalidRequestException.class); - - verifyNoInteractions(assetIndex); - verifyNoInteractions(policyDefinitionStore); - verifyNoInteractions(contractDefinitionStore); - } - - @Test - void create_dataAddressTransformationFails_throwException() { - // arrange - when(dtoTransformerRegistry.transform(assetEntryDto.getDataAddress(), DataAddress.class)) - .thenReturn(Result.failure("error")); + assetEntryDto.setDataAddressProperties(Map.of()); // act && assert assertThatThrownBy(() -> offeringService.create(createOfferingDto)) @@ -125,16 +101,17 @@ void create_dataAddressTransformationFails_throwException() { @Test void create_persistingAssetFails_throwException() { // arrange - doThrow(NullPointerException.class).when(assetIndex).accept(any(), any()); + doThrow(NullPointerException.class).when(assetIndex).create(any(), any()); // act && assert assertThatThrownBy(() -> offeringService.create(createOfferingDto)) .isInstanceOf(NullPointerException.class); - verify(assetIndex, times(1)).accept(asset, dataAddress); + verify(assetIndex, times(1)).create(argThat(def -> asset.getId().equals(def.getId())), + argThat(def -> dataAddress.getType().equals(def.getType()))); verify(assetIndex, times(1)).deleteById(asset.getId()); verify(policyDefinitionStore, times(1)) - .deleteById(policyDefinitionDto.getId()); + .delete(policyDefinitionDto.getId()); verify(contractDefinitionStore, times(1)) .deleteById(contractDefinition.getId()); } @@ -157,18 +134,19 @@ void create_mappingPolicyFails_throwException() { @Test void create_persistingPolicyFails_throwException() { // arrange - doThrow(EdcPersistenceException.class).when(policyDefinitionStore).save(any()); + doThrow(EdcPersistenceException.class).when(policyDefinitionStore).create(any()); // act && assert assertThatThrownBy(() -> offeringService.create(createOfferingDto)) .isInstanceOf(EdcPersistenceException.class); - verify(assetIndex, times(1)).accept(asset, dataAddress); + verify(assetIndex, times(1)).create(argThat(def -> asset.getId().equals(def.getId())), + argThat(def -> dataAddress.getType().equals(def.getType()))); verify(assetIndex, times(1)).deleteById(asset.getId()); - verify(policyDefinitionStore, times(1)).save(argThat(pd -> + verify(policyDefinitionStore, times(1)).create(argThat(pd -> policy.equals(pd.getPolicy()) && policyDefinitionDto.getId().equals(pd.getId()))); verify(policyDefinitionStore, times(1)) - .deleteById(policyDefinitionDto.getId()); + .delete(policyDefinitionDto.getId()); verify(contractDefinitionStore, times(1)) .deleteById(contractDefinition.getId()); } @@ -176,8 +154,7 @@ void create_persistingPolicyFails_throwException() { @Test void create_contractDefinitionTransformationFails_throwException() { // arrange - when(dtoTransformerRegistry.transform(contractDefinitionDto, ContractDefinition.class)) - .thenReturn(Result.failure("error")); + contractDefinitionDto.setAssetsSelector(null); // act && assert assertThatThrownBy(() -> offeringService.create(createOfferingDto)) @@ -198,27 +175,23 @@ void create_persistingContractDefinitionFails_throwException() { assertThatThrownBy(() -> offeringService.create(createOfferingDto)) .isInstanceOf(EdcPersistenceException.class); - verify(assetIndex, times(1)).accept(asset, dataAddress); + verify(assetIndex, times(1)).create(argThat(def -> asset.getId().equals(def.getId())), + argThat(def -> dataAddress.getType().equals(def.getType()))); verify(assetIndex, times(1)).deleteById(asset.getId()); - verify(policyDefinitionStore, times(1)).save(argThat(pd -> + verify(policyDefinitionStore, times(1)).create(argThat(pd -> policy.equals(pd.getPolicy()) && policyDefinitionDto.getId().equals(pd.getId()))); verify(policyDefinitionStore, times(1)) - .deleteById(policyDefinitionDto.getId()); + .delete(policyDefinitionDto.getId()); verify(contractDefinitionStore, times(1)).save(contractDefinition); verify(contractDefinitionStore, times(1)) .deleteById(contractDefinition.getId()); } - private AssetEntryDto assetEntryDto() { - var asset = AssetRequestDto.Builder.newInstance() - .id("asset-id") - .build(); - var dataAddress = DataAddressDto.Builder.newInstance() - .properties(Map.of("type", "type")) - .build(); - return AssetEntryDto.Builder.newInstance() - .asset(asset) - .dataAddress(dataAddress) + private AssetEntryDto assetDto() { + return AssetEntryDto.builder() + .assetRequestId("asset-id") + .assetRequestProperties(Map.of()) + .dataAddressProperties(Map.of("type", "type")) .build(); } @@ -238,18 +211,18 @@ private PolicyDefinitionRequestDto policyDefinitionDto() { private Policy policy() { return Policy.Builder.newInstance() - .permission(Permission.Builder.newInstance() - .action(Action.Builder.newInstance().type("USE").build()) - .build()) - .build(); + .permission(Permission.Builder.newInstance() + .action(Action.Builder.newInstance().type("USE").build()) + .build()) + .build(); } private ContractDefinitionRequestDto contractDefinitionDto() { - return ContractDefinitionRequestDto.Builder.newInstance() + return ContractDefinitionRequestDto.builder() .id("contract-definition-id") .accessPolicyId("policy-id") .contractPolicyId("policy-id") - .criteria(new ArrayList<>()) + .assetsSelector(new ArrayList<>()) .build(); } @@ -258,8 +231,6 @@ private ContractDefinition contractDefinition() { .id("contract-definition-id") .accessPolicyId("policy-id") .contractPolicyId("policy-id") - .selectorExpression(AssetSelectorExpression.SELECT_ALL) - .validity(1234) .build(); } } diff --git a/extensions/wrapper/wrapper/src/test/resources/usecase/contract-offer-valid.json b/extensions/wrapper/wrapper/src/test/resources/usecase/contract-offer-valid.json index 92492f98e..74cdf8a40 100644 --- a/extensions/wrapper/wrapper/src/test/resources/usecase/contract-offer-valid.json +++ b/extensions/wrapper/wrapper/src/test/resources/usecase/contract-offer-valid.json @@ -1,15 +1,9 @@ { "assetEntry": { - "asset": { - "id": "mock", - "properties": { - "key": "value" - } - }, - "dataAddress": { - "properties": { - "type": "mock" - } + "assetRequestId": "mock", + "assetRequestProperties": {}, + "dataAddressProperties": { + "type": "HttpData" } }, "policyDefinitionRequest": { @@ -83,9 +77,14 @@ }, "contractDefinitionRequest": { "id": "mock", - "accessPolicyId": "test", - "contractPolicyId": "test", - "validity": 10, - "criteria": [] + "accessPolicyId": "mock", + "contractPolicyId": "mock", + "assetsSelector": [ + { + "operandLeft": "string", + "operator": "EQ", + "operandRight": "string" + } + ] } } diff --git a/gradle.properties b/gradle.properties index e4ad48c30..2b5a34527 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ sovityEdcExtensionsVersion=0.0.1-SNAPSHOT sovityEdcExtensionGroup=de.sovity.edc.ext sovityEdcGroup=de.sovity.edc edcGroup=org.eclipse.edc -edcVersion=0.0.1-20230220.patch1 +edcVersion=0.2.0 registrationServiceVersion=0.0.1-milestone-7-SNAPSHOT identityHubVersion=0.0.1-milestone-7-SNAPSHOT assertj=3.23.1 @@ -13,5 +13,8 @@ jsonVersion=20220924 restAssured=4.5.0 flywayVersion=9.0.1 postgresVersion=42.4.0 +testcontainersVersion=1.17.6 +lombokVersion=1.18.28 +awaitilityVersion=4.2.0 org.gradle.jvmargs=-Xmx1024m diff --git a/settings.gradle.kts b/settings.gradle.kts index 73fae3a97..6ee9c6ff7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,6 @@ rootProject.name = "edc-extensions" include(":extensions:edc-ui-config") -include(":extensions:ids-broker-client") -include(":extensions:ids-clearinghouse-client") include(":extensions:last-commit-info") include(":extensions:policy-always-true") include(":extensions:policy-referring-connector") @@ -15,3 +13,4 @@ include(":extensions:wrapper:wrapper") include(":extensions:wrapper:wrapper-common-api") include(":extensions:wrapper:wrapper-ee-api") include(":connector") +include(":e2e-test") From c344797092ad5d5038ed3475a3dcb1d05f641e7e Mon Sep 17 00:00:00 2001 From: efiege <105237007+efiege@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:00:15 +0200 Subject: [PATCH 2/2] fix: remove clearing house and broker extensions from mds variant build (#474) --- connector/build.gradle.kts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/connector/build.gradle.kts b/connector/build.gradle.kts index cb2e32a14..d61de02c8 100644 --- a/connector/build.gradle.kts +++ b/connector/build.gradle.kts @@ -41,12 +41,6 @@ dependencies { implementation(project(":extensions:postgres-flyway")) } - // Optional: MDS Extensions - if (project.hasProperty("mds")) { - implementation(project(":extensions:ids-clearinghouse-client")) - implementation(project(":extensions:ids-broker-client")) - } - // Optional: Connector-To-Connector IAM if (project.hasProperty("oauth2")) { implementation("${edcGroup}:oauth2-core:${edcVersion}")