diff --git a/CHANGELOG.md b/CHANGELOG.md index 719d1b64c..28b88eec9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,12 +13,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### Major +- Migrated to Eclipse EDC 0.2.1 +- Migrated to edc-extensions 5.0.0 +- Migrated Assets to JSON-LD + #### Minor +- New Filter: Organization Name +- Search now hits Organization Name + #### Patch ### Deployment Migration Notes +- All connectors need to be re-crawled for detailed asset metadata and participant IDs to work + ## [v1.2.0] - 2023-10-30 ### Overview @@ -85,7 +94,7 @@ Bugfix release for the asset properties issue. Also contains the connector delet --url 'http://localhost:11002/backend/api/v1/management/wrapper/broker/connectors?adminApiKey=DefaultBrokerServerAdminApiKey' \ --header 'Content-Type: application/json' \ --header 'X-Api-Key: ApiKeyDefaultValue' \ - --data '["https://some-connector-to-delete/api/v1/ids/data", "https://some-other-connector-to-delete/api/v1/ids/data"]' + --data '["https://some-connector-to-delete/api/dsp", "https://some-other-connector-to-delete/api/dsp"]' ``` #### Compatible Versions @@ -201,7 +210,7 @@ Bugfix / Feature Release for the Broker MvP with MS8: Connectors can now be adde --url 'http://localhost:11002/backend/api/v1/management/wrapper/broker/connectors?adminApiKey=DefaultBrokerServerAdminApiKey' \ --header 'Content-Type: application/json' \ --header 'X-Api-Key: ApiKeyDefaultValue' \ - --data '["https://some-new-connector/api/v1/ids/data", "https://some-other-new-connector/api/v1/ids/data"]' + --data '["https://some-new-connector/api/dsp", "https://some-other-new-connector/api/dsp"]' ``` #### Compatible Versions @@ -248,7 +257,7 @@ Broker MvP using Core EDC MS8. 1. There are new **required** configuration properties: ```yaml # List of Data Space Names for special Connectors (default: '') - EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS: "Mobilithek=https://some-connector/ids/data,OtherDataspace=https://some-other-connector/ids/data" + EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS: "Mobilithek=https://some-connector/api/dsp,OtherDataspace=https://some-other-connector/api/dsp" ``` 2. There are new **optional** configuration properties available for overriding: ```yaml diff --git a/README.md b/README.md index db26877bb..e52b7f175 100644 --- a/README.md +++ b/README.md @@ -115,10 +115,10 @@ MY_EDC_JDBC_USER: edc MY_EDC_JDBC_PASSWORD: edc # Required: List of EDCs to fetch -EDC_BROKER_SERVER_KNOWN_CONNECTORS: "https://connector-a/ids/data,https://connector-b/ids/data" +EDC_BROKER_SERVER_KNOWN_CONNECTORS: "https://connector-a/api/dsp,https://connector-b/api/dsp" # List of Data Space Names for special Connectors (default: '') -EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS: "Mobilithek=https://some-connector/ids/data,OtherDataspace=https://some-other-connector/ids/data" +EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS: "Mobilithek=https://some-connector/api/dsp,OtherDataspace=https://some-other-connector/api/dsp" # Required: DAPS credentials EDC_OAUTH_TOKEN_URL: 'https://daps.test.mobility-dataspace.eu/token' @@ -162,7 +162,7 @@ curl --request PUT \ --url 'http://localhost:11002/backend/api/v1/management/wrapper/broker/connectors?adminApiKey=DefaultBrokerServerAdminApiKey' \ --header 'Content-Type: application/json' \ --header 'X-Api-Key: ApiKeyDefaultValue' \ - --data '["https://some-new-connector/api/v1/ids/data", "https://some-other-new-connector/api/v1/ids/data"]' + --data '["https://some-new-connector/api/dsp", "https://some-other-new-connector/api/dsp"]' ``` #### Removing Connectors at runtime @@ -175,7 +175,7 @@ curl --request DELETE \ --url 'http://localhost:11002/backend/api/v1/management/wrapper/broker/connectors?adminApiKey=DefaultBrokerServerAdminApiKey' \ --header 'Content-Type: application/json' \ --header 'X-Api-Key: ApiKeyDefaultValue' \ - --data '["https://some-connector-to-be-removed/api/v1/ids/data", "https://some-other-connector-to-be-removed/api/v1/ids/data"]' + --data '["https://some-connector-to-be-removed/api/dsp", "https://some-other-connector-to-be-removed/api/dsp"]' ```

(back to top)

diff --git a/build.gradle.kts b/build.gradle.kts index bd4c4bbbe..e3c232a72 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,6 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent + plugins { id("java") id("checkstyle") @@ -26,8 +29,12 @@ allprojects { tasks.getByName("test") { useJUnitPlatform() testLogging { - events("passed", "skipped", "failed") + events = setOf(TestLogEvent.FAILED) + exceptionFormat = TestExceptionFormat.FULL + showExceptions = true + showCauses = true } + failFast = true } checkstyle { diff --git a/connector/.env b/connector/.env index 0afa888d7..587bc2e28 100644 --- a/connector/.env +++ b/connector/.env @@ -33,7 +33,7 @@ EDC_BROKER_SERVER_KNOWN_CONNECTORS= EDC_BROKER_SERVER_DEFAULT_DATASPACE=MDS # List of Data Space Names for special Connectors -# e.g. Mobilithek=https://my-connector1/ids/data,SomeOtherDataspace=https://my-connector2/ids/data +# e.g. Mobilithek=https://my-connector1/api/dsp,SomeOtherDataspace=https://my-connector2/api/dsp EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS= # CRON interval for crawling ONLINE connectors diff --git a/connector/build.gradle.kts b/connector/build.gradle.kts index d373b592a..40f54740a 100644 --- a/connector/build.gradle.kts +++ b/connector/build.gradle.kts @@ -14,7 +14,8 @@ 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}") // JDK Logger implementation("${edcGroup}:monitor-jdk-logger:${edcVersion}") diff --git a/docker-compose.yaml b/docker-compose.yaml index 6beaeab6d..39c2bc8f8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -19,8 +19,8 @@ services: MY_EDC_JDBC_URL: jdbc:postgresql://broker-postgresql:5432/edc MY_EDC_JDBC_USER: edc MY_EDC_JDBC_PASSWORD: edc - EDC_BROKER_SERVER_KNOWN_CONNECTORS: "http://connector:11003/api/v1/ids/data" - EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS: "Mobilithek=https://some-other-connector/ids/data" + EDC_BROKER_SERVER_KNOWN_CONNECTORS: "http://connector:11003/api/dsp" + EDC_BROKER_SERVER_KNOWN_DATASPACE_CONNECTORS: "Mobilithek=https://some-other-connector/api/dsp" # Local Dev / Docker-Compose Config MY_EDC_PROTOCOL: "http://" # We don't have TLS in the docker container @@ -44,7 +44,7 @@ services: POSTGRESQL_PASSWORD: edc POSTGRESQL_DATABASE: edc ports: - - '54321:5432' + - '54321:5432' volumes: - 'broker-postgresql:/bitnami/postgresql' connector-ui: diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/BrokerServerResource.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/BrokerServerResource.java index c24eefe99..92be0fca4 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/BrokerServerResource.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/BrokerServerResource.java @@ -65,7 +65,7 @@ public interface BrokerServerResource { @Path("connector-detail-page") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @Operation(description = "Query a Known Connector's Detail Page") + @Operation(description = "Query a known Connector's Detail Page") ConnectorDetailPageResult connectorDetailPage(ConnectorDetailPageQuery query); @PUT diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogContractOffer.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogContractOffer.java index 87cebdb94..31f4b02a9 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogContractOffer.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogContractOffer.java @@ -14,7 +14,7 @@ package de.sovity.edc.ext.brokerserver.api.model; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDto; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -41,6 +41,6 @@ public class CatalogContractOffer { private OffsetDateTime updatedAt; @Schema(description = "Contract Policy", requiredMode = Schema.RequiredMode.REQUIRED) - private PolicyDto contractPolicy; + private UiPolicy contractPolicy; } diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogDataOffer.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogDataOffer.java index 44bcd3782..4c89b522b 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogDataOffer.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/CatalogDataOffer.java @@ -14,6 +14,7 @@ package de.sovity.edc.ext.brokerserver.api.model; +import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -23,7 +24,6 @@ import java.time.OffsetDateTime; import java.util.List; -import java.util.Map; @Getter @Setter @@ -35,7 +35,7 @@ public class CatalogDataOffer { @Schema(description = "ID of asset", requiredMode = Schema.RequiredMode.REQUIRED) private String assetId; - @Schema(description = "Connector Endpoint", example = "https://my-test.connector/control/ids/data", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Connector Endpoint", example = "https://my-test.connector/api/dsp", requiredMode = Schema.RequiredMode.REQUIRED) private String connectorEndpoint; @Schema(description = "Connector Online Status", requiredMode = Schema.RequiredMode.REQUIRED) @@ -51,7 +51,7 @@ public class CatalogDataOffer { private OffsetDateTime updatedAt; @Schema(description = "Asset properties", requiredMode = Schema.RequiredMode.REQUIRED) - private Map properties; + private UiAsset asset; @Schema(description = "Available Contract Offers", requiredMode = Schema.RequiredMode.REQUIRED) private List contractOffers; diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorDetailPageResult.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorDetailPageResult.java index 3928045a8..74c7c2710 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorDetailPageResult.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorDetailPageResult.java @@ -30,10 +30,10 @@ @AllArgsConstructor @Schema(description = "Connector Detail Page Data") public class ConnectorDetailPageResult { - @Schema(description = "Connector ID", example = "https://my-test.connector", requiredMode = Schema.RequiredMode.REQUIRED) - private String id; + @Schema(description = "Connector Participant ID", example = "https://my-test.connector", requiredMode = Schema.RequiredMode.REQUIRED) + private String participantId; - @Schema(description = "Connector Endpoint", example = "https://my-test.connector/control/ids/data", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Connector Endpoint", example = "https://my-test.connector/api/dsp", requiredMode = Schema.RequiredMode.REQUIRED) private String endpoint; @Schema(description = "Creation date in Broker", requiredMode = Schema.RequiredMode.REQUIRED) @@ -49,7 +49,7 @@ public class ConnectorDetailPageResult { private ConnectorOnlineStatus onlineStatus; @Schema(description = "Number of known data offerings") - private Integer numContractOffers; + private Integer numDataOffers; @Schema(description = "Average time to crawl the connector") private Long connectorCrawlingTimeAvg; diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorListEntry.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorListEntry.java index 42248d5c5..47ee2a661 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorListEntry.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/ConnectorListEntry.java @@ -30,10 +30,10 @@ @AllArgsConstructor @Schema(description = "A Contract Offer's Connector Status") public class ConnectorListEntry { - @Schema(description = "Connector ID", example = "https://my-test.connector", requiredMode = Schema.RequiredMode.REQUIRED) - private String id; + @Schema(description = "Connector Participant ID", example = "my-test-connector", requiredMode = Schema.RequiredMode.REQUIRED) + private String participantId; - @Schema(description = "Connector Endpoint", example = "https://my-test.connector/control/ids/data", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Connector Endpoint", example = "https://my-test.connector/api/dsp", requiredMode = Schema.RequiredMode.REQUIRED) private String endpoint; @Schema(description = "Creation date in Broker", requiredMode = Schema.RequiredMode.REQUIRED) @@ -49,6 +49,6 @@ public class ConnectorListEntry { private ConnectorOnlineStatus onlineStatus; @Schema(description = "Number of known data offerings") - private Integer numContractOffers; + private Integer numDataOffers; } diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailContractOffer.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailContractOffer.java index 6803d2293..c5554c765 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailContractOffer.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailContractOffer.java @@ -14,7 +14,7 @@ package de.sovity.edc.ext.brokerserver.api.model; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDto; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -41,6 +41,6 @@ public class DataOfferDetailContractOffer { private OffsetDateTime updatedAt; @Schema(description = "Contract Policy", requiredMode = Schema.RequiredMode.REQUIRED) - private PolicyDto contractPolicy; + private UiPolicy contractPolicy; } diff --git a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailPageResult.java b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailPageResult.java index bc40b36ea..354a63c81 100644 --- a/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailPageResult.java +++ b/extensions/broker-server-api/api/src/main/java/de/sovity/edc/ext/brokerserver/api/model/DataOfferDetailPageResult.java @@ -14,6 +14,7 @@ package de.sovity.edc.ext.brokerserver.api.model; +import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -23,7 +24,6 @@ import java.time.OffsetDateTime; import java.util.List; -import java.util.Map; @Getter @Setter @@ -35,7 +35,7 @@ public class DataOfferDetailPageResult { @Schema(description = "ID of asset", requiredMode = Schema.RequiredMode.REQUIRED) private String assetId; - @Schema(description = "Connector Endpoint", example = "https://my-test.connector/control/ids/data", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "Connector Endpoint", example = "https://my-test.connector/api/dsp", requiredMode = Schema.RequiredMode.REQUIRED) private String connectorEndpoint; @Schema(description = "Connector Online Status", requiredMode = Schema.RequiredMode.REQUIRED) @@ -51,7 +51,7 @@ public class DataOfferDetailPageResult { private OffsetDateTime updatedAt; @Schema(description = "Asset properties", requiredMode = Schema.RequiredMode.REQUIRED) - private Map properties; + private UiAsset asset; @Schema(description = "Available Contract Offers", requiredMode = Schema.RequiredMode.REQUIRED) private List contractOffers; diff --git a/extensions/broker-server-postgres-flyway-jooq/build.gradle.kts b/extensions/broker-server-postgres-flyway-jooq/build.gradle.kts index a787bffee..12b88dd30 100644 --- a/extensions/broker-server-postgres-flyway-jooq/build.gradle.kts +++ b/extensions/broker-server-postgres-flyway-jooq/build.gradle.kts @@ -46,13 +46,8 @@ dependencies { implementation("org.apache.commons:commons-lang3:3.13.0") implementation("${edcGroup}:core-spi:${edcVersion}") - implementation("${edcGroup}:sql-core:${edcVersion}") // Adds Database-Related EDC-Extensions (EDC-SQL-Stores, JDBC-Driver, Pool and Transactions) - implementation("${edcGroup}:control-plane-sql:${edcVersion}") - 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}") api("org.flywaydb:flyway-core:${flywayVersion}") diff --git a/extensions/broker-server-postgres-flyway-jooq/src/main/java/de/sovity/edc/ext/brokerserver/db/PostgresFlywayExtension.java b/extensions/broker-server-postgres-flyway-jooq/src/main/java/de/sovity/edc/ext/brokerserver/db/PostgresFlywayExtension.java index f4ec17d7e..0dcf2058a 100644 --- a/extensions/broker-server-postgres-flyway-jooq/src/main/java/de/sovity/edc/ext/brokerserver/db/PostgresFlywayExtension.java +++ b/extensions/broker-server-postgres-flyway-jooq/src/main/java/de/sovity/edc/ext/brokerserver/db/PostgresFlywayExtension.java @@ -14,9 +14,6 @@ package de.sovity.edc.ext.brokerserver.db; -import org.eclipse.edc.connector.dataplane.selector.store.sql.schema.DataPlaneInstanceStatements; -import org.eclipse.edc.connector.dataplane.selector.store.sql.schema.postgres.PostgresDataPlaneInstanceStatements; -import org.eclipse.edc.runtime.metamodel.annotation.Provider; import org.eclipse.edc.runtime.metamodel.annotation.Setting; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; @@ -39,11 +36,6 @@ public class PostgresFlywayExtension implements ServiceExtension { @Setting public static final String DB_CONNECTION_TIMEOUT_IN_MS = "edc.broker.server.db.connection.timeout.in.ms"; - @Provider - public DataPlaneInstanceStatements dataPlaneInstanceStatements() { - return new PostgresDataPlaneInstanceStatements(); - } - @Override public String name() { return "Postgres Flyway Extension (Broker Server)"; diff --git a/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/migration/V6__EDC0.sql b/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/migration/V6__EDC0.sql new file mode 100644 index 000000000..c8edbe6fc --- /dev/null +++ b/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/migration/V6__EDC0.sql @@ -0,0 +1,166 @@ +-- Migration Script for Broker from MS8 to EDC 0 + +-- Migrates an Asset ID +create + or replace function pg_temp.migrate_asset_id(asset_id text) returns text as +$$ +begin + return replace(replace(asset_id::text, 'urn:artifact:', ''), ':', '-'); +end; +$$ + language plpgsql; + +-- Migrates a Connector Endpoint to EDC 0 +create + or replace function pg_temp.migrate_connector_endpoint(endpoint text) returns text as +$$ +begin + return pg_temp.replace_suffix(endpoint, '/api/v1/ids/data', '/api/dsp'); +end; +$$ + language plpgsql; + +-- Creates a valid Asset JSON-LD from an Asset ID and Asset Title +create + or replace function pg_temp.build_asset_json_ld(asset_id text, asset_title text) returns jsonb as +$$ +begin + return jsonb_build_object( + '@id', asset_id, + 'https://w3id.org/edc/v0.0.1/ns/properties', jsonb_build_object( + 'https://w3id.org/edc/v0.0.1/ns/id', asset_id, + 'http://purl.org/dc/terms/title', asset_title + ) + ); +end; +$$ + language plpgsql; + +-- Utility Function: replaceSuffix +create + or replace function pg_temp.replace_suffix(str text, old_suffix text, new_suffix text) returns text as +$$ +begin + return case + when pg_temp.ends_with(str, old_suffix) then + left(str, length(str) - length(old_suffix)) || new_suffix + else + str + end; +end; +$$ + language plpgsql; + +-- Utility Function: endsWith +create or replace function pg_temp.ends_with(str text, suffix text) + returns boolean as +$$ +begin + return right(str, length(suffix)) = suffix; +end; +$$ language plpgsql; + +-- Utility Function: Drops fkey constraints that have auto-generated names. Different Postgresql versions generated different names. +create or replace function pg_temp.drop_constraints_containing_fkey(table_name text) + returns void as +$$ +declare + i record; +begin + for i in (select conname + from pg_catalog.pg_constraint con + inner join pg_catalog.pg_class rel on rel.oid = con.conrelid + inner join pg_catalog.pg_namespace nsp on nsp.oid = connamespace + where rel.relname = table_name + and conname like '%fkey%') + loop + execute format('alter table %s drop constraint %s', table_name, i.conname); + end loop; +end; +$$ language plpgsql; + + +-- Remove Connector Tables +-- All connector tables should be empty +-- There should be no references from broker tables to connector tables +drop table edc_asset cascade; +drop table edc_asset_dataaddress cascade; +drop table edc_asset_property cascade; +drop table edc_contract_agreement cascade; +drop table edc_contract_definitions cascade; +drop table edc_contract_negotiation cascade; +drop table edc_data_plane_instance cascade; +drop table edc_data_request cascade; +drop table edc_lease cascade; +drop table edc_policydefinitions cascade; +drop table edc_transfer_process cascade; + + +-- Drop constraints +select pg_temp.drop_constraints_containing_fkey('data_offer'); +select pg_temp.drop_constraints_containing_fkey('data_offer_contract_offer'); + +-- Migrate Connector Endpoints +update broker_event_log +set connector_endpoint = pg_temp.migrate_connector_endpoint(connector_endpoint); +update broker_execution_time_measurement +set connector_endpoint = pg_temp.migrate_connector_endpoint(connector_endpoint); +update connector +set endpoint = pg_temp.migrate_connector_endpoint(endpoint); +update data_offer +set connector_endpoint = pg_temp.migrate_connector_endpoint(connector_endpoint); +update data_offer_contract_offer +set connector_endpoint = pg_temp.migrate_connector_endpoint(connector_endpoint); +update data_offer_view_count +set connector_endpoint = pg_temp.migrate_connector_endpoint(connector_endpoint); + + +-- Migrate Asset IDs +update broker_event_log +set asset_id = pg_temp.migrate_asset_id(asset_id); +update data_offer +set asset_id = pg_temp.migrate_asset_id(asset_id); +update data_offer_contract_offer +set asset_id = pg_temp.migrate_asset_id(asset_id); +update data_offer_view_count +set asset_id = pg_temp.migrate_asset_id(asset_id); + +-- Rename data_offer_contract_offer to contract_offer +alter table data_offer_contract_offer + rename to contract_offer; + +-- Rename Connector ID to Participant ID +alter table connector + rename column connector_id to participant_id; + +-- Add constraints +alter table data_offer + add constraint data_offer_connector_endpoint_fkey + foreign key (connector_endpoint) references connector (endpoint); +alter table contract_offer + add constraint contract_offer_data_offer_fkey + foreign key (connector_endpoint, asset_id) references data_offer (connector_endpoint, asset_id); +alter table contract_offer + add constraint contract_offer_connector_fkey + foreign key (connector_endpoint) references connector (endpoint); + +-- Migrate to Asset JSON-LD +alter table data_offer + rename column asset_properties to asset_json_ld; +alter table data_offer + rename column asset_name to asset_title; +update data_offer +set asset_json_ld = pg_temp.build_asset_json_ld(asset_id, asset_title); + +-- Extracted Asset Metadata from the JSON-LD for Search / Filtering +alter table data_offer + add column description text not null default '', + add column curator_organization_name text not null default '', + add column data_category text not null default '', + add column data_subcategory text not null default '', + add column data_model text not null default '', + add column transport_mode text not null default '', + add column geo_reference_method text not null default '', + add column keywords text[] not null default '{}', + -- comma joined keywords for easier search + add column keywords_comma_joined text not null default ''; diff --git a/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/testdata/V2_1__PoC_Test_Data.sql b/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/testdata/V2_1__PoC_Test_Data.sql index b3235f637..fd42a12dd 100644 --- a/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/testdata/V2_1__PoC_Test_Data.sql +++ b/extensions/broker-server-postgres-flyway-jooq/src/main/resources/db/testdata/V2_1__PoC_Test_Data.sql @@ -2,23 +2,23 @@ insert into connector (endpoint, connector_id, created_at, last_refresh_attempt_at, last_successful_refresh_at, online_status) -values ('https://my-connector.com/ids/data', 'test-connector-1', '2019-01-01 00:00:00', +values ('https://my-connector.com/api/v1/ids/data', 'test-connector-1', '2019-01-01 00:00:00', '2019-01-01 00:00:00', '2019-01-01 00:00:00', 'ONLINE'); insert into data_offer (connector_endpoint, asset_id, asset_properties, created_at, updated_at) -values ('https://my-connector.com/ids/data', +values ('https://my-connector.com/api/v1/ids/data', 'test-asset-1', '{ "asset:prop:id": "test-asset-1" }', '2019-01-01 00:00:00', '2019-01-01 00:00:00'), - ('https://my-connector.com/ids/data', + ('https://my-connector.com/api/v1/ids/data', 'test-asset-2', '{ "asset:prop:id": "urn:artifact:db-rail-network-2023-jan", "asset:prop:name": "Rail Network DB 2023 January", "asset:prop:version": "1.1", - "asset:prop:originator": "https://example-connector.rail-mgmt.bahn.de/api/v1/ids/data", + "asset:prop:originator": "https://example-connector.rail-mgmt.bahn.de/api/v1/api/v1/ids/data", "asset:prop:originatorOrganization": "Deutsche Bahn AG", "asset:prop:keywords": "db, bahn, rail, Rail-Designer", "asset:prop:contenttype": "application/json", @@ -38,13 +38,13 @@ values ('https://my-connector.com/ids/data', insert into data_offer_contract_offer (contract_offer_id, connector_endpoint, asset_id, policy, created_at, updated_at) values ('test-contract-offer-1', - 'https://my-connector.com/ids/data', + 'https://my-connector.com/api/v1/ids/data', 'test-asset-1', '"test-policy-1"', '2019-01-01 00:00:00', '2019-01-01 00:00:00'), ('test-contract-offer-2', - 'https://my-connector.com/ids/data', + 'https://my-connector.com/api/v1/ids/data', 'test-asset-2', '"test-policy-2"', '2019-01-01 00:00:00', @@ -56,13 +56,13 @@ values ('2019-01-01 00:00:00', 'Connector was successfully updated, and changes were incorporated', 'CONNECTOR_UPDATED', 'OK', - 'https://my-connector.com/ids/data', + 'https://my-connector.com/api/v1/ids/data', 'test-asset-1', null, 100); insert into broker_execution_time_measurement (connector_endpoint, created_at, type, error_status, duration_in_ms) -values ('https://my-connector.com/ids/data', +values ('https://my-connector.com/api/v1/ids/data', '2019-01-01 00:00:00', 'CONNECTOR_REFRESH', 'OK', diff --git a/extensions/broker-server/build.gradle.kts b/extensions/broker-server/build.gradle.kts index aec9ba7b1..0e92eb5e6 100644 --- a/extensions/broker-server/build.gradle.kts +++ b/extensions/broker-server/build.gradle.kts @@ -11,6 +11,7 @@ val okHttpVersion: String by project val restAssured: String by project val testcontainersVersion: String by project val sovityEdcGroup: String by project +val sovityEdcExtensionGroup: String by project val sovityEdcExtensionsVersion: String by project configurations.all { @@ -22,6 +23,10 @@ dependencies { compileOnly("org.projectlombok:lombok:1.18.30") implementation("org.apache.commons:commons-lang3:3.13.0") + api("${sovityEdcGroup}:catalog-parser:${sovityEdcExtensionsVersion}") { isChanging = true } + api("${sovityEdcGroup}:json-and-jsonld-utils:${sovityEdcExtensionsVersion}") { isChanging = true } + api("${sovityEdcGroup}:wrapper-common-mappers:${sovityEdcExtensionsVersion}") { isChanging = true } + implementation("${edcGroup}:control-plane-spi:${edcVersion}") implementation("${edcGroup}:management-api-configuration:${edcVersion}") @@ -32,14 +37,18 @@ dependencies { testAnnotationProcessor("org.projectlombok:lombok:1.18.30") testCompileOnly("org.projectlombok:lombok:1.18.30") + testImplementation("${sovityEdcGroup}:client:${sovityEdcExtensionsVersion}") { isChanging = true } + testImplementation("${sovityEdcExtensionGroup}:sovity-edc-extensions-package:${sovityEdcExtensionsVersion}") { isChanging = true } testImplementation("org.assertj:assertj-core:${assertj}") testImplementation("org.mockito:mockito-core:${mockitoVersion}") testImplementation("org.mockito:mockito-inline:${mockitoVersion}") testImplementation("${edcGroup}:control-plane-core:${edcVersion}") + testImplementation("${edcGroup}:data-plane-selector-core:${edcVersion}") testImplementation("${edcGroup}:junit:${edcVersion}") testImplementation("${edcGroup}:http:${edcVersion}") testImplementation("${edcGroup}:iam-mock:${edcVersion}") - testImplementation("${edcGroup}:ids:${edcVersion}") + testImplementation("${edcGroup}:dsp:${edcVersion}") + testImplementation("${edcGroup}:json-ld:${edcVersion}") testImplementation("${edcGroup}:monitor-jdk-logger:${edcVersion}") testImplementation("${edcGroup}:configuration-filesystem:${edcVersion}") testImplementation(project(":extensions:broker-server-api:client")) diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtension.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtension.java index 65c61f688..3b288ea13 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtension.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtension.java @@ -15,7 +15,9 @@ package de.sovity.edc.ext.brokerserver; import org.eclipse.edc.connector.api.management.configuration.ManagementApiConfiguration; +import org.eclipse.edc.connector.api.management.configuration.transform.ManagementApiTypeTransformerRegistry; import org.eclipse.edc.connector.spi.catalog.CatalogService; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Setting; import org.eclipse.edc.spi.system.ServiceExtension; @@ -80,6 +82,12 @@ public class BrokerServerExtension implements ServiceExtension { @Inject private TypeManager typeManager; + @Inject + private ManagementApiTypeTransformerRegistry typeTransformerRegistry; + + @Inject + private JsonLd jsonLd; + @Inject private CatalogService catalogService; @@ -99,6 +107,8 @@ public void initialize(ServiceExtensionContext context) { context.getConfig(), context.getMonitor(), typeManager, + typeTransformerRegistry, + jsonLd, catalogService ); diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContext.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContext.java index f9010ec1d..3dd8bd2fa 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContext.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContext.java @@ -18,6 +18,9 @@ import de.sovity.edc.ext.brokerserver.services.BrokerServerInitializer; import de.sovity.edc.ext.brokerserver.services.ConnectorCreator; import de.sovity.edc.ext.brokerserver.services.refreshing.ConnectorUpdater; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferRecordUpdater; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.FetchedCatalogBuilder; +import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; /** @@ -32,7 +35,10 @@ public record BrokerServerExtensionContext( // Required for Integration Tests ConnectorUpdater connectorUpdater, - ConnectorCreator connectorCreator + ConnectorCreator connectorCreator, + PolicyMapper policyMapper, + FetchedCatalogBuilder fetchedCatalogBuilder, + DataOfferRecordUpdater dataOfferRecordUpdater ) { /** * This is a hack for our tests. diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContextBuilder.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContextBuilder.java index 330c9f53b..89b7477b9 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContextBuilder.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerExtensionContextBuilder.java @@ -14,8 +14,11 @@ package de.sovity.edc.ext.brokerserver; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import de.sovity.edc.ext.brokerserver.dao.ConnectorQueries; -import de.sovity.edc.ext.brokerserver.dao.DataOfferContractOfferQueries; +import de.sovity.edc.ext.brokerserver.dao.ContractOfferQueries; import de.sovity.edc.ext.brokerserver.dao.DataOfferQueries; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQueryAvailableFilterFetcher; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQueryContractOfferFetcher; @@ -23,7 +26,8 @@ import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQueryFilterService; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQueryService; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQuerySortingService; -import de.sovity.edc.ext.brokerserver.dao.pages.connector.ConnectorPageQueryService; +import de.sovity.edc.ext.brokerserver.dao.pages.connector.ConnectorDetailQueryService; +import de.sovity.edc.ext.brokerserver.dao.pages.connector.ConnectorListQueryService; import de.sovity.edc.ext.brokerserver.dao.pages.dataoffer.DataOfferDetailPageQueryService; import de.sovity.edc.ext.brokerserver.dao.pages.dataoffer.ViewCountLogger; import de.sovity.edc.ext.brokerserver.db.DataSourceFactory; @@ -34,16 +38,19 @@ import de.sovity.edc.ext.brokerserver.services.ConnectorKiller; import de.sovity.edc.ext.brokerserver.services.KnownConnectorsInitializer; import de.sovity.edc.ext.brokerserver.services.OfflineConnectorKiller; -import de.sovity.edc.ext.brokerserver.services.api.AssetPropertyParser; import de.sovity.edc.ext.brokerserver.services.api.CatalogApiService; import de.sovity.edc.ext.brokerserver.services.api.ConnectorApiService; +import de.sovity.edc.ext.brokerserver.services.api.ConnectorDetailApiService; +import de.sovity.edc.ext.brokerserver.services.api.ConnectorListApiService; +import de.sovity.edc.ext.brokerserver.services.api.ConnectorOnlineStatusMapper; import de.sovity.edc.ext.brokerserver.services.api.ConnectorService; import de.sovity.edc.ext.brokerserver.services.api.DataOfferCountApiService; import de.sovity.edc.ext.brokerserver.services.api.DataOfferDetailApiService; +import de.sovity.edc.ext.brokerserver.services.api.DataOfferMappingUtils; import de.sovity.edc.ext.brokerserver.services.api.PaginationMetadataUtils; -import de.sovity.edc.ext.brokerserver.services.api.PolicyDtoBuilder; import de.sovity.edc.ext.brokerserver.services.api.filtering.CatalogFilterAttributeDefinitionService; import de.sovity.edc.ext.brokerserver.services.api.filtering.CatalogFilterService; +import de.sovity.edc.ext.brokerserver.services.api.filtering.CatalogSearchService; import de.sovity.edc.ext.brokerserver.services.config.AdminApiKeyValidator; import de.sovity.edc.ext.brokerserver.services.config.BrokerServerSettingsFactory; import de.sovity.edc.ext.brokerserver.services.logging.BrokerEventLogger; @@ -55,27 +62,41 @@ import de.sovity.edc.ext.brokerserver.services.refreshing.ConnectorUpdateFailureWriter; import de.sovity.edc.ext.brokerserver.services.refreshing.ConnectorUpdateSuccessWriter; import de.sovity.edc.ext.brokerserver.services.refreshing.ConnectorUpdater; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.ContractOfferFetcher; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.CatalogFetcher; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.ContractOfferRecordUpdater; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferBuilder; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferFetcher; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferLimitsEnforcer; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferPatchApplier; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferPatchBuilder; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferRecordUpdater; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferWriter; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.FetchedCatalogBuilder; import de.sovity.edc.ext.brokerserver.services.schedules.DeadConnectorRefreshJob; import de.sovity.edc.ext.brokerserver.services.schedules.OfflineConnectorKillerJob; import de.sovity.edc.ext.brokerserver.services.schedules.OfflineConnectorRefreshJob; import de.sovity.edc.ext.brokerserver.services.schedules.OnlineConnectorRefreshJob; import de.sovity.edc.ext.brokerserver.services.schedules.QuartzScheduleInitializer; import de.sovity.edc.ext.brokerserver.services.schedules.utils.CronJobRef; +import de.sovity.edc.ext.wrapper.api.common.mappers.AssetMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.OperatorMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.AssetJsonLdUtils; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.AtomicConstraintMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.ConstraintExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.EdcPropertyUtils; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.LiteralMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.PolicyValidator; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.UiAssetMapper; +import de.sovity.edc.utils.catalog.DspCatalogService; +import de.sovity.edc.utils.catalog.mapper.DspDataOfferBuilder; import lombok.NoArgsConstructor; import org.eclipse.edc.connector.spi.catalog.CatalogService; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.CoreConstants; import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.configuration.Config; import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -96,6 +117,8 @@ public static BrokerServerExtensionContext buildContext( Config config, Monitor monitor, TypeManager typeManager, + TypeTransformerRegistry typeTransformerRegistry, + JsonLd jsonLd, CatalogService catalogService ) { var brokerServerSettingsFactory = new BrokerServerSettingsFactory(config, monitor); @@ -109,7 +132,8 @@ public static BrokerServerExtensionContext buildContext( var dslContextFactory = new DslContextFactory(dataSource); var connectorQueries = new ConnectorQueries(); var catalogQuerySortingService = new CatalogQuerySortingService(); - var catalogQueryFilterService = new CatalogQueryFilterService(brokerServerSettings); + var catalogSearchService = new CatalogSearchService(); + var catalogQueryFilterService = new CatalogQueryFilterService(brokerServerSettings, catalogSearchService); var catalogQueryContractOfferFetcher = new CatalogQueryContractOfferFetcher(); var catalogQueryDataOfferFetcher = new CatalogQueryDataOfferFetcher( catalogQuerySortingService, @@ -122,21 +146,22 @@ public static BrokerServerExtensionContext buildContext( catalogQueryAvailableFilterFetcher, brokerServerSettings ); - var connectorPageQueryService = new ConnectorPageQueryService(); + var connectorListQueryService = new ConnectorListQueryService(); + var connectorDetailQueryService = new ConnectorDetailQueryService(); var dataOfferDetailPageQueryService = new DataOfferDetailPageQueryService( catalogQueryContractOfferFetcher, brokerServerSettings); // Services - var objectMapper = typeManager.getMapper(); + var objectMapperJsonLd = getJsonLdObjectMapper(typeManager); var brokerEventLogger = new BrokerEventLogger(); var brokerExecutionTimeLogger = new BrokerExecutionTimeLogger(); var contractOfferRecordUpdater = new ContractOfferRecordUpdater(); var dataOfferRecordUpdater = new DataOfferRecordUpdater(); - var dataOfferContractOfferQueries = new DataOfferContractOfferQueries(); + var contractOfferQueries = new ContractOfferQueries(); var dataOfferLimitsEnforcer = new DataOfferLimitsEnforcer(brokerServerSettings, brokerEventLogger); var dataOfferPatchBuilder = new DataOfferPatchBuilder( - dataOfferContractOfferQueries, + contractOfferQueries, dataOfferQueries, dataOfferRecordUpdater, contractOfferRecordUpdater @@ -148,10 +173,25 @@ public static BrokerServerExtensionContext buildContext( dataOfferWriter, dataOfferLimitsEnforcer ); + var edcPropertyUtils = new EdcPropertyUtils(); + var assetJsonLdUtils = new AssetJsonLdUtils(); + var uiAssetMapper = new UiAssetMapper( + edcPropertyUtils, + assetJsonLdUtils + ); + var assetMapper = new AssetMapper( + typeTransformerRegistry, + uiAssetMapper, + jsonLd + ); + var fetchedDataOfferBuilder = new FetchedCatalogBuilder(assetMapper); + var dspDataOfferBuilder = new DspDataOfferBuilder(jsonLd); + var dspCatalogService = new DspCatalogService( + catalogService, + dspDataOfferBuilder + ); + var dataOfferFetcher = new CatalogFetcher(dspCatalogService, fetchedDataOfferBuilder); var connectorUpdateFailureWriter = new ConnectorUpdateFailureWriter(brokerEventLogger, monitor); - var contractOfferFetcher = new ContractOfferFetcher(catalogService); - var fetchedDataOfferBuilder = new DataOfferBuilder(objectMapper); - var dataOfferFetcher = new DataOfferFetcher(contractOfferFetcher, fetchedDataOfferBuilder); var connectorUpdater = new ConnectorUpdater( dataOfferFetcher, connectorUpdateSuccessWriter, @@ -161,8 +201,6 @@ public static BrokerServerExtensionContext buildContext( monitor, brokerExecutionTimeLogger ); - var policyDtoBuilder = new PolicyDtoBuilder(); - var assetPropertyParser = new AssetPropertyParser(objectMapper); var paginationMetadataUtils = new PaginationMetadataUtils(); var threadPoolTaskQueue = new ThreadPoolTaskQueue(); var threadPool = new ThreadPool(threadPoolTaskQueue, brokerServerSettings, monitor); @@ -187,6 +225,29 @@ public static BrokerServerExtensionContext buildContext( connectorKiller, connectorClearer ); + var operatorMapper = new OperatorMapper(); + var literalMapper = new LiteralMapper( + objectMapperJsonLd + ); + var atomicConstraintMapper = new AtomicConstraintMapper( + literalMapper, + operatorMapper + ); + var policyValidator = new PolicyValidator(); + var constraintExtractor = new ConstraintExtractor( + policyValidator, + atomicConstraintMapper + ); + var policyMapper = new PolicyMapper( + constraintExtractor, + atomicConstraintMapper, + typeTransformerRegistry + ); + var dataOfferMappingUtils = new DataOfferMappingUtils( + policyMapper, + assetMapper + ); + var connectorOnlineStatusMapper = new ConnectorOnlineStatusMapper(); // Schedules List> jobs = List.of( @@ -208,27 +269,27 @@ public static BrokerServerExtensionContext buildContext( var catalogApiService = new CatalogApiService( paginationMetadataUtils, catalogQueryService, - policyDtoBuilder, - assetPropertyParser, + dataOfferMappingUtils, catalogFilterService, brokerServerSettings ); var connectorApiService = new ConnectorApiService( - connectorPageQueryService, connectorService, - paginationMetadataUtils, brokerEventLogger ); var dataOfferDetailApiService = new DataOfferDetailApiService( dataOfferDetailPageQueryService, viewCountLogger, - policyDtoBuilder, - assetPropertyParser + dataOfferMappingUtils ); var dataOfferCountApiService = new DataOfferCountApiService(); + var connectorDetailApiService = new ConnectorDetailApiService(connectorDetailQueryService, connectorOnlineStatusMapper); + var connectorListApiService = new ConnectorListApiService(connectorListQueryService, connectorOnlineStatusMapper, paginationMetadataUtils); var brokerServerResource = new BrokerServerResourceImpl( dslContextFactory, connectorApiService, + connectorListApiService, + connectorDetailApiService, catalogApiService, dataOfferDetailApiService, adminApiKeyValidator, @@ -239,7 +300,10 @@ public static BrokerServerExtensionContext buildContext( brokerServerResource, brokerServerInitializer, connectorUpdater, - connectorCreator + connectorCreator, + policyMapper, + fetchedDataOfferBuilder, + dataOfferRecordUpdater ); } @@ -278,4 +342,15 @@ private static CronJobRef getDeadConnectorRefreshCronJo () -> new DeadConnectorRefreshJob(dslContextFactory, connectorQueueFiller) ); } + + private static ObjectMapper getJsonLdObjectMapper(TypeManager typeManager) { + var objectMapper = typeManager.getMapper(CoreConstants.JSON_LD); + + // Fixes Dates in JSON-LD Object Mapper + // The Core EDC uses longs over OffsetDateTime, so they never fixed the date format + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + + return objectMapper; + } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerResourceImpl.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerResourceImpl.java index eb34766e1..32fc227ff 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerResourceImpl.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/BrokerServerResourceImpl.java @@ -27,6 +27,8 @@ import de.sovity.edc.ext.brokerserver.db.DslContextFactory; import de.sovity.edc.ext.brokerserver.services.api.CatalogApiService; import de.sovity.edc.ext.brokerserver.services.api.ConnectorApiService; +import de.sovity.edc.ext.brokerserver.services.api.ConnectorDetailApiService; +import de.sovity.edc.ext.brokerserver.services.api.ConnectorListApiService; import de.sovity.edc.ext.brokerserver.services.api.DataOfferCountApiService; import de.sovity.edc.ext.brokerserver.services.api.DataOfferDetailApiService; import de.sovity.edc.ext.brokerserver.services.config.AdminApiKeyValidator; @@ -42,6 +44,8 @@ public class BrokerServerResourceImpl implements BrokerServerResource { private final DslContextFactory dslContextFactory; private final ConnectorApiService connectorApiService; + private final ConnectorListApiService connectorListApiService; + private final ConnectorDetailApiService connectorDetailApiService; private final CatalogApiService catalogApiService; private final DataOfferDetailApiService dataOfferDetailApiService; private final AdminApiKeyValidator adminApiKeyValidator; @@ -54,7 +58,7 @@ public CatalogPageResult catalogPage(CatalogPageQuery query) { @Override public ConnectorPageResult connectorPage(ConnectorPageQuery query) { - return dslContextFactory.transactionResult(dsl -> connectorApiService.connectorPage(dsl, query)); + return dslContextFactory.transactionResult(dsl -> connectorListApiService.connectorListPage(dsl, query)); } @Override @@ -64,7 +68,7 @@ public DataOfferDetailPageResult dataOfferDetailPage(DataOfferDetailPageQuery qu @Override public ConnectorDetailPageResult connectorDetailPage(ConnectorDetailPageQuery query) { - return dslContextFactory.transactionResult(dsl -> connectorApiService.connectorDetailPage(dsl, query)); + return dslContextFactory.transactionResult(dsl -> connectorDetailApiService.connectorDetailPage(dsl, query)); } @Override diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/AssetProperty.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/AssetProperty.java deleted file mode 100644 index 9d24f3bf2..000000000 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/AssetProperty.java +++ /dev/null @@ -1,44 +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.brokerserver.dao; - - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class AssetProperty { - public static final String ASSET_ID = "asset:prop:id"; - public static final String ASSET_NAME = "asset:prop:name"; - public static final String DESCRIPTION = "asset:prop:description"; - public static final String KEYWORDS = "asset:prop:keywords"; - - - public static final String CONTENT_TYPE = "asset:prop:contenttype"; - public static final String ORIGINATOR = "asset:prop:originator"; - public static final String ORIGINATOR_ORGANIZATION = "asset:prop:originatorOrganization"; - public static final String VERSION = "asset:prop:version"; - public static final String CURATOR_ORGANIZATION_NAME = "asset:prop:curatorOrganizationName"; - public static final String LANGUAGE = "asset:prop:language"; - public static final String PUBLISHER = "asset:prop:publisher"; - public static final String STANDARD_LICENSE = "asset:prop:standardLicense"; - public static final String ENDPOINT_DOCUMENTATION = "asset:prop:endpointDocumentation"; - - public static final String DATA_CATEGORY = "http://w3id.org/mds#dataCategory"; - public static final String DATA_SUBCATEGORY = "http://w3id.org/mds#dataSubcategory"; - public static final String DATA_MODEL = "http://w3id.org/mds#dataModel"; - public static final String GEO_REFERENCE_METHOD = "http://w3id.org/mds#geoReferenceMethod"; - public static final String TRANSPORT_MODE = "http://w3id.org/mds#transportMode"; -} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/DataOfferContractOfferQueries.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/ContractOfferQueries.java similarity index 67% rename from extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/DataOfferContractOfferQueries.java rename to extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/ContractOfferQueries.java index c02d0d52c..be5ef734c 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/DataOfferContractOfferQueries.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/ContractOfferQueries.java @@ -15,15 +15,15 @@ package de.sovity.edc.ext.brokerserver.dao; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; -import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferContractOfferRecord; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ContractOfferRecord; import org.jooq.DSLContext; import java.util.List; -public class DataOfferContractOfferQueries { +public class ContractOfferQueries { - public List findByConnectorEndpoint(DSLContext dsl, String connectorEndpoint) { - var co = Tables.DATA_OFFER_CONTRACT_OFFER; + public List findByConnectorEndpoint(DSLContext dsl, String connectorEndpoint) { + var co = Tables.CONTRACT_OFFER; return dsl.selectFrom(co).where(co.CONNECTOR_ENDPOINT.eq(connectorEndpoint)).stream().toList(); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryAvailableFilterFetcher.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryAvailableFilterFetcher.java index 564f20a38..ee3fdd7aa 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryAvailableFilterFetcher.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryAvailableFilterFetcher.java @@ -68,7 +68,7 @@ private Field queryFilterValues( return DSL.select(DSL.coalesce(DSL.arrayAggDistinct(value), DSL.array().cast(SQLDataType.VARCHAR.array()))) .from(d) .leftJoin(c).on(c.ENDPOINT.eq(d.CONNECTOR_ENDPOINT)) - .where(catalogQueryFilterService.filter(fields, searchQuery, otherFilters)) + .where(catalogQueryFilterService.filterDbQuery(fields, searchQuery, otherFilters)) .asField(); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryContractOfferFetcher.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryContractOfferFetcher.java index 364c7683b..d2e370c5c 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryContractOfferFetcher.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryContractOfferFetcher.java @@ -17,6 +17,7 @@ import de.sovity.edc.ext.brokerserver.dao.pages.dataoffer.model.ContractOfferRs; import de.sovity.edc.ext.brokerserver.dao.utils.MultisetUtils; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.DataOffer; import lombok.RequiredArgsConstructor; import org.jooq.Field; import org.jooq.impl.DSL; @@ -29,12 +30,11 @@ public class CatalogQueryContractOfferFetcher { /** * Query a data offer's contract offers. * - * @param fields query fields + * @param d Data offer table * @return {@link Field} of {@link ContractOfferRs}s */ - public Field> getContractOffers(CatalogQueryFields fields) { - var d = fields.getDataOfferTable(); - var co = Tables.DATA_OFFER_CONTRACT_OFFER; + public Field> getContractOffers(DataOffer d) { + var co = Tables.CONTRACT_OFFER; var query = DSL.select( co.CONTRACT_OFFER_ID, diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryDataOfferFetcher.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryDataOfferFetcher.java index 771ad908d..8c98af7b2 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryDataOfferFetcher.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryDataOfferFetcher.java @@ -55,18 +55,19 @@ public Field> queryDataOffers( var d = fields.getDataOfferTable(); var select = DSL.select( - fields.getAssetId().as("assetId"), - d.ASSET_PROPERTIES.cast(String.class).as("assetPropertiesJson"), + d.ASSET_ID.as("assetId"), + d.ASSET_JSON_LD.cast(String.class).as("assetJsonLd"), d.CREATED_AT, d.UPDATED_AT, - catalogQueryContractOfferFetcher.getContractOffers(fields).as("contractOffers"), + catalogQueryContractOfferFetcher.getContractOffers(d).as("contractOffers"), c.ENDPOINT.as("connectorEndpoint"), c.ONLINE_STATUS.as("connectorOnlineStatus"), + c.PARTICIPANT_ID.as("connectorParticipantId"), fields.getOfflineSinceOrLastUpdatedAt().as("connectorOfflineSinceOrLastUpdatedAt") ); var query = from(select, fields) - .where(catalogQueryFilterService.filter(fields, searchQuery, filters)) + .where(catalogQueryFilterService.filterDbQuery(fields, searchQuery, filters)) .orderBy(catalogQuerySortingService.getOrderBy(fields, sorting)) .limit(pageQuery.offset(), pageQuery.limit()); @@ -83,7 +84,7 @@ public Field> queryDataOffers( */ public Field queryNumDataOffers(CatalogQueryFields fields, String searchQuery, List filters) { var query = from(DSL.select(DSL.count()), fields) - .where(catalogQueryFilterService.filter(fields, searchQuery, filters)); + .where(catalogQueryFilterService.filterDbQuery(fields, searchQuery, filters)); return DSL.field(query); } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFields.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFields.java index 7f255b146..f9dc09795 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFields.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFields.java @@ -14,8 +14,6 @@ package de.sovity.edc.ext.brokerserver.dao.pages.catalog; -import com.github.t9t.jooq.json.JsonbDSL; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.db.jooq.tables.Connector; import de.sovity.edc.ext.brokerserver.db.jooq.tables.DataOffer; import de.sovity.edc.ext.brokerserver.db.jooq.tables.DataOfferViewCount; @@ -42,10 +40,6 @@ public class CatalogQueryFields { DataOfferViewCount dataOfferViewCountTable; // Asset Properties from JSON to be used in sorting / filtering - Field assetId; - Field assetName; - Field assetDescription; - Field assetKeywords; Field dataSpace; // This date should always be non-null @@ -64,10 +58,6 @@ public CatalogQueryFields( this.dataOfferTable = dataOfferTable; this.dataOfferViewCountTable = dataOfferViewCountTable; this.dataSpaceConfig = dataSpaceConfig; - assetId = dataOfferTable.ASSET_ID; - assetName = dataOfferTable.ASSET_NAME; - assetDescription = getAssetProperty(AssetProperty.DESCRIPTION); - assetKeywords = getAssetProperty(AssetProperty.KEYWORDS); offlineSinceOrLastUpdatedAt = DSL.coalesce( connectorTable.LAST_SUCCESSFUL_REFRESH_AT, connectorTable.CREATED_AT @@ -94,10 +84,6 @@ private Field buildDataSpaceField(Connector connectorTable, DataSpaceCon return dspCase.else_(DSL.val(dataSpaceConfig.defaultDataSpace())); } - public Field getAssetProperty(String name) { - return JsonbDSL.fieldByKeyText(dataOfferTable.ASSET_PROPERTIES, name); - } - public CatalogQueryFields withSuffix(String additionalSuffix) { return new CatalogQueryFields( connectorTable.as(withSuffix(connectorTable, additionalSuffix)), diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFilterService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFilterService.java index 9f83645be..b92af8920 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFilterService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQueryFilterService.java @@ -14,11 +14,10 @@ package de.sovity.edc.ext.brokerserver.dao.pages.catalog; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.models.CatalogQueryFilter; -import de.sovity.edc.ext.brokerserver.dao.utils.SearchUtils; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; import de.sovity.edc.ext.brokerserver.db.jooq.tables.Connector; +import de.sovity.edc.ext.brokerserver.services.api.filtering.CatalogSearchService; import de.sovity.edc.ext.brokerserver.services.config.BrokerServerSettings; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; @@ -33,18 +32,11 @@ @RequiredArgsConstructor public class CatalogQueryFilterService { private final BrokerServerSettings brokerServerSettings; + private final CatalogSearchService catalogSearchService; - public Condition filter(CatalogQueryFields fields, String searchQuery, List filters) { + public Condition filterDbQuery(CatalogQueryFields fields, String searchQuery, List filters) { var conditions = new ArrayList(); - conditions.add(SearchUtils.simpleSearch(searchQuery, List.of( - fields.getAssetId(), - fields.getAssetName(), - fields.getAssetProperty(AssetProperty.DATA_CATEGORY), - fields.getAssetProperty(AssetProperty.DATA_SUBCATEGORY), - fields.getAssetDescription(), - fields.getAssetKeywords(), - fields.getConnectorTable().ENDPOINT - ))); + conditions.add(catalogSearchService.filterBySearch(fields, searchQuery)); conditions.add(onlyOnlineOrRecentlyOfflineConnectors(fields.getConnectorTable())); conditions.addAll(filters.stream().map(CatalogQueryFilter::queryFilterClauseOrNull) .filter(Objects::nonNull).map(it -> it.filterDataOffers(fields)).toList()); diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQuerySortingService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQuerySortingService.java index b643d0f57..e08fdfe46 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQuerySortingService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/CatalogQuerySortingService.java @@ -28,7 +28,7 @@ public List> getOrderBy(CatalogQueryFields fields, CatalogPageSort List> orderBy; if (sorting == null || sorting == CatalogPageSortingType.TITLE) { orderBy = List.of( - fields.getAssetName().asc(), + fields.getDataOfferTable().ASSET_TITLE.asc(), fields.getConnectorTable().ENDPOINT.asc() ); } else if (sorting == CatalogPageSortingType.MOST_RECENT) { @@ -39,7 +39,7 @@ public List> getOrderBy(CatalogQueryFields fields, CatalogPageSort } else if (sorting == CatalogPageSortingType.ORIGINATOR) { orderBy = List.of( fields.getConnectorTable().ENDPOINT.asc(), - fields.getAssetName().asc() + fields.getDataOfferTable().ASSET_TITLE.asc() ); } else if (sorting == CatalogPageSortingType.VIEW_COUNT) { orderBy = List.of( diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/models/DataOfferListEntryRs.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/models/DataOfferListEntryRs.java index 0abc3749a..8d177cb2e 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/models/DataOfferListEntryRs.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/catalog/models/DataOfferListEntryRs.java @@ -29,11 +29,12 @@ @FieldDefaults(level = AccessLevel.PRIVATE) public class DataOfferListEntryRs { String assetId; - String assetPropertiesJson; + String assetJsonLd; OffsetDateTime createdAt; OffsetDateTime updatedAt; List contractOffers; String connectorEndpoint; ConnectorOnlineStatus connectorOnlineStatus; + String connectorParticipantId; OffsetDateTime connectorOfflineSinceOrLastUpdatedAt; } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorDetailQueryService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorDetailQueryService.java new file mode 100644 index 000000000..336256464 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorDetailQueryService.java @@ -0,0 +1,60 @@ +/* + * 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.brokerserver.dao.pages.connector; + +import de.sovity.edc.ext.brokerserver.dao.pages.connector.model.ConnectorDetailsRs; +import de.sovity.edc.ext.brokerserver.db.jooq.Tables; +import de.sovity.edc.ext.brokerserver.db.jooq.enums.MeasurementErrorStatus; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.Connector; +import org.jetbrains.annotations.NotNull; +import org.jooq.DSLContext; +import org.jooq.Field; +import org.jooq.impl.DSL; + +import java.math.BigDecimal; + +public class ConnectorDetailQueryService { + public ConnectorDetailsRs queryConnectorDetailPage(DSLContext dsl, String connectorEndpoint) { + var c = Tables.CONNECTOR; + + return dsl.select( + c.ENDPOINT.as("endpoint"), + c.PARTICIPANT_ID.as("participantId"), + c.CREATED_AT.as("createdAt"), + c.LAST_SUCCESSFUL_REFRESH_AT.as("lastSuccessfulRefreshAt"), + c.LAST_REFRESH_ATTEMPT_AT.as("lastRefreshAttemptAt"), + c.ONLINE_STATUS.as("onlineStatus"), + dataOfferCount(c.ENDPOINT).as("numDataOffers"), + getAvgSuccessfulCrawlTimeInMs(c).as("connectorCrawlingTimeAvg")) + .from(c) + .where(c.ENDPOINT.eq(connectorEndpoint)) + .groupBy(c.ENDPOINT) + .fetchOneInto(ConnectorDetailsRs.class); + } + + @NotNull + private Field getAvgSuccessfulCrawlTimeInMs(Connector c) { + var betm = Tables.BROKER_EXECUTION_TIME_MEASUREMENT; + return DSL.select(DSL.avg(betm.DURATION_IN_MS)) + .from(betm) + .where(betm.CONNECTOR_ENDPOINT.eq(c.ENDPOINT), betm.ERROR_STATUS.eq(MeasurementErrorStatus.OK)) + .asField(); + } + + private Field dataOfferCount(Field endpoint) { + var d = Tables.DATA_OFFER; + return DSL.select(DSL.count()).from(d).where(d.CONNECTOR_ENDPOINT.eq(endpoint)).asField(); + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorPageQueryService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorListQueryService.java similarity index 60% rename from extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorPageQueryService.java rename to extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorListQueryService.java index 15b91fb3b..18f860f71 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorPageQueryService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/ConnectorListQueryService.java @@ -15,12 +15,10 @@ package de.sovity.edc.ext.brokerserver.dao.pages.connector; import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageSortingType; -import de.sovity.edc.ext.brokerserver.dao.pages.connector.model.ConnectorDetailsRs; import de.sovity.edc.ext.brokerserver.dao.pages.connector.model.ConnectorListEntryRs; import de.sovity.edc.ext.brokerserver.dao.utils.SearchUtils; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; -import de.sovity.edc.ext.brokerserver.db.jooq.enums.MeasurementErrorStatus; import de.sovity.edc.ext.brokerserver.db.jooq.tables.Connector; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -30,36 +28,24 @@ import java.util.List; -public class ConnectorPageQueryService { +public class ConnectorListQueryService { public List queryConnectorPage(DSLContext dsl, String searchQuery, ConnectorPageSortingType sorting) { var c = Tables.CONNECTOR; - var filterBySearchQuery = SearchUtils.simpleSearch(searchQuery, List.of(c.ENDPOINT, c.CONNECTOR_ID)); + var filterBySearchQuery = SearchUtils.simpleSearch(searchQuery, List.of(c.ENDPOINT, c.PARTICIPANT_ID)); - return dsl.select(c.asterisk(), dataOfferCount(c.ENDPOINT).as("numDataOffers")) - .from(c) - .where(filterBySearchQuery) - .orderBy(sortConnectorPage(c, sorting)) - .fetchInto(ConnectorListEntryRs.class); - } - - public ConnectorDetailsRs queryConnectorDetailPage(DSLContext dsl, String connectorEndpoint) { - var c = Tables.CONNECTOR; - var betm = Tables.BROKER_EXECUTION_TIME_MEASUREMENT; - - var filterBySearchQuery = SearchUtils.simpleSearch(connectorEndpoint, List.of(c.ENDPOINT, c.CONNECTOR_ID)); - - var avgSuccessfulCrawlTimeInMs = dsl.select(DSL.avg(betm.DURATION_IN_MS)) - .from(betm) - .where(betm.CONNECTOR_ENDPOINT.eq(connectorEndpoint), betm.ERROR_STATUS.eq(MeasurementErrorStatus.OK)) - .asField(); - - return dsl.select(c.asterisk(), - dataOfferCount(c.ENDPOINT).as("numDataOffers"), - avgSuccessfulCrawlTimeInMs.as("connectorCrawlingTimeAvg")) - .from(c) - .where(filterBySearchQuery) - .groupBy(c.ENDPOINT) - .fetchOneInto(ConnectorDetailsRs.class); + return dsl.select( + c.ENDPOINT.as("endpoint"), + c.PARTICIPANT_ID.as("participantId"), + c.CREATED_AT.as("createdAt"), + c.LAST_SUCCESSFUL_REFRESH_AT.as("lastSuccessfulRefreshAt"), + c.LAST_REFRESH_ATTEMPT_AT.as("lastRefreshAttemptAt"), + c.ONLINE_STATUS.as("onlineStatus"), + dataOfferCount(c.ENDPOINT).as("numDataOffers") + ) + .from(c) + .where(filterBySearchQuery) + .orderBy(sortConnectorPage(c, sorting)) + .fetchInto(ConnectorListEntryRs.class); } @NotNull @@ -73,7 +59,7 @@ private List> sortConnectorPage(Connector c, ConnectorPageSortingT .asc(); if (sorting == null || sorting == ConnectorPageSortingType.ONLINE_STATUS) { - return List.of(onlineStatus, alphabetically); + return List.of(onlineStatus, alphabetically); } else if (sorting == ConnectorPageSortingType.TITLE) { return List.of(alphabetically, recentFirst); } else if (sorting == ConnectorPageSortingType.MOST_RECENT) { diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorDetailsRs.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorDetailsRs.java index 39d291c68..a593dcece 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorDetailsRs.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorDetailsRs.java @@ -27,7 +27,7 @@ @FieldDefaults(level = AccessLevel.PRIVATE) public class ConnectorDetailsRs { String endpoint; - String connectorId; + String participantId; OffsetDateTime createdAt; OffsetDateTime lastSuccessfulRefreshAt; OffsetDateTime lastRefreshAttemptAt; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorListEntryRs.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorListEntryRs.java index af82420a1..189f01c26 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorListEntryRs.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/connector/model/ConnectorListEntryRs.java @@ -27,7 +27,7 @@ @FieldDefaults(level = AccessLevel.PRIVATE) public class ConnectorListEntryRs { String endpoint; - String connectorId; + String participantId; OffsetDateTime createdAt; OffsetDateTime lastSuccessfulRefreshAt; OffsetDateTime lastRefreshAttemptAt; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/DataOfferDetailPageQueryService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/DataOfferDetailPageQueryService.java index fcfd96e6a..1ae809722 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/DataOfferDetailPageQueryService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/DataOfferDetailPageQueryService.java @@ -41,13 +41,14 @@ public DataOfferDetailRs queryDataOfferDetailsPage(DSLContext dsl, String assetI return dsl.select( d.ASSET_ID, - d.ASSET_PROPERTIES.cast(String.class).as("assetPropertiesJson"), + d.ASSET_JSON_LD.cast(String.class).as("assetJsonLd"), d.CREATED_AT, d.UPDATED_AT, - catalogQueryContractOfferFetcher.getContractOffers(fields).as("contractOffers"), + catalogQueryContractOfferFetcher.getContractOffers(fields.getDataOfferTable()).as("contractOffers"), fields.getOfflineSinceOrLastUpdatedAt().as("connectorOfflineSinceOrLastUpdatedAt"), c.ENDPOINT.as("connectorEndpoint"), c.ONLINE_STATUS.as("connectorOnlineStatus"), + c.PARTICIPANT_ID.as("connectorParticipantId"), fields.getViewCount().as("viewCount")) .from(d) .leftJoin(c).on(c.ENDPOINT.eq(d.CONNECTOR_ENDPOINT)) diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/ViewCountLogger.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/ViewCountLogger.java index 7fedc8f4c..377abeafa 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/ViewCountLogger.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/ViewCountLogger.java @@ -1,3 +1,17 @@ +/* + * 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.brokerserver.dao.pages.dataoffer; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/model/DataOfferDetailRs.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/model/DataOfferDetailRs.java index 4d2cb5241..54953edb8 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/model/DataOfferDetailRs.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/pages/dataoffer/model/DataOfferDetailRs.java @@ -28,12 +28,13 @@ @FieldDefaults(level = AccessLevel.PRIVATE) public class DataOfferDetailRs { String assetId; - String assetPropertiesJson; + String assetJsonLd; OffsetDateTime createdAt; OffsetDateTime updatedAt; List contractOffers; String connectorEndpoint; ConnectorOnlineStatus connectorOnlineStatus; + String connectorParticipantId; OffsetDateTime connectorOfflineSinceOrLastUpdatedAt; Integer viewCount; } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/utils/JsonDeserializationUtils.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/utils/JsonDeserializationUtils.java index 3803c91fe..1c3f4e2f9 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/utils/JsonDeserializationUtils.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/dao/utils/JsonDeserializationUtils.java @@ -33,7 +33,7 @@ public class JsonDeserializationUtils { }; @SneakyThrows - public static List> deserializeStringArray2(String json) { + public static List> read2dStringList(String json) { return OBJECT_MAPPER.readValue(json, TYPE_STRING_LIST_2); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCleaner.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCleaner.java index 512fdbd6e..b21cc2787 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCleaner.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCleaner.java @@ -22,7 +22,7 @@ public class ConnectorCleaner { public void removeDataForDeadConnectors(DSLContext dsl, Collection endpoints) { - var doco = Tables.DATA_OFFER_CONTRACT_OFFER; + var doco = Tables.CONTRACT_OFFER; var dof = Tables.DATA_OFFER; dsl.deleteFrom(doco).where(PostgresqlUtils.in(doco.CONNECTOR_ENDPOINT, endpoints)).execute(); dsl.deleteFrom(dof).where(PostgresqlUtils.in(dof.CONNECTOR_ENDPOINT, endpoints)).execute(); diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCreator.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCreator.java index ae83ced18..51b5f461e 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCreator.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/ConnectorCreator.java @@ -20,7 +20,6 @@ import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ConnectorRecord; import de.sovity.edc.ext.brokerserver.utils.CollectionUtils2; -import de.sovity.edc.ext.brokerserver.utils.UrlUtils; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -56,7 +55,7 @@ public void addConnectors(DSLContext dsl, Collection connectorEndpoints) private ConnectorRecord newConnectorRow(String endpoint) { var connector = new ConnectorRecord(); connector.setEndpoint(endpoint); - connector.setConnectorId(UrlUtils.getEverythingBeforeThePath(endpoint)); + connector.setParticipantId(""); connector.setCreatedAt(OffsetDateTime.now()); connector.setOnlineStatus(ConnectorOnlineStatus.OFFLINE); connector.setDataOffersExceeded(ConnectorDataOffersExceeded.OK); diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/OfflineConnectorKiller.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/OfflineConnectorKiller.java index c459269e7..8b46d9c81 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/OfflineConnectorKiller.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/OfflineConnectorKiller.java @@ -12,7 +12,6 @@ * */ - package de.sovity.edc.ext.brokerserver.services; import de.sovity.edc.ext.brokerserver.dao.ConnectorQueries; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiService.java index 0a08c44e0..1ba483a06 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiService.java @@ -37,8 +37,7 @@ public class CatalogApiService { private final PaginationMetadataUtils paginationMetadataUtils; private final CatalogQueryService catalogQueryService; - private final PolicyDtoBuilder policyDtoBuilder; - private final AssetPropertyParser assetPropertyParser; + private final DataOfferMappingUtils dataOfferMappingUtils; private final CatalogFilterService catalogFilterService; private final BrokerServerSettings brokerServerSettings; @@ -84,11 +83,17 @@ private List buildCatalogDataOffers(List } private CatalogDataOffer buildCatalogDataOffer(DataOfferListEntryRs dataOfferRs) { + var asset = dataOfferMappingUtils.buildUiAsset( + dataOfferRs.getAssetJsonLd(), + dataOfferRs.getConnectorEndpoint(), + dataOfferRs.getConnectorParticipantId() + ); + var dataOffer = new CatalogDataOffer(); dataOffer.setAssetId(dataOfferRs.getAssetId()); dataOffer.setCreatedAt(dataOfferRs.getCreatedAt()); dataOffer.setUpdatedAt(dataOfferRs.getUpdatedAt()); - dataOffer.setProperties(assetPropertyParser.parsePropertiesFromJsonString(dataOfferRs.getAssetPropertiesJson())); + dataOffer.setAsset(asset); dataOffer.setContractOffers(buildCatalogContractOffers(dataOfferRs)); dataOffer.setConnectorEndpoint(dataOfferRs.getConnectorEndpoint()); dataOffer.setConnectorOfflineSinceOrLastUpdatedAt(dataOfferRs.getConnectorOfflineSinceOrLastUpdatedAt()); @@ -105,7 +110,7 @@ private List buildCatalogContractOffers(DataOfferListEntry private CatalogContractOffer buildCatalogContractOffer(ContractOfferRs contractOfferDbRow) { var contractOffer = new CatalogContractOffer(); contractOffer.setContractOfferId(contractOfferDbRow.getContractOfferId()); - contractOffer.setContractPolicy(policyDtoBuilder.buildPolicyFromJson(contractOfferDbRow.getPolicyJson())); + contractOffer.setContractPolicy(dataOfferMappingUtils.buildUiPolicy(contractOfferDbRow.getPolicyJson())); contractOffer.setCreatedAt(contractOfferDbRow.getCreatedAt()); contractOffer.setUpdatedAt(contractOfferDbRow.getUpdatedAt()); return contractOffer; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiService.java index dfaa22851..46e017be9 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiService.java @@ -14,17 +14,6 @@ package de.sovity.edc.ext.brokerserver.services.api; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorDetailPageQuery; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorDetailPageResult; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorListEntry; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorOnlineStatus; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageQuery; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageResult; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageSortingItem; -import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageSortingType; -import de.sovity.edc.ext.brokerserver.dao.pages.connector.ConnectorPageQueryService; -import de.sovity.edc.ext.brokerserver.dao.pages.connector.model.ConnectorDetailsRs; -import de.sovity.edc.ext.brokerserver.dao.pages.connector.model.ConnectorListEntryRs; import de.sovity.edc.ext.brokerserver.services.logging.BrokerEventLogger; import de.sovity.edc.ext.brokerserver.utils.UrlUtils; import lombok.RequiredArgsConstructor; @@ -32,109 +21,23 @@ import java.util.List; import java.util.Objects; -import java.util.stream.Stream; import static de.sovity.edc.ext.brokerserver.services.queue.ConnectorRefreshPriority.ADDED_ON_API_CALL; import static java.util.stream.Collectors.toSet; @RequiredArgsConstructor public class ConnectorApiService { - private final ConnectorPageQueryService connectorPageQueryService; private final ConnectorService connectorService; - private final PaginationMetadataUtils paginationMetadataUtils; private final BrokerEventLogger brokerEventLogger; - public ConnectorPageResult connectorPage(DSLContext dsl, ConnectorPageQuery query) { - Objects.requireNonNull(query, "query must not be null"); - - var connectorDbRows = connectorPageQueryService.queryConnectorPage(dsl, query.getSearchQuery(), query.getSorting()); - - var result = new ConnectorPageResult(); - result.setAvailableSortings(buildAvailableSortings()); - result.setPaginationMetadata(paginationMetadataUtils.buildDummyPaginationMetadata(connectorDbRows.size())); - result.setConnectors(buildConnectorListEntries(connectorDbRows)); - return result; - } - - public ConnectorDetailPageResult connectorDetailPage(DSLContext dsl, ConnectorDetailPageQuery query) { - Objects.requireNonNull(query, "query must not be null"); - - var connectorDbRow = connectorPageQueryService.queryConnectorDetailPage(dsl, query.getConnectorEndpoint()); - var connector = buildConnectorDetailPageEntry(connectorDbRow); - - var result = new ConnectorDetailPageResult(); - result.setCreatedAt(connector.getCreatedAt()); - result.setEndpoint(connector.getEndpoint()); - result.setId(connector.getId()); - result.setLastRefreshAttemptAt(connector.getLastRefreshAttemptAt()); - result.setLastSuccessfulRefreshAt(connector.getLastSuccessfulRefreshAt()); - result.setNumContractOffers(connector.getNumContractOffers()); - result.setOnlineStatus(connector.getOnlineStatus()); - result.setConnectorCrawlingTimeAvg(connector.getConnectorCrawlingTimeAvg()); - return result; - } - - private List buildConnectorListEntries(List connectors) { - return connectors.stream().map(this::buildConnectorListEntry).toList(); - } - - private ConnectorListEntry buildConnectorListEntry(ConnectorListEntryRs connector) { - var dto = new ConnectorListEntry(); - dto.setId(connector.getConnectorId()); - dto.setEndpoint(connector.getEndpoint()); - dto.setCreatedAt(connector.getCreatedAt()); - dto.setLastRefreshAttemptAt(connector.getLastRefreshAttemptAt()); - dto.setLastSuccessfulRefreshAt(connector.getLastSuccessfulRefreshAt()); - dto.setOnlineStatus(getOnlineStatus(connector)); - dto.setNumContractOffers(connector.getNumDataOffers()); - return dto; - } - - private ConnectorDetailPageResult buildConnectorDetailPageEntry(ConnectorDetailsRs connector) { - var dto = new ConnectorDetailPageResult(); - dto.setId(connector.getConnectorId()); - dto.setEndpoint(connector.getEndpoint()); - dto.setCreatedAt(connector.getCreatedAt()); - dto.setLastRefreshAttemptAt(connector.getLastRefreshAttemptAt()); - dto.setLastSuccessfulRefreshAt(connector.getLastSuccessfulRefreshAt()); - dto.setOnlineStatus(getOnlineStatus(connector)); - dto.setNumContractOffers(connector.getNumDataOffers()); - dto.setConnectorCrawlingTimeAvg(connector.getConnectorCrawlingTimeAvg()); - return dto; - } - - private ConnectorOnlineStatus getOnlineStatus(ConnectorListEntryRs connector) { - return switch (connector.getOnlineStatus()) { - case ONLINE -> ConnectorOnlineStatus.ONLINE; - case OFFLINE -> ConnectorOnlineStatus.OFFLINE; - case DEAD -> ConnectorOnlineStatus.DEAD; - default -> throw new IllegalStateException("Unknown ConnectorOnlineStatus from DAO for API: " + connector.getOnlineStatus()); - }; - } - - private ConnectorOnlineStatus getOnlineStatus(ConnectorDetailsRs connector) { - return switch (connector.getOnlineStatus()) { - case ONLINE -> ConnectorOnlineStatus.ONLINE; - case OFFLINE -> ConnectorOnlineStatus.OFFLINE; - default -> throw new IllegalStateException("Unknown ConnectorOnlineStatus from DAO for API: " + connector.getOnlineStatus()); - }; - } - - private List buildAvailableSortings() { - return Stream.of( - ConnectorPageSortingType.MOST_RECENT, - ConnectorPageSortingType.TITLE - ).map(it -> new ConnectorPageSortingItem(it, it.getTitle())).toList(); - } - public void addConnectors(DSLContext dsl, List connectorEndpoints) { var existingEndpoints = connectorService.getConnectorEndpoints(dsl); var endpoints = connectorEndpoints.stream() - .filter(Objects::nonNull) - .map(String::trim) - .filter(UrlUtils::isValidUrl) - .filter(endpoint -> !existingEndpoints.contains(endpoint)) - .collect(toSet()); + .filter(Objects::nonNull) + .map(String::trim) + .filter(UrlUtils::isValidUrl) + .filter(endpoint -> !existingEndpoints.contains(endpoint)) + .collect(toSet()); connectorService.addConnectors(dsl, endpoints, ADDED_ON_API_CALL); } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorDetailApiService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorDetailApiService.java new file mode 100644 index 000000000..33ae006e8 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorDetailApiService.java @@ -0,0 +1,46 @@ +/* + * 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.brokerserver.services.api; + +import de.sovity.edc.ext.brokerserver.api.model.ConnectorDetailPageQuery; +import de.sovity.edc.ext.brokerserver.api.model.ConnectorDetailPageResult; +import de.sovity.edc.ext.brokerserver.dao.pages.connector.ConnectorDetailQueryService; +import lombok.RequiredArgsConstructor; +import org.jooq.DSLContext; + +import java.util.Objects; + +@RequiredArgsConstructor +public class ConnectorDetailApiService { + private final ConnectorDetailQueryService connectorDetailQueryService; + private final ConnectorOnlineStatusMapper connectorOnlineStatusMapper; + + public ConnectorDetailPageResult connectorDetailPage(DSLContext dsl, ConnectorDetailPageQuery query) { + Objects.requireNonNull(query, "query must not be null"); + + var connectorDbRow = connectorDetailQueryService.queryConnectorDetailPage(dsl, query.getConnectorEndpoint()); + var dto = new ConnectorDetailPageResult(); + dto.setParticipantId(connectorDbRow.getParticipantId()); + dto.setEndpoint(connectorDbRow.getEndpoint()); + dto.setCreatedAt(connectorDbRow.getCreatedAt()); + dto.setLastRefreshAttemptAt(connectorDbRow.getLastRefreshAttemptAt()); + dto.setLastSuccessfulRefreshAt(connectorDbRow.getLastSuccessfulRefreshAt()); + dto.setOnlineStatus(connectorOnlineStatusMapper.getOnlineStatus(connectorDbRow.getOnlineStatus())); + dto.setNumDataOffers(connectorDbRow.getNumDataOffers()); + dto.setConnectorCrawlingTimeAvg(connectorDbRow.getConnectorCrawlingTimeAvg()); + return dto; + } + +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorListApiService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorListApiService.java new file mode 100644 index 000000000..fe41c641a --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorListApiService.java @@ -0,0 +1,71 @@ +/* + * 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.brokerserver.services.api; + +import de.sovity.edc.ext.brokerserver.api.model.ConnectorListEntry; +import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageQuery; +import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageResult; +import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageSortingItem; +import de.sovity.edc.ext.brokerserver.api.model.ConnectorPageSortingType; +import de.sovity.edc.ext.brokerserver.dao.pages.connector.ConnectorListQueryService; +import de.sovity.edc.ext.brokerserver.dao.pages.connector.model.ConnectorListEntryRs; +import lombok.RequiredArgsConstructor; +import org.jooq.DSLContext; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +@RequiredArgsConstructor +public class ConnectorListApiService { + private final ConnectorListQueryService connectorListQueryService; + private final ConnectorOnlineStatusMapper connectorOnlineStatusMapper; + private final PaginationMetadataUtils paginationMetadataUtils; + + public ConnectorPageResult connectorListPage(DSLContext dsl, ConnectorPageQuery query) { + Objects.requireNonNull(query, "query must not be null"); + + var connectorDbRows = connectorListQueryService.queryConnectorPage(dsl, query.getSearchQuery(), query.getSorting()); + + var result = new ConnectorPageResult(); + result.setAvailableSortings(buildAvailableSortings()); + result.setPaginationMetadata(paginationMetadataUtils.buildDummyPaginationMetadata(connectorDbRows.size())); + result.setConnectors(buildConnectorListEntries(connectorDbRows)); + return result; + } + + private List buildConnectorListEntries(List connectors) { + return connectors.stream().map(this::buildConnectorListEntry).toList(); + } + + private ConnectorListEntry buildConnectorListEntry(ConnectorListEntryRs connector) { + var dto = new ConnectorListEntry(); + dto.setParticipantId(connector.getParticipantId()); + dto.setEndpoint(connector.getEndpoint()); + dto.setCreatedAt(connector.getCreatedAt()); + dto.setLastRefreshAttemptAt(connector.getLastRefreshAttemptAt()); + dto.setLastSuccessfulRefreshAt(connector.getLastSuccessfulRefreshAt()); + dto.setOnlineStatus(connectorOnlineStatusMapper.getOnlineStatus(connector.getOnlineStatus())); + dto.setNumDataOffers(connector.getNumDataOffers()); + return dto; + } + + private List buildAvailableSortings() { + return Stream.of( + ConnectorPageSortingType.MOST_RECENT, + ConnectorPageSortingType.TITLE + ).map(it -> new ConnectorPageSortingItem(it, it.getTitle())).toList(); + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorOnlineStatusMapper.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorOnlineStatusMapper.java new file mode 100644 index 000000000..15f204711 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorOnlineStatusMapper.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 - initial API and implementation + * + */ + +package de.sovity.edc.ext.brokerserver.services.api; + +import de.sovity.edc.ext.brokerserver.api.model.ConnectorOnlineStatus; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class ConnectorOnlineStatusMapper { + + public ConnectorOnlineStatus getOnlineStatus(de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus onlineStatus) { + return switch (onlineStatus) { + case ONLINE -> ConnectorOnlineStatus.ONLINE; + case OFFLINE -> ConnectorOnlineStatus.OFFLINE; + case DEAD -> ConnectorOnlineStatus.DEAD; + default -> throw new IllegalStateException("Unknown ConnectorOnlineStatus from DAO for API: " + onlineStatus); + }; + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorService.java index f22460146..b3996dcb8 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorService.java @@ -37,7 +37,7 @@ public void addConnectors(DSLContext dsl, Collection connectorEndpoints, public void deleteConnectors(DSLContext dsl, Collection endpoints) { removeConnectorRows(dsl, Tables.BROKER_EXECUTION_TIME_MEASUREMENT.CONNECTOR_ENDPOINT, endpoints); - removeConnectorRows(dsl, Tables.DATA_OFFER_CONTRACT_OFFER.CONNECTOR_ENDPOINT, endpoints); + removeConnectorRows(dsl, Tables.CONTRACT_OFFER.CONNECTOR_ENDPOINT, endpoints); removeConnectorRows(dsl, Tables.DATA_OFFER.CONNECTOR_ENDPOINT, endpoints); removeConnectorRows(dsl, Tables.DATA_OFFER_VIEW_COUNT.CONNECTOR_ENDPOINT, endpoints); removeConnectorRows(dsl, Tables.CONNECTOR.ENDPOINT, endpoints); diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiService.java index 137743c26..e6a927a7f 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiService.java @@ -32,13 +32,17 @@ public class DataOfferDetailApiService { private final DataOfferDetailPageQueryService dataOfferDetailPageQueryService; private final ViewCountLogger viewCountLogger; - private final PolicyDtoBuilder policyDtoBuilder; - private final AssetPropertyParser assetPropertyParser; + private final DataOfferMappingUtils dataOfferMappingUtils; public DataOfferDetailPageResult dataOfferDetailPage(DSLContext dsl, DataOfferDetailPageQuery query) { Objects.requireNonNull(query, "query must not be null"); var dataOffer = dataOfferDetailPageQueryService.queryDataOfferDetailsPage(dsl, query.getAssetId(), query.getConnectorEndpoint()); + var asset = dataOfferMappingUtils.buildUiAsset( + dataOffer.getAssetJsonLd(), + dataOffer.getConnectorEndpoint(), + dataOffer.getConnectorParticipantId() + ); viewCountLogger.increaseDataOfferViewCount(dsl, query.getAssetId(), query.getConnectorEndpoint()); var result = new DataOfferDetailPageResult(); @@ -46,7 +50,7 @@ public DataOfferDetailPageResult dataOfferDetailPage(DSLContext dsl, DataOfferDe result.setConnectorEndpoint(dataOffer.getConnectorEndpoint()); result.setConnectorOnlineStatus(mapConnectorOnlineStatus(dataOffer.getConnectorOnlineStatus())); result.setConnectorOfflineSinceOrLastUpdatedAt(dataOffer.getConnectorOfflineSinceOrLastUpdatedAt()); - result.setProperties(assetPropertyParser.parsePropertiesFromJsonString(dataOffer.getAssetPropertiesJson())); + result.setAsset(asset); result.setCreatedAt(dataOffer.getCreatedAt()); result.setUpdatedAt(dataOffer.getUpdatedAt()); result.setContractOffers(buildDataOfferDetailContractOffers(dataOffer.getContractOffers())); @@ -78,7 +82,7 @@ private DataOfferDetailContractOffer buildDataOfferDetailContractOffer(ContractO newOffer.setCreatedAt(offer.getCreatedAt()); newOffer.setUpdatedAt(offer.getUpdatedAt()); newOffer.setContractOfferId(offer.getContractOfferId()); - newOffer.setContractPolicy(policyDtoBuilder.buildPolicyFromJson(offer.getPolicyJson())); + newOffer.setContractPolicy(dataOfferMappingUtils.buildUiPolicy(offer.getPolicyJson())); return newOffer; } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferMappingUtils.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferMappingUtils.java new file mode 100644 index 000000000..e683bf298 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferMappingUtils.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 - initial API and implementation + * + */ + +package de.sovity.edc.ext.brokerserver.services.api; + +import de.sovity.edc.ext.wrapper.api.common.mappers.AssetMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; +import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; +import de.sovity.edc.utils.JsonUtils; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class DataOfferMappingUtils { + private final PolicyMapper policyMapper; + private final AssetMapper assetMapper; + + public UiAsset buildUiAsset(String assetJsonLd, String endpoint, String participantId) { + var asset = assetMapper.buildAsset(JsonUtils.parseJsonObj(assetJsonLd)); + return assetMapper.buildUiAsset(asset, endpoint, participantId); + } + + public UiPolicy buildUiPolicy(String policyJson) { + var policy = policyMapper.buildPolicy(policyJson); + return policyMapper.buildUiPolicy(policy); + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/PolicyDtoBuilder.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/PolicyDtoBuilder.java deleted file mode 100644 index 5768ee970..000000000 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/PolicyDtoBuilder.java +++ /dev/null @@ -1,43 +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.brokerserver.services.api; - -import de.sovity.edc.ext.wrapper.api.common.model.ExpressionDto; -import de.sovity.edc.ext.wrapper.api.common.model.PermissionDto; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDto; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -@RequiredArgsConstructor -public class PolicyDtoBuilder { - - @SneakyThrows - public PolicyDto buildPolicyFromJson(@NonNull String policyJson) { - var policyDto = new PolicyDto(); - policyDto.setLegacyPolicy(policyJson); - policyDto.setPermission(extractPermissions(policyJson)); - return policyDto; - } - - @NotNull - private PermissionDto extractPermissions(String policyJson) { - // TODO - return new PermissionDto(new ExpressionDto(ExpressionDto.Type.AND, null, List.of(), null, null)); - } -} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterAttributeDefinitionService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterAttributeDefinitionService.java index a54ec8f8e..088b2cc84 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterAttributeDefinitionService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterAttributeDefinitionService.java @@ -16,27 +16,31 @@ import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQueryFields; import de.sovity.edc.ext.brokerserver.dao.utils.PostgresqlUtils; -import org.jetbrains.annotations.NotNull; import org.jooq.Field; -import org.jooq.impl.DSL; + +import java.util.function.Function; public class CatalogFilterAttributeDefinitionService { - public CatalogFilterAttributeDefinition fromAssetProperty(String assetProperty, String label) { + public CatalogFilterAttributeDefinition forField( + Function> fieldExtractor, + String name, + String label + ) { return new CatalogFilterAttributeDefinition( - assetProperty, - label, - fields -> getValue(fields, assetProperty), - (fields, values) -> PostgresqlUtils.in(getValue(fields, assetProperty), values) + name, + label, + fieldExtractor::apply, + (fields, values) -> PostgresqlUtils.in(fieldExtractor.apply(fields), values) ); } public CatalogFilterAttributeDefinition buildDataSpaceFilter() { return new CatalogFilterAttributeDefinition( - "dataSpace", - "Data Space", - CatalogQueryFields::getDataSpace, - (fields, values) -> PostgresqlUtils.in(fields.getDataSpace(), values) + "dataSpace", + "Data Space", + CatalogQueryFields::getDataSpace, + (fields, values) -> PostgresqlUtils.in(fields.getDataSpace(), values) ); } @@ -48,9 +52,4 @@ public CatalogFilterAttributeDefinition buildConnectorEndpointFilter() { (fields, values) -> PostgresqlUtils.in(fields.getDataOfferTable().CONNECTOR_ENDPOINT, values) ); } - - @NotNull - private Field getValue(CatalogQueryFields fields, String assetProperty) { - return DSL.coalesce(fields.getAssetProperty(assetProperty), DSL.value("")); - } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterService.java index 73a6cce17..094c2cdfa 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterService.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogFilterService.java @@ -19,11 +19,10 @@ import de.sovity.edc.ext.brokerserver.api.model.CnfFilterItem; import de.sovity.edc.ext.brokerserver.api.model.CnfFilterValue; import de.sovity.edc.ext.brokerserver.api.model.CnfFilterValueAttribute; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.models.CatalogQueryFilter; import de.sovity.edc.ext.brokerserver.dao.pages.catalog.models.CatalogQuerySelectedFilterQuery; import de.sovity.edc.ext.brokerserver.dao.utils.JsonDeserializationUtils; -import de.sovity.edc.ext.brokerserver.dao.utils.PostgresqlUtils; +import de.sovity.edc.ext.brokerserver.db.jooq.Tables; import de.sovity.edc.ext.brokerserver.utils.CollectionUtils2; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.Validate; @@ -58,40 +57,50 @@ public class CatalogFilterService { */ private List getAvailableFilters() { return List.of( - catalogFilterAttributeDefinitionService.buildDataSpaceFilter(), - catalogFilterAttributeDefinitionService.fromAssetProperty( - AssetProperty.DATA_CATEGORY, - "Data Category" - ), - catalogFilterAttributeDefinitionService.fromAssetProperty( - AssetProperty.DATA_SUBCATEGORY, - "Data Subcategory" - ), - catalogFilterAttributeDefinitionService.fromAssetProperty( - AssetProperty.DATA_MODEL, - "Data Model" - ), - catalogFilterAttributeDefinitionService.fromAssetProperty( - AssetProperty.TRANSPORT_MODE, - "Transport Mode" - ), - catalogFilterAttributeDefinitionService.fromAssetProperty( - AssetProperty.GEO_REFERENCE_METHOD, - "Geo Reference Method" - ), - catalogFilterAttributeDefinitionService.buildConnectorEndpointFilter() + catalogFilterAttributeDefinitionService.buildDataSpaceFilter(), + catalogFilterAttributeDefinitionService.forField( + fields -> fields.getDataOfferTable().DATA_CATEGORY, + "dataCategory", + "Data Category" + ), + catalogFilterAttributeDefinitionService.forField( + fields -> fields.getDataOfferTable().DATA_SUBCATEGORY, + "dataSubcategory", + "Data Subcategory" + ), + catalogFilterAttributeDefinitionService.forField( + fields -> fields.getDataOfferTable().DATA_MODEL, + "dataModel", + "Data Model" + ), + catalogFilterAttributeDefinitionService.forField( + fields -> fields.getDataOfferTable().TRANSPORT_MODE, + "transportMode", + "Transport Mode" + ), + catalogFilterAttributeDefinitionService.forField( + fields -> fields.getDataOfferTable().GEO_REFERENCE_METHOD, + "geoReferenceMethod", + "Geo Reference Method" + ), + catalogFilterAttributeDefinitionService.forField( + fields -> fields.getDataOfferTable().CURATOR_ORGANIZATION_NAME, + "curatorOrganizationName", + "Organization Name" + ), + catalogFilterAttributeDefinitionService.buildConnectorEndpointFilter() ); } public List getCatalogQueryFilters(CnfFilterValue cnfFilterValue) { var values = getCnfFilterValuesMap(cnfFilterValue); return getAvailableFilters().stream() - .map(filter -> new CatalogQueryFilter( - filter.name(), - filter.valueGetter(), - getQueryFilter(filter, values.get(filter.name())) - )) - .toList(); + .map(filter -> new CatalogQueryFilter( + filter.name(), + filter.valueGetter(), + getQueryFilter(filter, values.get(filter.name())) + )) + .toList(); } private CatalogQuerySelectedFilterQuery getQueryFilter(CatalogFilterAttributeDefinition filter, List values) { @@ -102,34 +111,34 @@ private CatalogQuerySelectedFilterQuery getQueryFilter(CatalogFilterAttributeDef } public CnfFilter buildAvailableFilters(String filterValuesJson) { - var filterValues = JsonDeserializationUtils.deserializeStringArray2(filterValuesJson); + var filterValues = JsonDeserializationUtils.read2dStringList(filterValuesJson); var filterAttributes = zipAvailableFilters(getAvailableFilters(), filterValues) - .map(availableFilter -> new CnfFilterAttribute( - availableFilter.definition().name(), - availableFilter.definition().label(), - buildAvailableFilterValues(availableFilter) - )) - .toList(); + .map(availableFilter -> new CnfFilterAttribute( + availableFilter.definition().name(), + availableFilter.definition().label(), + buildAvailableFilterValues(availableFilter) + )) + .toList(); return new CnfFilter(filterAttributes); } private List buildAvailableFilterValues(AvailableFilter availableFilter) { return availableFilter.availableValues().stream() - .sorted(caseInsensitiveEmptyStringLast) - .map(value -> new CnfFilterItem(value, value)) - .toList(); + .sorted(caseInsensitiveEmptyStringLast) + .map(value -> new CnfFilterItem(value, value)) + .toList(); } private Stream zipAvailableFilters(List availableFilters, List> filterValues) { Validate.isTrue( - availableFilters.size() == filterValues.size(), - "Number of available filters and filter values must match: %d != %d", - availableFilters.size(), - filterValues.size() + availableFilters.size() == filterValues.size(), + "Number of available filters and filter values must match: %d != %d", + availableFilters.size(), + filterValues.size() ); return Stream.iterate(0, i -> i + 1) - .limit(availableFilters.size()) - .map(i -> new AvailableFilter(availableFilters.get(i), filterValues.get(i))); + .limit(availableFilters.size()) + .map(i -> new AvailableFilter(availableFilters.get(i), filterValues.get(i))); } private record AvailableFilter(CatalogFilterAttributeDefinition definition, List availableValues) { @@ -140,7 +149,7 @@ private Map> getCnfFilterValuesMap(CnfFilterValue cnfFilter return Map.of(); } return cnfFilterValue.getSelectedAttributeValues().stream() - .filter(it -> it.getId() != null && CollectionUtils2.isNotEmpty(it.getSelectedIds())) - .collect(toMap(CnfFilterValueAttribute::getId, CnfFilterValueAttribute::getSelectedIds)); + .filter(it -> it.getId() != null && CollectionUtils2.isNotEmpty(it.getSelectedIds())) + .collect(toMap(CnfFilterValueAttribute::getId, CnfFilterValueAttribute::getSelectedIds)); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogSearchService.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogSearchService.java new file mode 100644 index 000000000..0c4c89bfa --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/api/filtering/CatalogSearchService.java @@ -0,0 +1,39 @@ +/* + * 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.brokerserver.services.api.filtering; + +import de.sovity.edc.ext.brokerserver.dao.pages.catalog.CatalogQueryFields; +import de.sovity.edc.ext.brokerserver.dao.utils.SearchUtils; +import lombok.RequiredArgsConstructor; +import org.jooq.Condition; + +import java.util.List; + +@RequiredArgsConstructor +public class CatalogSearchService { + + public Condition filterBySearch(CatalogQueryFields fields, String searchQuery) { + return SearchUtils.simpleSearch(searchQuery, List.of( + fields.getDataOfferTable().ASSET_ID, + fields.getDataOfferTable().ASSET_TITLE, + fields.getDataOfferTable().DATA_CATEGORY, + fields.getDataOfferTable().DATA_SUBCATEGORY, + fields.getDataOfferTable().DESCRIPTION, + fields.getDataOfferTable().CURATOR_ORGANIZATION_NAME, + fields.getDataOfferTable().KEYWORDS_COMMA_JOINED, + fields.getConnectorTable().ENDPOINT + )); + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/config/DataSpaceConnector.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/config/DataSpaceConnector.java index 5e8d57cf3..589f08aa0 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/config/DataSpaceConnector.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/config/DataSpaceConnector.java @@ -12,7 +12,6 @@ * */ - package de.sovity.edc.ext.brokerserver.services.config; /** diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/logging/ConnectorChangeTracker.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/logging/ConnectorChangeTracker.java index b34688f7c..1513c1f5e 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/logging/ConnectorChangeTracker.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/logging/ConnectorChangeTracker.java @@ -34,8 +34,11 @@ public class ConnectorChangeTracker { @Setter private int numOffersUpdated = 0; + @Setter + private String participantIdChanged = null; + public boolean isEmpty() { - return numOffersAdded == 0 && numOffersDeleted == 0 && numOffersUpdated == 0; + return numOffersAdded == 0 && numOffersDeleted == 0 && numOffersUpdated == 0 && participantIdChanged == null; } @Override @@ -58,6 +61,9 @@ public String toString() { } msg += " Data Offers changed: %s.".formatted(String.join(", ", offersMsgs)); } + if (participantIdChanged != null) { + msg += " Participant ID changed to %s.".formatted(participantIdChanged); + } return msg; } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdateSuccessWriter.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdateSuccessWriter.java index dc2c3b6a9..8b4279b64 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdateSuccessWriter.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdateSuccessWriter.java @@ -20,12 +20,12 @@ import de.sovity.edc.ext.brokerserver.services.logging.ConnectorChangeTracker; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferLimitsEnforcer; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferWriter; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedCatalog; import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; import java.time.OffsetDateTime; -import java.util.Collection; +import java.util.Objects; @RequiredArgsConstructor public class ConnectorUpdateSuccessWriter { @@ -36,12 +36,10 @@ public class ConnectorUpdateSuccessWriter { public void handleConnectorOnline( DSLContext dsl, ConnectorRecord connector, - Collection dataOffers + FetchedCatalog catalog ) { - var now = OffsetDateTime.now(); - // Limit data offers and log limitation if necessary - var limitedDataOffers = dataOfferLimitsEnforcer.enforceLimits(dataOffers); + var limitedDataOffers = dataOfferLimitsEnforcer.enforceLimits(catalog.getDataOffers()); dataOfferLimitsEnforcer.logEnforcedLimitsIfChanged(dsl, connector, limitedDataOffers); // Log Status Change and set status to online if necessary @@ -52,16 +50,27 @@ public void handleConnectorOnline( // Track changes for final log message var changes = new ConnectorChangeTracker(); - connector.setLastSuccessfulRefreshAt(now); - connector.setLastRefreshAttemptAt(now); - connector.update(); + updateConnector(connector, catalog, changes); - // Log Event if changes are present + // Update data offers + dataOfferWriter.updateDataOffers(dsl, connector.getEndpoint(), limitedDataOffers.abbreviatedDataOffers(), changes); + + // Log event if changes are present if (!changes.isEmpty()) { brokerEventLogger.logConnectorUpdated(dsl, connector.getEndpoint(), changes); } + } - // Update data offers - dataOfferWriter.updateDataOffers(dsl, connector.getEndpoint(), limitedDataOffers.abbreviatedDataOffers(), changes); + private static void updateConnector(ConnectorRecord connector, FetchedCatalog catalog, ConnectorChangeTracker changes) { + var now = OffsetDateTime.now(); + var participantId = catalog.getParticipantId(); + + connector.setLastSuccessfulRefreshAt(now); + connector.setLastRefreshAttemptAt(now); + if (!Objects.equals(connector.getParticipantId(), participantId)) { + connector.setParticipantId(participantId); + changes.setParticipantIdChanged(participantId); + } + connector.update(); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdater.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdater.java index 591c45f34..5a759fab0 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdater.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdater.java @@ -19,7 +19,7 @@ import de.sovity.edc.ext.brokerserver.db.jooq.enums.MeasurementErrorStatus; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ConnectorRecord; import de.sovity.edc.ext.brokerserver.services.logging.BrokerExecutionTimeLogger; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferFetcher; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.CatalogFetcher; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.time.StopWatch; import org.eclipse.edc.spi.monitor.Monitor; @@ -31,7 +31,7 @@ */ @RequiredArgsConstructor public class ConnectorUpdater { - private final DataOfferFetcher dataOfferFetcher; + private final CatalogFetcher catalogFetcher; private final ConnectorUpdateSuccessWriter connectorUpdateSuccessWriter; private final ConnectorUpdateFailureWriter connectorUpdateFailureWriter; private final ConnectorQueries connectorQueries; @@ -51,12 +51,12 @@ public void updateConnector(String connectorEndpoint) { try { monitor.info("Updating connector: " + connectorEndpoint); - var dataOffers = dataOfferFetcher.fetch(connectorEndpoint); + var catalog = catalogFetcher.fetchCatalog(connectorEndpoint); // Update connector in a single transaction dslContextFactory.transaction(dsl -> { ConnectorRecord connectorRecord = connectorQueries.findByEndpoint(dsl, connectorEndpoint); - connectorUpdateSuccessWriter.handleConnectorOnline(dsl, connectorRecord, dataOffers); + connectorUpdateSuccessWriter.handleConnectorOnline(dsl, connectorRecord, catalog); }); } catch (Exception e) { failed = true; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferFetcher.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/CatalogFetcher.java similarity index 63% rename from extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferFetcher.java rename to extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/CatalogFetcher.java index d87705716..2b7da851c 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferFetcher.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/CatalogFetcher.java @@ -14,17 +14,17 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedCatalog; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; +import de.sovity.edc.utils.catalog.DspCatalogService; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; -import java.util.Collection; - @RequiredArgsConstructor -public class DataOfferFetcher { - private final ContractOfferFetcher contractOfferFetcher; - private final DataOfferBuilder dataOfferBuilder; +public class CatalogFetcher { + private final DspCatalogService dspCatalogService; + private final FetchedCatalogBuilder fetchedCatalogBuilder; /** * Fetches {@link ContractOffer}s and de-duplicates them into {@link FetchedDataOffer}s. @@ -33,11 +33,8 @@ public class DataOfferFetcher { * @return updated connector db row */ @SneakyThrows - public Collection fetch(String connectorEndpoint) { - // Contract Offers contain assets multiple times, with different policies - var contractOffers = contractOfferFetcher.fetch(connectorEndpoint); - - // Data Offers represent unique assets - return dataOfferBuilder.deduplicateContractOffers(contractOffers); + public FetchedCatalog fetchCatalog(String connectorEndpoint) { + var dspCatalog = dspCatalogService.fetchDataOffers(connectorEndpoint); + return fetchedCatalogBuilder.buildFetchedCatalog(dspCatalog); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferFetcher.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferFetcher.java deleted file mode 100644 index fcdd370e1..000000000 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferFetcher.java +++ /dev/null @@ -1,46 +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.brokerserver.services.refreshing.offers; - -import de.sovity.edc.ext.brokerserver.services.refreshing.exceptions.ConnectorUnreachableException; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; -import org.eclipse.edc.connector.spi.catalog.CatalogService; -import org.eclipse.edc.spi.query.QuerySpec; - -import java.util.List; - -@RequiredArgsConstructor -public class ContractOfferFetcher { - private final CatalogService catalogService; - - /** - * Fetches Connector contract offers - * - * @param connectorEndpoint connector endpoint - * @return updated connector db row - */ - @SneakyThrows - public List fetch(String connectorEndpoint) { - try { - return catalogService.getByProviderUrl(connectorEndpoint, QuerySpec.max()).get().getContractOffers(); - } catch (InterruptedException e) { - throw e; - } catch (Exception e) { - throw new ConnectorUnreachableException("Failed to fetch connector contract offers", e); - } - } -} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferRecordUpdater.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferRecordUpdater.java index 8e9854f79..3b3980294 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferRecordUpdater.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/ContractOfferRecordUpdater.java @@ -15,9 +15,9 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers; import de.sovity.edc.ext.brokerserver.dao.utils.JsonbUtils; -import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferContractOfferRecord; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ContractOfferRecord; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOfferContractOffer; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedContractOffer; import lombok.RequiredArgsConstructor; import org.jooq.JSONB; @@ -25,7 +25,7 @@ import java.util.Objects; /** - * Creates or updates {@link DataOfferContractOfferRecord} DB Rows. + * Creates or updates {@link ContractOfferRecord} DB Rows. *

* (Or at least prepares them for batch inserts / updates) */ @@ -33,14 +33,14 @@ public class ContractOfferRecordUpdater { /** - * Create new {@link DataOfferContractOfferRecord} from {@link FetchedDataOfferContractOffer}. + * Create new {@link ContractOfferRecord} from {@link FetchedContractOffer}. * * @param dataOffer parent data offer db row * @param fetchedContractOffer fetched contract offer * @return new db row */ - public DataOfferContractOfferRecord newContractOffer(DataOfferRecord dataOffer, FetchedDataOfferContractOffer fetchedContractOffer) { - var contractOffer = new DataOfferContractOfferRecord(); + public ContractOfferRecord newContractOffer(DataOfferRecord dataOffer, FetchedContractOffer fetchedContractOffer) { + var contractOffer = new ContractOfferRecord(); contractOffer.setConnectorEndpoint(dataOffer.getConnectorEndpoint()); contractOffer.setContractOfferId(fetchedContractOffer.getContractOfferId()); contractOffer.setAssetId(dataOffer.getAssetId()); @@ -50,13 +50,13 @@ public DataOfferContractOfferRecord newContractOffer(DataOfferRecord dataOffer, } /** - * Update existing {@link DataOfferContractOfferRecord} with changes from {@link FetchedDataOfferContractOffer}. + * Update existing {@link ContractOfferRecord} with changes from {@link FetchedContractOffer}. * * @param contractOffer existing row * @param fetchedContractOffer changes to be integrated * @return if anything was changed */ - public boolean updateContractOffer(DataOfferContractOfferRecord contractOffer, FetchedDataOfferContractOffer fetchedContractOffer) { + public boolean updateContractOffer(ContractOfferRecord contractOffer, FetchedContractOffer fetchedContractOffer) { var existingPolicy = JsonbUtils.getDataOrNull(contractOffer.getPolicy()); var fetchedPolicy = fetchedContractOffer.getPolicyJson(); var changed = false; diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferBuilder.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferBuilder.java deleted file mode 100644 index 25c4f5e83..000000000 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferBuilder.java +++ /dev/null @@ -1,135 +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.brokerserver.services.refreshing.offers; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOfferContractOffer; -import de.sovity.edc.ext.brokerserver.utils.StreamUtils2; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import org.apache.commons.lang3.tuple.Pair; -import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; -import org.eclipse.edc.spi.types.domain.asset.Asset; -import org.jetbrains.annotations.NotNull; - -import java.net.URI; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static java.util.stream.Collectors.groupingBy; - -@RequiredArgsConstructor -public class DataOfferBuilder { - private final ObjectMapper objectMapper; - - /** - * De-duplicates {@link ContractOffer}s into {@link FetchedDataOffer}s. - *

- * Also de-duplicates {@link ContractOffer}s into {@link FetchedDataOfferContractOffer}s. - * - * @param contractOffers {@link ContractOffer}s - * @return {@link FetchedDataOffer}s - */ - public Collection deduplicateContractOffers(Collection contractOffers) { - return groupByAssetId(contractOffers) - .stream() - .map(offers -> buildFetchedDataOffer(offers.get(0).getAsset(), offers)) - .toList(); - } - - @NotNull - private FetchedDataOffer buildFetchedDataOffer(Asset asset, List offers) { - var dataOffer = new FetchedDataOffer(); - dataOffer.setAssetId(asset.getId()); - dataOffer.setAssetName(getAssetName(asset)); - dataOffer.setAssetPropertiesJson(getAssetPropertiesJson(asset)); - dataOffer.setContractOffers(buildFetchedDataOfferContractOffers(offers)); - return dataOffer; - } - - @NotNull - private List buildFetchedDataOfferContractOffers(List offers) { - return offers.stream() - .map(this::buildFetchedDataOfferContractOffer) - .filter(StreamUtils2.distinctByKey(FetchedDataOfferContractOffer::getContractOfferId)) - .toList(); - } - - @NotNull - private FetchedDataOfferContractOffer buildFetchedDataOfferContractOffer(ContractOffer offer) { - var contractOffer = new FetchedDataOfferContractOffer(); - contractOffer.setContractOfferId(offer.getId()); - contractOffer.setPolicyJson(getPolicyJson(offer)); - return contractOffer; - } - - private Collection> groupByAssetId(Collection contractOffers) { - return contractOffers.stream().collect(groupingBy(offer -> offer.getAsset().getId())).values(); - } - - private String getAssetName(Asset asset) { - String assetName = asset.getName(); - if (assetName == null) { - assetName = asset.getId(); - } - return assetName; - } - - @NotNull - @SneakyThrows - private String getAssetPropertiesJson(Asset asset) { - var properties = mapNonNullValues(asset.getProperties(), this::getAssetPropertyValue); - return objectMapper.writeValueAsString(properties); - } - - @SneakyThrows - private String getAssetPropertyValue(Object value) { - if (value == null) { - return null; - } - - if (value instanceof URI uri) { - // I don't know why the Eclipse EDC is casting Strings to URIs, but it does - // We need to prevent this from hitting the writeValueAsString or additional - // quotes are added - return uri.toString(); - } - - if (value instanceof String stringValue) { - return stringValue; - } - - // Using JSON Properties in the MS8 EDC causes the broker to fail - // this is why we map them to their JSON to "show them", but not fail due to them - return objectMapper.writeValueAsString(value); - } - - @NotNull - @SneakyThrows - private String getPolicyJson(ContractOffer offer) { - return objectMapper.writeValueAsString(offer.getPolicy()); - } - - private Map mapNonNullValues(Map map, Function valueMapper) { - return map.entrySet().stream() - .map(entry -> Pair.of(entry.getKey(), valueMapper.apply(entry.getValue()))) - .filter(entry -> entry.getValue() != null) - .collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); - } -} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferPatchBuilder.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferPatchBuilder.java index 959885022..8b7dcc6be 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferPatchBuilder.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferPatchBuilder.java @@ -14,13 +14,13 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers; -import de.sovity.edc.ext.brokerserver.dao.DataOfferContractOfferQueries; +import de.sovity.edc.ext.brokerserver.dao.ContractOfferQueries; import de.sovity.edc.ext.brokerserver.dao.DataOfferQueries; -import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferContractOfferRecord; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ContractOfferRecord; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.DataOfferPatch; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedContractOffer; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOfferContractOffer; import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; @@ -32,7 +32,7 @@ @RequiredArgsConstructor public class DataOfferPatchBuilder { - private final DataOfferContractOfferQueries dataOfferContractOfferQueries; + private final ContractOfferQueries contractOfferQueries; private final DataOfferQueries dataOfferQueries; private final DataOfferRecordUpdater dataOfferRecordUpdater; private final ContractOfferRecordUpdater contractOfferRecordUpdater; @@ -52,9 +52,9 @@ public DataOfferPatch buildDataOfferPatch( ) { var patch = new DataOfferPatch(); var dataOffers = dataOfferQueries.findByConnectorEndpoint(dsl, connectorEndpoint); - var contractOffersByAssetId = dataOfferContractOfferQueries.findByConnectorEndpoint(dsl, connectorEndpoint) + var contractOffersByAssetId = contractOfferQueries.findByConnectorEndpoint(dsl, connectorEndpoint) .stream() - .collect(groupingBy(DataOfferContractOfferRecord::getAssetId)); + .collect(groupingBy(ContractOfferRecord::getAssetId)); var diff = DiffUtils.compareLists( dataOffers, @@ -97,16 +97,16 @@ public DataOfferPatch buildDataOfferPatch( private boolean patchContractOffers( DataOfferPatch patch, DataOfferRecord dataOffer, - Collection contractOffers, - Collection fetchedContractOffers + Collection contractOffers, + Collection fetchedContractOffers ) { var hasUpdates = new AtomicBoolean(false); var diff = DiffUtils.compareLists( contractOffers, - DataOfferContractOfferRecord::getContractOfferId, + ContractOfferRecord::getContractOfferId, fetchedContractOffers, - FetchedDataOfferContractOffer::getContractOfferId + FetchedContractOffer::getContractOfferId ); diff.added().forEach(fetched -> { diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferRecordUpdater.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferRecordUpdater.java index 2676ffb46..97b1e2102 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferRecordUpdater.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferRecordUpdater.java @@ -17,11 +17,17 @@ import de.sovity.edc.ext.brokerserver.dao.utils.JsonbUtils; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; +import de.sovity.edc.ext.brokerserver.utils.JsonUtils2; import lombok.RequiredArgsConstructor; import org.jooq.JSONB; import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; /** * Creates or updates {@link DataOfferRecord} DB Rows. @@ -55,20 +61,78 @@ public DataOfferRecord newDataOffer(String connectorEndpoint, FetchedDataOffer f * @param changed whether the data offer should be marked as updated simply because the contract offers changed * @return whether any fields were updated */ - public boolean updateDataOffer(DataOfferRecord dataOffer, FetchedDataOffer fetchedDataOffer, boolean changed) { - if (!Objects.equals(fetchedDataOffer.getAssetName(), dataOffer.getAssetName())) { - Objects.requireNonNull(fetchedDataOffer.getAssetName(), - "Fetched data offer's asset name should have been set as id if name isn't present"); - dataOffer.setAssetName(fetchedDataOffer.getAssetName()); - changed = true; - } + public boolean updateDataOffer( + DataOfferRecord dataOffer, + FetchedDataOffer fetchedDataOffer, + boolean changed + ) { + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getAssetTitle, + DataOfferRecord::getAssetTitle, + dataOffer::setAssetTitle + ); - String existingAssetProps = JsonbUtils.getDataOrNull(dataOffer.getAssetProperties()); - var fetchedAssetProps = fetchedDataOffer.getAssetPropertiesJson(); - if (!Objects.equals(fetchedAssetProps, existingAssetProps)) { - dataOffer.setAssetProperties(JSONB.jsonb(fetchedAssetProps)); - changed = true; - } + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getDescription, + DataOfferRecord::getDescription, + dataOffer::setDescription + ); + + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getCuratorOrganizationName, + DataOfferRecord::getCuratorOrganizationName, + dataOffer::setCuratorOrganizationName + ); + + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getDataCategory, + DataOfferRecord::getDataCategory, + dataOffer::setDataCategory + ); + + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getDataSubcategory, + DataOfferRecord::getDataSubcategory, + dataOffer::setDataSubcategory + ); + + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getDataModel, + DataOfferRecord::getDataModel, + dataOffer::setDataModel + ); + + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getTransportMode, + DataOfferRecord::getTransportMode, + dataOffer::setTransportMode + ); + + changed |= updateField( + dataOffer, + fetchedDataOffer, + FetchedDataOffer::getGeoReferenceMethod, + DataOfferRecord::getGeoReferenceMethod, + dataOffer::setGeoReferenceMethod + ); + + changed |= updateKeywords(dataOffer, fetchedDataOffer); + + changed |= updateAssetJsonLd(dataOffer, fetchedDataOffer); if (changed) { dataOffer.setUpdatedAt(OffsetDateTime.now()); @@ -76,4 +140,67 @@ public boolean updateDataOffer(DataOfferRecord dataOffer, FetchedDataOffer fetch return changed; } + + private boolean updateField( + DataOfferRecord dataOffer, + FetchedDataOffer fetchedDataOffer, + Function fetchedField, + Function existingField, + Consumer setter + ) { + var fetched = fetchedField.apply(fetchedDataOffer); + if (fetched == null) { + fetched = ""; + } + + var existing = existingField.apply(dataOffer); + if (existing == null) { + existing = ""; + } + + + if (Objects.equals(fetched, existing)) { + return false; + } + + setter.accept(fetched); + return true; + } + + private boolean updateKeywords( + DataOfferRecord dataOffer, + FetchedDataOffer fetchedDataOffer + ) { + List fetched = fetchedDataOffer.getKeywords(); + if (fetched == null) { + fetched = List.of(); + } + + String[] existing = dataOffer.getKeywords(); + if (existing == null) { + existing = new String[0]; + } + + if (Objects.equals(new HashSet<>(fetched), new HashSet<>(Arrays.asList(existing)))) { + return false; + } + + dataOffer.setKeywords(fetched.toArray(new String[0])); + dataOffer.setKeywordsCommaJoined(String.join(",", fetched)); + return true; + } + + private boolean updateAssetJsonLd( + DataOfferRecord dataOffer, + FetchedDataOffer fetchedDataOffer + ) { + String existing = JsonbUtils.getDataOrNull(dataOffer.getAssetJsonLd()); + var fetched = fetchedDataOffer.getAssetJsonLd(); + if (JsonUtils2.isEqualJson(fetched, existing)) { + return false; + } + + dataOffer.setAssetJsonLd(JSONB.jsonb(fetched)); + return true; + } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/FetchedCatalogBuilder.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/FetchedCatalogBuilder.java new file mode 100644 index 000000000..64d850281 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/FetchedCatalogBuilder.java @@ -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 - initial API and implementation + * + */ + +package de.sovity.edc.ext.brokerserver.services.refreshing.offers; + +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedCatalog; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedContractOffer; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; +import de.sovity.edc.ext.wrapper.api.common.mappers.AssetMapper; +import de.sovity.edc.utils.JsonUtils; +import de.sovity.edc.utils.catalog.model.DspCatalog; +import de.sovity.edc.utils.catalog.model.DspContractOffer; +import de.sovity.edc.utils.catalog.model.DspDataOffer; +import jakarta.json.JsonObject; +import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@RequiredArgsConstructor +public class FetchedCatalogBuilder { + private final AssetMapper assetMapper; + + public FetchedCatalog buildFetchedCatalog(DspCatalog catalog) { + var participantId = catalog.getParticipantId(); + + var fetchedDataOffers = catalog.getDataOffers().stream() + .map(dspDataOffer -> buildFetchedDataOffer(dspDataOffer, participantId)) + .toList(); + + var fetchedCatalog = new FetchedCatalog(); + fetchedCatalog.setParticipantId(participantId); + fetchedCatalog.setDataOffers(fetchedDataOffers); + + return fetchedCatalog; + } + + @NotNull + private FetchedDataOffer buildFetchedDataOffer(DspDataOffer dspDataOffer, String participantId) { + var assetJsonLd = assetMapper.buildAssetJsonLdFromDatasetProperties(dspDataOffer.getAssetPropertiesJsonLd()); + + var fetchedDataOffer = new FetchedDataOffer(); + setAssetMetadata(fetchedDataOffer, assetJsonLd, participantId); + fetchedDataOffer.setContractOffers(buildFetchedContractOffers(dspDataOffer.getContractOffers())); + return fetchedDataOffer; + } + + @NotNull + private List buildFetchedContractOffers(List offers) { + return offers.stream() + .map(this::buildFetchedContractOffer) + .toList(); + } + + @NotNull + private FetchedContractOffer buildFetchedContractOffer(DspContractOffer offer) { + var contractOffer = new FetchedContractOffer(); + contractOffer.setContractOfferId(offer.getContractOfferId()); + contractOffer.setPolicyJson(JsonUtils.toJson(offer.getPolicyJsonLd())); + return contractOffer; + } + + /** + * This method was extract so tests could re-use the logic of assetJsonLd -> fetchedDataOffer -> dataOfferRecord + * + * @param fetchedDataOffer fetchedDataOffer + * @param assetJsonLd assetJsonLd + */ + public void setAssetMetadata(FetchedDataOffer fetchedDataOffer, JsonObject assetJsonLd, String participantId) { + var uiAsset = assetMapper.buildUiAsset(assetJsonLd, "http://if-you-see-this-this-is-a-bug", participantId); + fetchedDataOffer.setAssetId(uiAsset.getAssetId()); + fetchedDataOffer.setAssetJsonLd(JsonUtils.toJson(assetJsonLd)); + + // Most of these fields are extracted so our DB does not need to + // semantically interpret JSON-LD when sorting, searching and filtering + fetchedDataOffer.setAssetTitle(uiAsset.getTitle()); + fetchedDataOffer.setDescription(uiAsset.getDescription()); + fetchedDataOffer.setCuratorOrganizationName(uiAsset.getCreatorOrganizationName()); + + fetchedDataOffer.setDataCategory(uiAsset.getDataCategory()); + fetchedDataOffer.setDataSubcategory(uiAsset.getDataSubcategory()); + fetchedDataOffer.setDataModel(uiAsset.getDataModel()); + fetchedDataOffer.setGeoReferenceMethod(uiAsset.getGeoReferenceMethod()); + fetchedDataOffer.setTransportMode(uiAsset.getTransportMode()); + fetchedDataOffer.setKeywords(uiAsset.getKeywords()); + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/DataOfferPatch.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/DataOfferPatch.java index e9bf5ad69..a7a2b49bd 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/DataOfferPatch.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/DataOfferPatch.java @@ -14,7 +14,7 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers.model; -import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferContractOfferRecord; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ContractOfferRecord; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; import lombok.AccessLevel; import lombok.Getter; @@ -35,9 +35,9 @@ public class DataOfferPatch { List dataOffersToUpdate = new ArrayList<>(); List dataOffersToDelete = new ArrayList<>(); - List contractOffersToInsert = new ArrayList<>(); - List contractOffersToUpdate = new ArrayList<>(); - List contractOffersToDelete = new ArrayList<>(); + List contractOffersToInsert = new ArrayList<>(); + List contractOffersToUpdate = new ArrayList<>(); + List contractOffersToDelete = new ArrayList<>(); public void insertDataOffer(DataOfferRecord offer) { dataOffersToInsert.add(offer); @@ -51,15 +51,15 @@ public void deleteDataOffer(DataOfferRecord offer) { dataOffersToDelete.add(offer); } - public void insertContractOffer(DataOfferContractOfferRecord offer) { + public void insertContractOffer(ContractOfferRecord offer) { contractOffersToInsert.add(offer); } - public void updateContractOffer(DataOfferContractOfferRecord offer) { + public void updateContractOffer(ContractOfferRecord offer) { contractOffersToUpdate.add(offer); } - public void deleteContractOffer(DataOfferContractOfferRecord offer) { + public void deleteContractOffer(ContractOfferRecord offer) { contractOffersToDelete.add(offer); } } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedCatalog.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedCatalog.java new file mode 100644 index 000000000..550dd0657 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedCatalog.java @@ -0,0 +1,33 @@ +/* + * 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.brokerserver.services.refreshing.offers.model; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.FieldDefaults; + +import java.util.List; + +/** + * Contains catalog response as required for writing into DB. + */ +@Getter +@Setter +@FieldDefaults(level = AccessLevel.PRIVATE) +public class FetchedCatalog { + String participantId; + List dataOffers; +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOfferContractOffer.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedContractOffer.java similarity index 93% rename from extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOfferContractOffer.java rename to extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedContractOffer.java index 76c099dfa..b2d566f70 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOfferContractOffer.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedContractOffer.java @@ -22,7 +22,7 @@ @Getter @Setter @FieldDefaults(level = AccessLevel.PRIVATE) -public class FetchedDataOfferContractOffer { +public class FetchedContractOffer { String contractOfferId; String policyJson; } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOffer.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOffer.java index 78cf0c9a1..d93306613 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOffer.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/model/FetchedDataOffer.java @@ -21,12 +21,23 @@ import java.util.List; +/** + * Contains data offer response as required for writing into DB. + */ @Getter @Setter @FieldDefaults(level = AccessLevel.PRIVATE) public class FetchedDataOffer { String assetId; - String assetName; - String assetPropertiesJson; - List contractOffers; + String assetTitle; + String description; + String curatorOrganizationName; + String dataCategory; + String dataSubcategory; + String dataModel; + String transportMode; + String geoReferenceMethod; + List keywords; + String assetJsonLd; + List contractOffers; } diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/JsonUtils2.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/JsonUtils2.java new file mode 100644 index 000000000..fbe1af366 --- /dev/null +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/JsonUtils2.java @@ -0,0 +1,32 @@ +/* + * 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.brokerserver.utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils2 { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + @SneakyThrows + public static boolean isEqualJson(String json, String otherJson) { + return + (json == null && otherJson == null) || + (json != null && otherJson != null && OBJECT_MAPPER.readTree(json).equals(OBJECT_MAPPER.readTree(otherJson))); + } +} diff --git a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/UrlUtils.java b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/UrlUtils.java index f728d05ef..ae720063b 100644 --- a/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/UrlUtils.java +++ b/extensions/broker-server/src/main/java/de/sovity/edc/ext/brokerserver/utils/UrlUtils.java @@ -18,35 +18,12 @@ import lombok.NoArgsConstructor; import java.net.MalformedURLException; -import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class UrlUtils { - - /** - * Returns everything before the URLs path. - *

- * Example: http://www.example.com/path/to/my/file.html -> http://www.example.com - * Example 2: http://www.example.com:9000/path/to/my/file.html -> http://www.example.com:9000 - * - * @param url url - * @return protocol, host, port - */ - public static String getEverythingBeforeThePath(String url) { - var uri = URI.create(url); - var scheme = uri.getScheme(); // "http" - var authority = uri.getAuthority(); // "www.example.com" - int port = uri.getPort(); // -1 (no port specified) - var everythingBeforePath = scheme + "://" + authority; - if (port != -1) { - everythingBeforePath += ":" + port; - } - return everythingBeforePath; - } - public static boolean isValidUrl(String url) { try { new URL(url).toURI(); diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/AssertionUtils.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/AssertionUtils.java index 781aa4504..c810d36eb 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/AssertionUtils.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/AssertionUtils.java @@ -14,6 +14,7 @@ package de.sovity.edc.ext.brokerserver; +import de.sovity.edc.ext.brokerserver.client.gen.JSON; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.SneakyThrows; @@ -26,4 +27,8 @@ public class AssertionUtils { public static void assertEqualJson(String expected, String actual) { JSONAssert.assertEquals(expected, actual, JSONCompareMode.STRICT); } + + public static void assertEqualUsingJson(Object expected, Object actual) { + assertEqualJson(JSON.serialize(expected), JSON.serialize(actual)); + } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestAsset.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestAsset.java new file mode 100644 index 000000000..c954d6a86 --- /dev/null +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestAsset.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 API and implementation + * + */ + +package de.sovity.edc.ext.brokerserver; + +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; +import de.sovity.edc.utils.jsonld.vocab.Prop; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TestAsset { + public static JsonObject getAssetJsonLd(String assetId) { + return getAssetJsonLd(assetId, Map.of()); + } + + public static JsonObject getAssetJsonLd(String assetId, Map properties) { + return Json.createObjectBuilder() + .add(Prop.ID, assetId) + .add(Prop.Edc.PROPERTIES, Json.createObjectBuilder() + .add(Prop.Edc.ASSET_ID, assetId) + .addAll(Json.createObjectBuilder(properties))) + .build(); + } + + /** + * Sets assetJsonLd and other extracted fields. + *

+ * This method keeps our tests consistent if we change the extracted fields. + * + * @param dataOfferRecord data offer record to be updated + * @param assetJsonLd asset json ld + * @param participantId required because the organization name will default to the participant id if unset + */ + public static void setDataOfferAssetMetadata(DataOfferRecord dataOfferRecord, JsonObject assetJsonLd, String participantId) { + // We trickily use the real code to update all the extracted values from the asset JSON-LD + var fetchedCatalogBuilder = BrokerServerExtensionContext.instance.fetchedCatalogBuilder(); + var dataOfferRecordUpdater = BrokerServerExtensionContext.instance.dataOfferRecordUpdater(); + + var fetchedDataOffer = new FetchedDataOffer(); + fetchedCatalogBuilder.setAssetMetadata(fetchedDataOffer, assetJsonLd, participantId); + + dataOfferRecord.setAssetId(fetchedDataOffer.getAssetId()); + dataOfferRecordUpdater.updateDataOffer(dataOfferRecord, fetchedDataOffer, false); + } +} diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestPolicy.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestPolicy.java new file mode 100644 index 000000000..3087968d9 --- /dev/null +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestPolicy.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 API and implementation + * + */ + +package de.sovity.edc.ext.brokerserver; + +import de.sovity.edc.ext.brokerserver.client.gen.JSON; +import de.sovity.edc.ext.wrapper.api.common.model.OperatorDto; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyCreateRequest; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyLiteral; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyLiteralType; +import de.sovity.edc.utils.JsonUtils; +import org.jooq.JSONB; + +import java.time.OffsetDateTime; +import java.util.List; + +public class TestPolicy { + private static OffsetDateTime today = OffsetDateTime.now(); + + public static UiPolicyConstraint createAfterYesterdayConstraint() { + return UiPolicyConstraint.builder() + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.GT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(today.minusDays(1).toString()) + .build()) + .build(); + } + + public static de.sovity.edc.client.gen.model.UiPolicyCreateRequest createAfterYesterdayPolicyEdcGen() { + return jsonCast(createAfterYesterdayPolicy(), de.sovity.edc.client.gen.model.UiPolicyCreateRequest.class); + } + + private static R jsonCast(T obj, Class clazz) { + return JSON.deserialize(JSON.serialize(obj), clazz); + } + + public static UiPolicyCreateRequest createAfterYesterdayPolicy() { + return UiPolicyCreateRequest.builder() + .constraints(List.of(createAfterYesterdayConstraint())) + .build(); + } + + public static JSONB createAfterYesterdayPolicyJson() { + var createRequest = TestPolicy.createAfterYesterdayPolicy(); + return getPolicyJsonLd(createRequest); + } + + /** + * This method only works in integration tests, because it depends on the broker server extension context. + */ + public static JSONB getPolicyJsonLd(UiPolicyCreateRequest createRequest) { + var policyMapper = BrokerServerExtensionContext.instance.policyMapper(); + var jsonLd = policyMapper.buildPolicyJsonLd(policyMapper.buildPolicy(createRequest)); + return JSONB.jsonb(JsonUtils.toJson(jsonLd)); + } +} diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestUtils.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestUtils.java index c9e14605c..2d797c6c6 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestUtils.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/TestUtils.java @@ -19,7 +19,6 @@ import de.sovity.edc.ext.brokerserver.db.PostgresFlywayExtension; import de.sovity.edc.ext.brokerserver.db.TestDatabase; import org.assertj.core.api.ThrowableAssert; -import org.eclipse.edc.protocol.ids.api.configuration.IdsApiConfigurationExtension; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -31,19 +30,19 @@ import static org.eclipse.edc.junit.testfixtures.TestUtils.getFreePort; public class TestUtils { - - private static final int DATA_PORT = getFreePort(); + private static final int MANAGEMENT_PORT = getFreePort(); private static final int PROTOCOL_PORT = getFreePort(); - private static final String DATA_PATH = "/api/v1/data"; - private static final String PROTOCOL_PATH = "/api/v1/ids"; + private static final String MANAGEMENT_PATH = "/api/management"; + private static final String PROTOCOL_PATH = "/api/dsp"; public static final String MANAGEMENT_API_KEY = "123456"; - public static final String MANAGEMENT_ENDPOINT = "http://localhost:" + DATA_PORT + DATA_PATH; - + public static final String MANAGEMENT_ENDPOINT = "http://localhost:" + MANAGEMENT_PORT + MANAGEMENT_PATH; public static final String ADMIN_API_KEY = "123456"; public static final String PROTOCOL_HOST = "http://localhost:" + PROTOCOL_PORT; - public static final String PROTOCOL_ENDPOINT = PROTOCOL_HOST + PROTOCOL_PATH + "/data"; + public static final String PROTOCOL_ENDPOINT = PROTOCOL_HOST + PROTOCOL_PATH; + public static final String PARTICIPANT_ID = "my-edc-participant-id"; + public static final String CURATOR_NAME = "My Org"; @NotNull public static Map createConfiguration( @@ -51,16 +50,26 @@ public static Map createConfiguration( Map additionalConfigProperties ) { Map config = new HashMap<>(); + config.put("web.http.port", String.valueOf(getFreePort())); config.put("web.http.path", "/api"); - config.put("web.http.management.port", String.valueOf(DATA_PORT)); - config.put("web.http.management.path", DATA_PATH); + config.put("web.http.management.port", String.valueOf(MANAGEMENT_PORT)); + config.put("web.http.management.path", MANAGEMENT_PATH); config.put("web.http.protocol.port", String.valueOf(PROTOCOL_PORT)); config.put("web.http.protocol.path", PROTOCOL_PATH); config.put("edc.api.auth.key", MANAGEMENT_API_KEY); - config.put("edc.ids.endpoint", PROTOCOL_ENDPOINT); - config.put(IdsApiConfigurationExtension.IDS_WEBHOOK_ADDRESS, PROTOCOL_HOST); + config.put("edc.dsp.callback.address", PROTOCOL_ENDPOINT); config.put("edc.oauth.provider.audience", "idsc:IDS_CONNECTORS_ALL"); + + config.put("edc.participant.id", PARTICIPANT_ID); + config.put("my.edc.name.kebab.case", PARTICIPANT_ID); + config.put("my.edc.title", "My Connector"); + config.put("my.edc.description", "My Connector Description"); + config.put("my.edc.curator.url", "https://connector.my-org"); + config.put("my.edc.curator.name", CURATOR_NAME); + config.put("my.edc.maintainer.url", "https://maintainer-org"); + config.put("my.edc.maintainer.name", "Maintainer Org"); + config.put(PostgresFlywayExtension.JDBC_URL, testDatabase.getJdbcUrl()); config.put(PostgresFlywayExtension.JDBC_USER, testDatabase.getJdbcUser()); config.put(PostgresFlywayExtension.JDBC_PASSWORD, testDatabase.getJdbcPassword()); diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/db/TestDatabase.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/db/TestDatabase.java index bf200c29d..e593df41c 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/db/TestDatabase.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/db/TestDatabase.java @@ -19,8 +19,8 @@ import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; -import java.util.function.Consumer; import javax.sql.DataSource; +import java.util.function.Consumer; public interface TestDatabase extends BeforeAllCallback, AfterAllCallback { String getJdbcUrl(); diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiTest.java index b5c1b9b86..4b0bf063c 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/CatalogApiTest.java @@ -25,13 +25,15 @@ import de.sovity.edc.ext.brokerserver.client.gen.model.CnfFilterValueAttribute; import de.sovity.edc.ext.brokerserver.client.gen.model.DataOfferDetailPageQuery; import de.sovity.edc.ext.brokerserver.client.gen.model.DataOfferDetailPageResult; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.db.TestDatabase; import de.sovity.edc.ext.brokerserver.db.TestDatabaseFactory; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorContractOffersExceeded; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorDataOffersExceeded; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.AssetJsonLdUtils; +import de.sovity.edc.utils.jsonld.vocab.Prop; +import jakarta.json.JsonObject; import lombok.SneakyThrows; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; @@ -48,6 +50,8 @@ import java.util.List; import java.util.Map; +import static de.sovity.edc.ext.brokerserver.TestAsset.getAssetJsonLd; +import static de.sovity.edc.ext.brokerserver.TestAsset.setDataOfferAssetMetadata; import static de.sovity.edc.ext.brokerserver.TestUtils.brokerServerClient; import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; import static java.util.stream.IntStream.range; @@ -65,7 +69,7 @@ void setUp(EdcExtension extension) { extension.setConfiguration(createConfiguration(TEST_DATABASE, Map.of( BrokerServerExtension.CATALOG_PAGE_PAGE_SIZE, "10", BrokerServerExtension.DEFAULT_CONNECTOR_DATASPACE, "MDS", - BrokerServerExtension.KNOWN_DATASPACE_CONNECTORS, "Example1=http://my-connector2/ids/data,Example2=http://my-connector3/ids/data" + BrokerServerExtension.KNOWN_DATASPACE_CONNECTORS, "Example1=https://my-connector2/api/dsp,Example2=https://my-connector3/api/dsp" ))); } @@ -75,16 +79,15 @@ void testDataSpace_two_dataspaces_filter_for_one() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); // Dataspace: MDS - createConnector(dsl, today, "http://my-connector2/ids/data"); // Dataspace: Example1 - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset" - ), "http://my-connector/ids/data"); // Dataspace: MDS - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset" - ), "http://my-connector2/ids/data"); // Dataspace: Example1 + var assetJsonLd = getAssetJsonLd("my-asset", Map.of(Prop.Dcterms.TITLE, "My Asset")); + + // Dataspace: MDS + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd); + + // Dataspace: Example1 + createConnector(dsl, today, "https://my-connector2/api/dsp"); + createDataOffer(dsl, today, "https://my-connector2/api/dsp", assetJsonLd); var query = new CatalogPageQuery(); query.setFilter(new CnfFilterValue(List.of( @@ -95,7 +98,7 @@ void testDataSpace_two_dataspaces_filter_for_one() { assertThat(result.getDataOffers()).hasSize(1); var dataOfferResult = result.getDataOffers().get(0); - assertThat(dataOfferResult.getConnectorEndpoint()).isEqualTo("http://my-connector2/ids/data"); + assertThat(dataOfferResult.getConnectorEndpoint()).isEqualTo("https://my-connector2/api/dsp"); }); } @@ -105,24 +108,21 @@ void testConnectorEndpointFilter_two_connectors_filter_for_one() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createConnector(dsl, today, "http://my-connector2/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset" - ), "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset" - ), "http://my-connector2/ids/data"); + var assetJsonLd = getAssetJsonLd("my-asset", Map.of(Prop.Dcterms.TITLE, "My Asset")); + + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd); + + createConnector(dsl, today, "https://my-connector2/api/dsp"); + createDataOffer(dsl, today, "https://my-connector2/api/dsp", assetJsonLd); var query = new CatalogPageQuery(); query.setFilter(new CnfFilterValue(List.of( - new CnfFilterValueAttribute("connectorEndpoint", List.of("http://my-connector/ids/data")) + new CnfFilterValueAttribute("connectorEndpoint", List.of("https://my-connector/api/dsp")) ))); var result = brokerServerClient().brokerServerApi().catalogPage(query); - assertThat(result.getDataOffers()).extracting(CatalogDataOffer::getAssetId).containsExactly("urn:artifact:my-asset"); + assertThat(result.getDataOffers()).extracting(CatalogDataOffer::getConnectorEndpoint).containsExactly("https://my-connector/api/dsp"); }); } @@ -132,29 +132,18 @@ void test_available_filter_values_to_filter_by() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); // Dataspace: MDS - createConnector(dsl, today, "http://my-connector2/ids/data"); // Dataspace: Example1 - createConnector(dsl, today, "http://my-connector3/ids/data"); // Dataspace: Example2 - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset", - AssetProperty.LANGUAGE, "de" - ), "http://my-connector/ids/data"); // Dataspace: MDS - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset", - AssetProperty.LANGUAGE, "en" - ), "http://my-connector2/ids/data"); // Dataspace: Example1 - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset2", - AssetProperty.ASSET_NAME, "my-asset", - AssetProperty.LANGUAGE, "fr" - ), "http://my-connector2/ids/data"); // Dataspace: Example1 - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset3", - AssetProperty.ASSET_NAME, "my-asset", - AssetProperty.LANGUAGE, "fr" - ), "http://my-connector3/ids/data"); // Dataspace: Example2 + createConnector(dsl, today, "https://my-connector/api/dsp"); // Dataspace: MDS + createConnector(dsl, today, "https://my-connector2/api/dsp"); // Dataspace: Example1 + createConnector(dsl, today, "https://my-connector3/api/dsp"); // Dataspace: Example2 + + var assetJsonLd1 = getAssetJsonLd("my-asset-1"); + var assetJsonLd2 = getAssetJsonLd("my-asset-2"); + var assetJsonLd3 = getAssetJsonLd("my-asset-3"); + + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd1); // Dataspace: MDS + createDataOffer(dsl, today, "https://my-connector2/api/dsp", assetJsonLd1); // Dataspace: Example1 + createDataOffer(dsl, today, "https://my-connector2/api/dsp", assetJsonLd2); // Dataspace: Example1 + createDataOffer(dsl, today, "https://my-connector3/api/dsp", assetJsonLd3); // Dataspace: Example2 // get all available filter values var result = brokerServerClient().brokerServerApi().catalogPage(new CatalogPageQuery()); @@ -175,25 +164,23 @@ void testDataOfferDetails() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset" - ), "http://my-connector/ids/data"); + var assetJsonLd = getAssetJsonLd("my-asset-1", Map.of( + Prop.Dcterms.TITLE, "My Asset" + )); + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd); var result = brokerServerClient().brokerServerApi().catalogPage(new CatalogPageQuery()); assertThat(result.getDataOffers()).hasSize(1); var dataOfferResult = result.getDataOffers().get(0); - assertThat(dataOfferResult.getConnectorEndpoint()).isEqualTo("http://my-connector/ids/data"); + assertThat(dataOfferResult.getConnectorEndpoint()).isEqualTo("https://my-connector/api/dsp"); assertThat(dataOfferResult.getConnectorOfflineSinceOrLastUpdatedAt()).isEqualTo(today); assertThat(dataOfferResult.getConnectorOnlineStatus()).isEqualTo(CatalogDataOffer.ConnectorOnlineStatusEnum.ONLINE); - assertThat(dataOfferResult.getAssetId()).isEqualTo("urn:artifact:my-asset"); - assertThat(dataOfferResult.getProperties()).isEqualTo(Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset", - AssetProperty.ASSET_NAME, "my-asset" - )); + assertThat(dataOfferResult.getAssetId()).isEqualTo("my-asset-1"); + assertThat(dataOfferResult.getAsset().getAssetId()).isEqualTo("my-asset-1"); + assertThat(dataOfferResult.getAsset().getTitle()).isEqualTo("My Asset"); assertThat(dataOfferResult.getCreatedAt()).isEqualTo(today.minusDays(5)); }); } @@ -206,7 +193,7 @@ void testEmptyConnector() { TEST_DATABASE.testTransaction(dsl -> { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); + createConnector(dsl, today, "https://my-connector/api/dsp"); // act var result = brokerServerClient().brokerServerApi().catalogPage(new CatalogPageQuery()); @@ -226,31 +213,39 @@ void testAvailableFilters_noFilter() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category-1", - AssetProperty.TRANSPORT_MODE, "MY-TRANSPORT-MODE-1", - AssetProperty.DATA_SUBCATEGORY, "MY-SUBCATEGORY-2" - ), "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-2", - AssetProperty.DATA_CATEGORY, "my-category-1", - AssetProperty.TRANSPORT_MODE, "my-transport-mode-2", - AssetProperty.DATA_SUBCATEGORY, "MY-SUBCATEGORY-2" - ), "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-3", - AssetProperty.DATA_CATEGORY, "my-category-1", - AssetProperty.TRANSPORT_MODE, "MY-TRANSPORT-MODE-1", - AssetProperty.DATA_SUBCATEGORY, "my-subcategory-1" - ), "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-4", - AssetProperty.DATA_CATEGORY, "my-category-1", - AssetProperty.TRANSPORT_MODE, "" - ), "http://my-connector/ids/data"); + var assetJsonLd1 = getAssetJsonLd("my-asset-1", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category-1", + Prop.Mds.TRANSPORT_MODE, "MY-TRANSPORT-MODE-1", + Prop.Mds.DATA_SUBCATEGORY, "MY-SUBCATEGORY-2", + Prop.Mds.DATA_MODEL, "my-data-model", + Prop.Mds.GEO_REFERENCE_METHOD, "my-geo-ref", + Prop.Dcterms.CREATOR, Map.of( + Prop.Foaf.NAME, "my-org" + ) + )); + + var assetJsonLd2 = getAssetJsonLd("my-asset-2", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category-1", + Prop.Mds.TRANSPORT_MODE, "my-transport-mode-2", + Prop.Mds.DATA_SUBCATEGORY, "MY-SUBCATEGORY-2" + )); + + var assetJsonLd3 = getAssetJsonLd("my-asset-3", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category-1", + Prop.Mds.TRANSPORT_MODE, "MY-TRANSPORT-MODE-1", + Prop.Mds.DATA_SUBCATEGORY, "my-subcategory-1" + )); + + var assetJsonLd4 = getAssetJsonLd("my-asset-4", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category-1", + Prop.Mds.TRANSPORT_MODE, "" + )); + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd1); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd2); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd3); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd4); var result = brokerServerClient().brokerServerApi().catalogPage(new CatalogPageQuery()); @@ -258,11 +253,12 @@ void testAvailableFilters_noFilter() { .extracting(CnfFilterAttribute::getId) .containsExactly( "dataSpace", - AssetProperty.DATA_CATEGORY, - AssetProperty.DATA_SUBCATEGORY, - AssetProperty.DATA_MODEL, - AssetProperty.TRANSPORT_MODE, - AssetProperty.GEO_REFERENCE_METHOD, + "dataCategory", + "dataSubcategory", + "dataModel", + "transportMode", + "geoReferenceMethod", + "curatorOrganizationName", "connectorEndpoint" ); @@ -275,28 +271,41 @@ void testAvailableFilters_noFilter() { "Data Model", "Transport Mode", "Geo Reference Method", + "Organization Name", "Connector" ); - var dataCategory = getAvailableFilter(result, AssetProperty.DATA_CATEGORY); - assertThat(dataCategory.getTitle()).isEqualTo("Data Category"); + var dataSpace = getAvailableFilter(result, "dataSpace"); + assertThat(dataSpace.getValues()).extracting(CnfFilterItem::getId).containsExactly("MDS"); + assertThat(dataSpace.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("MDS"); + + var dataCategory = getAvailableFilter(result, "dataCategory"); assertThat(dataCategory.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-category-1"); assertThat(dataCategory.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-category-1"); - var transportMode = getAvailableFilter(result, AssetProperty.TRANSPORT_MODE); - assertThat(transportMode.getTitle()).isEqualTo("Transport Mode"); + var dataSubcategory = getAvailableFilter(result, "dataSubcategory"); + assertThat(dataSubcategory.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-subcategory-1", "MY-SUBCATEGORY-2", ""); + assertThat(dataSubcategory.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-subcategory-1", "MY-SUBCATEGORY-2", ""); + + var dataModel = getAvailableFilter(result, "dataModel"); + assertThat(dataModel.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-data-model", ""); + assertThat(dataModel.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-data-model", ""); + + var transportMode = getAvailableFilter(result, "transportMode"); assertThat(transportMode.getValues()).extracting(CnfFilterItem::getId).containsExactly("MY-TRANSPORT-MODE-1", "my-transport-mode-2", ""); assertThat(transportMode.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("MY-TRANSPORT-MODE-1", "my-transport-mode-2", ""); - var dataSubcategory = getAvailableFilter(result, AssetProperty.DATA_SUBCATEGORY); - assertThat(dataSubcategory.getTitle()).isEqualTo("Data Subcategory"); - assertThat(dataSubcategory.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-subcategory-1", "MY-SUBCATEGORY-2", ""); - assertThat(dataSubcategory.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-subcategory-1", "MY-SUBCATEGORY-2", ""); + var geoReferenceMethod = getAvailableFilter(result, "geoReferenceMethod"); + assertThat(geoReferenceMethod.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-geo-ref", ""); + assertThat(geoReferenceMethod.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-geo-ref", ""); + + var curatorOrganizationName = getAvailableFilter(result, "curatorOrganizationName"); + assertThat(curatorOrganizationName.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-org", "my-participant-id"); // second value comes from tests mocking + assertThat(curatorOrganizationName.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-org", "my-participant-id"); var connectorEndpoint = getAvailableFilter(result, "connectorEndpoint"); - assertThat(connectorEndpoint.getTitle()).isEqualTo("Connector"); - assertThat(connectorEndpoint.getValues()).extracting(CnfFilterItem::getId).containsExactly("http://my-connector/ids/data"); - assertThat(connectorEndpoint.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("http://my-connector/ids/data"); + assertThat(connectorEndpoint.getValues()).extracting(CnfFilterItem::getId).containsExactly("https://my-connector/api/dsp"); + assertThat(connectorEndpoint.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("https://my-connector/api/dsp"); }); } @@ -312,11 +321,10 @@ void testSearchCaseInsensitive() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "123", - AssetProperty.ASSET_NAME, "Hello" - ), "http://my-connector/ids/data"); + var assetJsonLd = getAssetJsonLd("123", Map.of(Prop.Dcterms.TITLE, "Hello")); + + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd); // act @@ -341,34 +349,31 @@ void testAvailableFilters_withFilter() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.DATA_SUBCATEGORY, "my-subcategory" - ), "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-2", - AssetProperty.DATA_SUBCATEGORY, "my-other-subcategory" - ), "http://my-connector/ids/data"); + var assetJsonLd1 = getAssetJsonLd("my-asset-1", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category", + Prop.Mds.DATA_SUBCATEGORY, "my-subcategory" + )); + + var assetJsonLd2 = getAssetJsonLd("my-asset-2", Map.of( + Prop.Mds.DATA_SUBCATEGORY, "my-other-subcategory" + )); + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd1); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd2); var query = new CatalogPageQuery(); query.setFilter(new CnfFilterValue(List.of( - new CnfFilterValueAttribute(AssetProperty.DATA_CATEGORY, List.of("")) + new CnfFilterValueAttribute("dataCategory", List.of("")) ))); var result = brokerServerClient().brokerServerApi().catalogPage(query); - var dataCategory = getAvailableFilter(result, AssetProperty.DATA_CATEGORY); - assertThat(dataCategory.getId()).isEqualTo(AssetProperty.DATA_CATEGORY); - assertThat(dataCategory.getTitle()).isEqualTo("Data Category"); + var dataCategory = getAvailableFilter(result, "dataCategory"); assertThat(dataCategory.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-category", ""); assertThat(dataCategory.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-category", ""); - var dataSubcategory = getAvailableFilter(result, AssetProperty.DATA_SUBCATEGORY); - assertThat(dataSubcategory.getId()).isEqualTo(AssetProperty.DATA_SUBCATEGORY); - assertThat(dataSubcategory.getTitle()).isEqualTo("Data Subcategory"); + var dataSubcategory = getAvailableFilter(result, "dataSubcategory"); assertThat(dataSubcategory.getValues()).extracting(CnfFilterItem::getId).containsExactly("my-other-subcategory"); assertThat(dataSubcategory.getValues()).extracting(CnfFilterItem::getTitle).containsExactly("my-other-subcategory"); }); @@ -380,14 +385,9 @@ void testPagination_firstPage() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - range(0, 15).forEach(i -> createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-%d".formatted(i) - ), "http://my-connector/ids/data")); - range(0, 15).forEach(i -> createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:some-other-asset-%d".formatted(i) - ), "http://my-connector/ids/data")); - + createConnector(dsl, today, "https://my-connector/api/dsp"); + range(0, 15).forEach(i -> createDataOffer(dsl, today, "https://my-connector/api/dsp", getAssetJsonLd("my-asset-%d".formatted(i)))); + range(0, 15).forEach(i -> createDataOffer(dsl, today, "https://my-connector/api/dsp", getAssetJsonLd("some-other-asset-%d".formatted(i)))); var query = new CatalogPageQuery(); query.setSearchQuery("my-asset"); @@ -395,7 +395,7 @@ void testPagination_firstPage() { var result = brokerServerClient().brokerServerApi().catalogPage(query); assertThat(result.getDataOffers()).extracting(CatalogDataOffer::getAssetId) - .isEqualTo(range(0, 10).mapToObj("urn:artifact:my-asset-%d"::formatted).toList()); + .isEqualTo(range(0, 10).mapToObj("my-asset-%d"::formatted).toList()); var actual = result.getPaginationMetadata(); assertThat(actual.getPageOneBased()).isEqualTo(1); @@ -411,13 +411,9 @@ void testPagination_secondPage() { // arrange var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - range(0, 15).forEach(i -> createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-%d".formatted(i) - ), "http://my-connector/ids/data")); - range(0, 15).forEach(i -> createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:some-other-asset-%d".formatted(i) - ), "http://my-connector/ids/data")); + createConnector(dsl, today, "https://my-connector/api/dsp"); + range(0, 15).forEach(i -> createDataOffer(dsl, today, "https://my-connector/api/dsp", getAssetJsonLd("my-asset-%d".formatted(i)))); + range(0, 15).forEach(i -> createDataOffer(dsl, today, "https://my-connector/api/dsp", getAssetJsonLd("some-other-asset-%d".formatted(i)))); var query = new CatalogPageQuery(); @@ -428,7 +424,7 @@ void testPagination_secondPage() { var result = brokerServerClient().brokerServerApi().catalogPage(query); assertThat(result.getDataOffers()).extracting(CatalogDataOffer::getAssetId) - .isEqualTo(range(10, 15).mapToObj("urn:artifact:my-asset-%d"::formatted).toList()); + .isEqualTo(range(10, 15).mapToObj("my-asset-%d"::formatted).toList()); var actual = result.getPaginationMetadata(); assertThat(actual.getPageOneBased()).isEqualTo(2); @@ -444,14 +440,14 @@ void testSortingByPopularity() { // arrange var today = OffsetDateTime.now().withNano(0); - var endpoint = "http://my-connector/ids/data"; + var endpoint = "https://my-connector/api/dsp"; createConnector(dsl, today, endpoint); - createDataOffer(dsl, today, Map.of(AssetProperty.ASSET_ID, "urn:artifact:asset-1"), endpoint); - createDataOffer(dsl, today, Map.of(AssetProperty.ASSET_ID, "urn:artifact:asset-2"), endpoint); - createDataOffer(dsl, today, Map.of(AssetProperty.ASSET_ID, "urn:artifact:asset-3"), endpoint); + createDataOffer(dsl, today, endpoint, getAssetJsonLd("asset-1")); + createDataOffer(dsl, today, endpoint, getAssetJsonLd("asset-2")); + createDataOffer(dsl, today, endpoint, getAssetJsonLd("asset-3")); - range(0, 3).forEach(i -> dataOfferDetails(endpoint, "urn:artifact:asset-1")); - range(0, 5).forEach(i -> dataOfferDetails(endpoint, "urn:artifact:asset-2")); + range(0, 3).forEach(i -> dataOfferDetails(endpoint, "asset-1")); + range(0, 5).forEach(i -> dataOfferDetails(endpoint, "asset-2")); var query = new CatalogPageQuery(); @@ -459,27 +455,25 @@ void testSortingByPopularity() { var result = brokerServerClient().brokerServerApi().catalogPage(query); assertThat(result.getDataOffers()).extracting(CatalogDataOffer::getAssetId).containsExactly( - "urn:artifact:asset-2", - "urn:artifact:asset-1", - "urn:artifact:asset-3" + "asset-2", + "asset-1", + "asset-3" ); }); } - private void createDataOffer(DSLContext dsl, OffsetDateTime today, Map assetProperties, String connectorEndpoint) { + private void createDataOffer(DSLContext dsl, OffsetDateTime today, String connectorEndpoint, JsonObject assetJsonLd) { var dataOffer = dsl.newRecord(Tables.DATA_OFFER); - dataOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); - dataOffer.setAssetName(assetProperties.getOrDefault(AssetProperty.ASSET_NAME, dataOffer.getAssetId())); - dataOffer.setAssetProperties(JSONB.jsonb(assetProperties(assetProperties))); + setDataOfferAssetMetadata(dataOffer, assetJsonLd, "my-participant-id"); dataOffer.setConnectorEndpoint(connectorEndpoint); dataOffer.setCreatedAt(today.minusDays(5)); dataOffer.setUpdatedAt(today); dataOffer.insert(); - var contractOffer = dsl.newRecord(Tables.DATA_OFFER_CONTRACT_OFFER); + var contractOffer = dsl.newRecord(Tables.CONTRACT_OFFER); contractOffer.setContractOfferId("my-contract-offer-1"); contractOffer.setConnectorEndpoint(connectorEndpoint); - contractOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); + contractOffer.setAssetId(dataOffer.getAssetId()); contractOffer.setCreatedAt(today.minusDays(5)); contractOffer.setUpdatedAt(today); contractOffer.setPolicy(JSONB.jsonb(policyToJson(dummyPolicy()))); @@ -488,7 +482,7 @@ private void createDataOffer(DSLContext dsl, OffsetDateTime today, Map assetProperties) { - return new ObjectMapper().writeValueAsString(assetProperties); - } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiTest.java index 1436ffd18..c567728af 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/ConnectorApiTest.java @@ -14,10 +14,9 @@ package de.sovity.edc.ext.brokerserver.services.api; -import com.fasterxml.jackson.databind.ObjectMapper; +import de.sovity.edc.ext.brokerserver.TestPolicy; import de.sovity.edc.ext.brokerserver.client.gen.model.ConnectorDetailPageQuery; import de.sovity.edc.ext.brokerserver.client.gen.model.ConnectorPageQuery; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.db.TestDatabase; import de.sovity.edc.ext.brokerserver.db.TestDatabaseFactory; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; @@ -27,12 +26,11 @@ import de.sovity.edc.ext.brokerserver.db.jooq.enums.MeasurementErrorStatus; import de.sovity.edc.ext.brokerserver.db.jooq.enums.MeasurementType; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ConnectorRecord; -import lombok.SneakyThrows; +import de.sovity.edc.utils.jsonld.vocab.Prop; +import jakarta.json.JsonObject; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.policy.model.Policy; import org.jooq.DSLContext; -import org.jooq.JSONB; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,9 +39,10 @@ import java.time.OffsetDateTime; import java.util.Map; -import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; +import static de.sovity.edc.ext.brokerserver.TestAsset.getAssetJsonLd; +import static de.sovity.edc.ext.brokerserver.TestAsset.setDataOfferAssetMetadata; import static de.sovity.edc.ext.brokerserver.TestUtils.brokerServerClient; -import static groovy.json.JsonOutput.toJson; +import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; import static org.assertj.core.api.Assertions.assertThat; @ApiTest @@ -55,8 +54,7 @@ class ConnectorApiTest { @BeforeEach void setUp(EdcExtension extension) { - extension.setConfiguration(createConfiguration(TEST_DATABASE, Map.of( - ))); + extension.setConfiguration(createConfiguration(TEST_DATABASE, Map.of())); } @Test @@ -64,22 +62,24 @@ void testQueryConnectors() { TEST_DATABASE.testTransaction(dsl -> { var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.ASSET_NAME, "My Asset 1" - ), "http://my-connector/ids/data"); + var assetJsonLd = getAssetJsonLd("my-asset-1", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category", + Prop.Dcterms.TITLE, "My Asset 1" + )); + + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd); var result = brokerServerClient().brokerServerApi().connectorPage(new ConnectorPageQuery()); assertThat(result.getConnectors()).hasSize(1); var connector = result.getConnectors().get(0); - assertThat(connector.getId()).isEqualTo("http://my-connector/ids/data"); - assertThat(connector.getEndpoint()).isEqualTo("http://my-connector/ids/data"); + assertThat(connector.getParticipantId()).isEqualTo("my-participant-id"); + assertThat(connector.getEndpoint()).isEqualTo("https://my-connector/api/dsp"); assertThat(connector.getCreatedAt()).isEqualTo(today.minusDays(1)); assertThat(connector.getLastRefreshAttemptAt()).isEqualTo(today); assertThat(connector.getLastSuccessfulRefreshAt()).isEqualTo(today); + assertThat(connector.getNumDataOffers()).isEqualTo(1); }); } @@ -88,17 +88,18 @@ void testQueryConnectorDetails() { TEST_DATABASE.testTransaction(dsl -> { var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector/ids/data"); - createConnector(dsl, today, "http://my-connector2/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.ASSET_NAME, "My Asset 1" - ), "http://my-connector/ids/data"); - - var connector = brokerServerClient().brokerServerApi().connectorDetailPage(new ConnectorDetailPageQuery("http://my-connector/ids/data")); - assertThat(connector.getId()).isEqualTo("http://my-connector/ids/data"); - assertThat(connector.getEndpoint()).isEqualTo("http://my-connector/ids/data"); + var assetJsonLd = getAssetJsonLd("my-asset-1", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category", + Prop.Dcterms.TITLE, "My Asset 1" + )); + + createConnector(dsl, today, "https://my-connector/api/dsp"); + createConnector(dsl, today, "https://my-connector2/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd); + + var connector = brokerServerClient().brokerServerApi().connectorDetailPage(new ConnectorDetailPageQuery("https://my-connector/api/dsp")); + assertThat(connector.getParticipantId()).isEqualTo("my-participant-id"); + assertThat(connector.getEndpoint()).isEqualTo("https://my-connector/api/dsp"); assertThat(connector.getCreatedAt()).isEqualTo(today.minusDays(1)); assertThat(connector.getLastRefreshAttemptAt()).isEqualTo(today); assertThat(connector.getLastSuccessfulRefreshAt()).isEqualTo(today); @@ -108,7 +109,7 @@ void testQueryConnectorDetails() { private void createConnector(DSLContext dsl, OffsetDateTime today, String connectorEndpoint) { var connector = dsl.newRecord(Tables.CONNECTOR); - connector.setConnectorId(connectorEndpoint); + connector.setParticipantId("my-participant-id"); connector.setEndpoint(connectorEndpoint); connector.setOnlineStatus(ConnectorOnlineStatus.ONLINE); connector.setCreatedAt(today.minusDays(1)); @@ -132,38 +133,21 @@ private static void addCrawlingTime(DSLContext dsl, OffsetDateTime today, Connec crawlingTime.insert(); } - private void createDataOffer(DSLContext dsl, OffsetDateTime today, Map assetProperties, String connectorEndpoint) { + private void createDataOffer(DSLContext dsl, OffsetDateTime today, String connectorEndpoint, JsonObject assetJsonLd) { var dataOffer = dsl.newRecord(Tables.DATA_OFFER); - dataOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); - dataOffer.setAssetName(assetProperties.getOrDefault(AssetProperty.ASSET_NAME, dataOffer.getAssetId())); - dataOffer.setAssetProperties(JSONB.jsonb(assetProperties(assetProperties))); + setDataOfferAssetMetadata(dataOffer, assetJsonLd, "my-participant-id"); dataOffer.setConnectorEndpoint(connectorEndpoint); dataOffer.setCreatedAt(today.minusDays(5)); dataOffer.setUpdatedAt(today); dataOffer.insert(); - var contractOffer = dsl.newRecord(Tables.DATA_OFFER_CONTRACT_OFFER); + var contractOffer = dsl.newRecord(Tables.CONTRACT_OFFER); contractOffer.setContractOfferId("my-contract-offer-1"); contractOffer.setConnectorEndpoint(connectorEndpoint); - contractOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); + contractOffer.setAssetId(dataOffer.getAssetId()); contractOffer.setCreatedAt(today.minusDays(5)); contractOffer.setUpdatedAt(today); - contractOffer.setPolicy(JSONB.jsonb(policyToJson(dummyPolicy()))); + contractOffer.setPolicy(TestPolicy.createAfterYesterdayPolicyJson()); contractOffer.insert(); } - - private Policy dummyPolicy() { - return Policy.Builder.newInstance() - .assignee("Example Assignee") - .build(); - } - - private String policyToJson(Policy policy) { - return toJson(policy); - } - - @SneakyThrows - private String assetProperties(Map assetProperties) { - return new ObjectMapper().writeValueAsString(assetProperties); - } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferCountApiTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferCountApiTest.java index 053c14c6d..722ee6747 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferCountApiTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferCountApiTest.java @@ -14,20 +14,18 @@ package de.sovity.edc.ext.brokerserver.services.api; -import com.fasterxml.jackson.databind.ObjectMapper; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; +import de.sovity.edc.ext.brokerserver.TestPolicy; import de.sovity.edc.ext.brokerserver.db.TestDatabase; import de.sovity.edc.ext.brokerserver.db.TestDatabaseFactory; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorContractOffersExceeded; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorDataOffersExceeded; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; -import lombok.SneakyThrows; +import de.sovity.edc.ext.wrapper.api.common.mappers.utils.AssetJsonLdUtils; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.policy.model.Policy; import org.jooq.DSLContext; -import org.jooq.JSONB; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -37,6 +35,8 @@ import java.util.Arrays; import java.util.Map; +import static de.sovity.edc.ext.brokerserver.TestAsset.getAssetJsonLd; +import static de.sovity.edc.ext.brokerserver.TestAsset.setDataOfferAssetMetadata; import static de.sovity.edc.ext.brokerserver.TestUtils.brokerServerClient; import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; import static groovy.json.JsonOutput.toJson; @@ -88,7 +88,7 @@ void testCountByEndpoints() { private void createConnector(DSLContext dsl, OffsetDateTime today, int iConnector) { var connector = dsl.newRecord(Tables.CONNECTOR); - connector.setConnectorId("https://my-connector"); + connector.setParticipantId("my-connector"); connector.setEndpoint(getEndpoint(iConnector)); connector.setOnlineStatus(ConnectorOnlineStatus.ONLINE); connector.setCreatedAt(today.minusDays(1)); @@ -105,26 +105,22 @@ private String getEndpoint(int iConnector) { private void createDataOffer(DSLContext dsl, OffsetDateTime today, int iConnector, int iDataOffer) { var connectorEndpoint = getEndpoint(iConnector); - var assetProperties = Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-%d".formatted(iDataOffer) - ); + var assetJsonLd = getAssetJsonLd("my-asset-%d".formatted(iDataOffer)); var dataOffer = dsl.newRecord(Tables.DATA_OFFER); - dataOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); - dataOffer.setAssetName(assetProperties.getOrDefault(AssetProperty.ASSET_NAME, dataOffer.getAssetId())); - dataOffer.setAssetProperties(JSONB.jsonb(assetProperties(assetProperties))); + setDataOfferAssetMetadata(dataOffer, assetJsonLd, "my-participant-id"); dataOffer.setConnectorEndpoint(connectorEndpoint); dataOffer.setCreatedAt(today.minusDays(5)); dataOffer.setUpdatedAt(today); dataOffer.insert(); - var contractOffer = dsl.newRecord(Tables.DATA_OFFER_CONTRACT_OFFER); + var contractOffer = dsl.newRecord(Tables.CONTRACT_OFFER); contractOffer.setContractOfferId("my-contract-offer-1"); contractOffer.setConnectorEndpoint(connectorEndpoint); - contractOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); + contractOffer.setAssetId(dataOffer.getAssetId()); contractOffer.setCreatedAt(today.minusDays(5)); contractOffer.setUpdatedAt(today); - contractOffer.setPolicy(JSONB.jsonb(policyToJson(dummyPolicy()))); + contractOffer.setPolicy(TestPolicy.createAfterYesterdayPolicyJson()); contractOffer.insert(); } @@ -137,9 +133,4 @@ private Policy dummyPolicy() { private String policyToJson(Policy policy) { return toJson(policy); } - - @SneakyThrows - private String assetProperties(Map assetProperties) { - return new ObjectMapper().writeValueAsString(assetProperties); - } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiTest.java index 44e72ded3..299742ba7 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DataOfferDetailApiTest.java @@ -14,22 +14,19 @@ package de.sovity.edc.ext.brokerserver.services.api; -import com.fasterxml.jackson.databind.ObjectMapper; import de.sovity.edc.ext.brokerserver.client.gen.model.DataOfferDetailPageQuery; import de.sovity.edc.ext.brokerserver.client.gen.model.DataOfferDetailPageResult; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.db.TestDatabase; import de.sovity.edc.ext.brokerserver.db.TestDatabaseFactory; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorContractOffersExceeded; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorDataOffersExceeded; import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; -import lombok.SneakyThrows; +import de.sovity.edc.utils.jsonld.vocab.Prop; +import jakarta.json.JsonObject; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; -import org.eclipse.edc.policy.model.Policy; import org.jooq.DSLContext; -import org.jooq.JSONB; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -38,10 +35,13 @@ import java.time.OffsetDateTime; import java.util.Map; -import static de.sovity.edc.ext.brokerserver.AssertionUtils.assertEqualJson; -import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; +import static de.sovity.edc.ext.brokerserver.AssertionUtils.assertEqualUsingJson; +import static de.sovity.edc.ext.brokerserver.TestAsset.getAssetJsonLd; +import static de.sovity.edc.ext.brokerserver.TestAsset.setDataOfferAssetMetadata; +import static de.sovity.edc.ext.brokerserver.TestPolicy.createAfterYesterdayConstraint; +import static de.sovity.edc.ext.brokerserver.TestPolicy.createAfterYesterdayPolicyJson; import static de.sovity.edc.ext.brokerserver.TestUtils.brokerServerClient; -import static groovy.json.JsonOutput.toJson; +import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; import static org.assertj.core.api.Assertions.assertThat; @ApiTest @@ -62,48 +62,39 @@ void testQueryDataOfferDetails() { TEST_DATABASE.testTransaction(dsl -> { var today = OffsetDateTime.now().withNano(0); - createConnector(dsl, today, "http://my-connector2/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-2", - AssetProperty.DATA_CATEGORY, "my-category2", - AssetProperty.ASSET_NAME, "My Asset 2" - ), "http://my-connector2/ids/data"); - - createConnector(dsl, today, "http://my-connector/ids/data"); - createDataOffer(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.ASSET_NAME, "My Asset 1" - ), "http://my-connector/ids/data"); - - //create view for dataoffer - createDataOfferView(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.ASSET_NAME, "My Asset 1" - ), "http://my-connector/ids/data"); - createDataOfferView(dsl, today, Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.ASSET_NAME, "My Asset 1" - ), "http://my-connector/ids/data"); - - var actual = brokerServerClient().brokerServerApi().dataOfferDetailPage(new DataOfferDetailPageQuery("http://my-connector/ids/data", "urn:artifact:my-asset-1")); - assertThat(actual.getAssetId()).isEqualTo("urn:artifact:my-asset-1"); - assertThat(actual.getConnectorEndpoint()).isEqualTo("http://my-connector/ids/data"); + var assetJsonLd1 = getAssetJsonLd("my-asset-1", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category", + Prop.Dcterms.TITLE, "My Asset 1" + )); + + var assetJsonLd2 = getAssetJsonLd("my-asset-2", Map.of( + Prop.Mds.DATA_CATEGORY, "my-category-2", + Prop.Dcterms.TITLE, "My Asset 2" + )); + + createConnector(dsl, today, "https://my-connector/api/dsp"); + createDataOffer(dsl, today, "https://my-connector/api/dsp", assetJsonLd1); + + createDataOfferView(dsl, today, "https://my-connector/api/dsp", "my-asset-1"); + createDataOfferView(dsl, today, "https://my-connector/api/dsp", "my-asset-1"); + + createConnector(dsl, today, "https://my-connector2/api/dsp"); + createDataOffer(dsl, today, "https://my-connector2/api/dsp", assetJsonLd2); + + var actual = brokerServerClient().brokerServerApi().dataOfferDetailPage(new DataOfferDetailPageQuery("https://my-connector/api/dsp", "my-asset-1")); + assertThat(actual.getAssetId()).isEqualTo("my-asset-1"); + assertThat(actual.getConnectorEndpoint()).isEqualTo("https://my-connector/api/dsp"); assertThat(actual.getConnectorOfflineSinceOrLastUpdatedAt()).isEqualTo(today); assertThat(actual.getConnectorOnlineStatus()).isEqualTo(DataOfferDetailPageResult.ConnectorOnlineStatusEnum.ONLINE); assertThat(actual.getCreatedAt()).isEqualTo(today.minusDays(5)); - assertThat(actual.getProperties()).isEqualTo(Map.of( - AssetProperty.ASSET_ID, "urn:artifact:my-asset-1", - AssetProperty.DATA_CATEGORY, "my-category", - AssetProperty.ASSET_NAME, "My Asset 1" - )); + assertThat(actual.getAsset().getAssetId()).isEqualTo("my-asset-1"); + assertThat(actual.getAsset().getDataCategory()).isEqualTo("my-category"); + assertThat(actual.getAsset().getTitle()).isEqualTo("My Asset 1"); assertThat(actual.getUpdatedAt()).isEqualTo(today); assertThat(actual.getContractOffers()).hasSize(1); var contractOffer = actual.getContractOffers().get(0); assertThat(contractOffer.getContractOfferId()).isEqualTo("my-contract-offer-1"); - assertEqualJson(contractOffer.getContractPolicy().getLegacyPolicy(), policyToJson(dummyPolicy())); + assertEqualUsingJson(contractOffer.getContractPolicy().getConstraints().get(0), createAfterYesterdayConstraint()); assertThat(contractOffer.getCreatedAt()).isEqualTo(today.minusDays(5)); assertThat(contractOffer.getUpdatedAt()).isEqualTo(today); assertThat(actual.getViewCount()).isEqualTo(2); @@ -112,7 +103,7 @@ void testQueryDataOfferDetails() { private void createConnector(DSLContext dsl, OffsetDateTime today, String connectorEndpoint) { var connector = dsl.newRecord(Tables.CONNECTOR); - connector.setConnectorId("http://my-connector"); + connector.setParticipantId("my-connector"); connector.setEndpoint(connectorEndpoint); connector.setOnlineStatus(ConnectorOnlineStatus.ONLINE); connector.setCreatedAt(today.minusDays(1)); @@ -123,46 +114,29 @@ private void createConnector(DSLContext dsl, OffsetDateTime today, String connec connector.insert(); } - private void createDataOffer(DSLContext dsl, OffsetDateTime today, Map assetProperties, String connectorEndpoint) { + private void createDataOffer(DSLContext dsl, OffsetDateTime today, String connectorEndpoint, JsonObject assetJsonLd) { var dataOffer = dsl.newRecord(Tables.DATA_OFFER); - dataOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); - dataOffer.setAssetName(assetProperties.getOrDefault(AssetProperty.ASSET_NAME, dataOffer.getAssetId())); - dataOffer.setAssetProperties(JSONB.jsonb(assetProperties(assetProperties))); + setDataOfferAssetMetadata(dataOffer, assetJsonLd, "my-participant-id"); dataOffer.setConnectorEndpoint(connectorEndpoint); dataOffer.setCreatedAt(today.minusDays(5)); dataOffer.setUpdatedAt(today); dataOffer.insert(); - var contractOffer = dsl.newRecord(Tables.DATA_OFFER_CONTRACT_OFFER); + var contractOffer = dsl.newRecord(Tables.CONTRACT_OFFER); contractOffer.setContractOfferId("my-contract-offer-1"); contractOffer.setConnectorEndpoint(connectorEndpoint); - contractOffer.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); + contractOffer.setAssetId(dataOffer.getAssetId()); contractOffer.setCreatedAt(today.minusDays(5)); contractOffer.setUpdatedAt(today); - contractOffer.setPolicy(JSONB.jsonb(policyToJson(dummyPolicy()))); + contractOffer.setPolicy(createAfterYesterdayPolicyJson()); contractOffer.insert(); } - private static void createDataOfferView(DSLContext dsl, OffsetDateTime date, Map assetProperties, String connectorEndpoint) { + private static void createDataOfferView(DSLContext dsl, OffsetDateTime date, String connectorEndpoint, String assetId) { var view = dsl.newRecord(Tables.DATA_OFFER_VIEW_COUNT); - view.setAssetId(assetProperties.get(AssetProperty.ASSET_ID)); + view.setAssetId(assetId); view.setConnectorEndpoint(connectorEndpoint); view.setDate(date); view.insert(); } - - private Policy dummyPolicy() { - return Policy.Builder.newInstance() - .assignee("Example Assignee") - .build(); - } - - private String policyToJson(Policy policy) { - return toJson(policy); - } - - @SneakyThrows - private String assetProperties(Map assetProperties) { - return new ObjectMapper().writeValueAsString(assetProperties); - } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DeleteConnectorsApiTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DeleteConnectorsApiTest.java index 21c57b658..fb6ba3aca 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DeleteConnectorsApiTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/api/DeleteConnectorsApiTest.java @@ -14,6 +14,7 @@ package de.sovity.edc.ext.brokerserver.services.api; +import de.sovity.edc.ext.brokerserver.TestPolicy; import de.sovity.edc.ext.brokerserver.TestUtils; import de.sovity.edc.ext.brokerserver.client.BrokerServerClient; import de.sovity.edc.ext.brokerserver.client.gen.model.ConnectorListEntry; @@ -28,9 +29,7 @@ import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; import org.jooq.DSLContext; -import org.jooq.JSONB; import org.jooq.Record; -import org.jooq.Record1; import org.jooq.TableField; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -42,6 +41,8 @@ import java.util.List; import java.util.Map; +import static de.sovity.edc.ext.brokerserver.TestAsset.getAssetJsonLd; +import static de.sovity.edc.ext.brokerserver.TestAsset.setDataOfferAssetMetadata; import static de.sovity.edc.ext.brokerserver.TestUtils.ADMIN_API_KEY; import static de.sovity.edc.ext.brokerserver.TestUtils.brokerServerClient; import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; @@ -72,7 +73,7 @@ void testRemoveConnectors() { var connectorsBefore = List.of(firstConnector, otherConnector); assertContainsEndpoints(dsl, Tables.BROKER_EXECUTION_TIME_MEASUREMENT.CONNECTOR_ENDPOINT, connectorsBefore); - assertContainsEndpoints(dsl, Tables.DATA_OFFER_CONTRACT_OFFER.CONNECTOR_ENDPOINT, connectorsBefore); + assertContainsEndpoints(dsl, Tables.CONTRACT_OFFER.CONNECTOR_ENDPOINT, connectorsBefore); assertContainsEndpoints(dsl, Tables.DATA_OFFER.CONNECTOR_ENDPOINT, connectorsBefore); assertContainsEndpoints(dsl, Tables.DATA_OFFER_VIEW_COUNT.CONNECTOR_ENDPOINT, connectorsBefore); assertContainsEndpoints(dsl, Tables.CONNECTOR.ENDPOINT, connectorsBefore); @@ -87,7 +88,7 @@ void testRemoveConnectors() { var connectorsAfter = List.of(otherConnector); assertContainsEndpoints(dsl, Tables.BROKER_EXECUTION_TIME_MEASUREMENT.CONNECTOR_ENDPOINT, connectorsAfter); - assertContainsEndpoints(dsl, Tables.DATA_OFFER_CONTRACT_OFFER.CONNECTOR_ENDPOINT, connectorsAfter); + assertContainsEndpoints(dsl, Tables.CONTRACT_OFFER.CONNECTOR_ENDPOINT, connectorsAfter); assertContainsEndpoints(dsl, Tables.DATA_OFFER.CONNECTOR_ENDPOINT, connectorsAfter); assertContainsEndpoints(dsl, Tables.DATA_OFFER_VIEW_COUNT.CONNECTOR_ENDPOINT, connectorsAfter); assertContainsEndpoints(dsl, Tables.CONNECTOR.ENDPOINT, connectorsAfter); @@ -109,20 +110,18 @@ public void setupConnectorData(DSLContext dsl, String endpoint) { var assetId = "my-asset"; var dataOffer = dsl.newRecord(Tables.DATA_OFFER); - dataOffer.setAssetId(assetId); - dataOffer.setAssetName("My Asset"); - dataOffer.setAssetProperties(JSONB.valueOf("{}")); + setDataOfferAssetMetadata(dataOffer, getAssetJsonLd("my-asset"), "my-participant-id"); dataOffer.setConnectorEndpoint(endpoint); dataOffer.setCreatedAt(OffsetDateTime.now()); dataOffer.setUpdatedAt(OffsetDateTime.now()); dataOffer.insert(); - var contractOffer = dsl.newRecord(Tables.DATA_OFFER_CONTRACT_OFFER); + var contractOffer = dsl.newRecord(Tables.CONTRACT_OFFER); contractOffer.setAssetId(assetId); contractOffer.setConnectorEndpoint(endpoint); contractOffer.setContractOfferId("my-asset-co"); contractOffer.setCreatedAt(OffsetDateTime.now()); - contractOffer.setPolicy(JSONB.valueOf("{}")); + contractOffer.setPolicy(TestPolicy.createAfterYesterdayPolicyJson()); contractOffer.setUpdatedAt(OffsetDateTime.now()); contractOffer.insert(); diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/logging/BrokerEventLoggerTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/logging/BrokerEventLoggerTest.java index d93c33671..eee984c6f 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/logging/BrokerEventLoggerTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/logging/BrokerEventLoggerTest.java @@ -42,7 +42,7 @@ void testDataOfferWriter_allSortsOfUpdates() { var brokerEventLogger = new BrokerEventLogger(); // Test that insertions insert required fields and don't cause DB errors - String endpoint = "https://example.com/ids/data"; + String endpoint = "https://example.com/api/dsp"; brokerEventLogger.logConnectorUpdated(dsl, endpoint, new ConnectorChangeTracker()); brokerEventLogger.logConnectorOnline(dsl, endpoint); brokerEventLogger.logConnectorOffline(dsl, endpoint, new BrokerEventErrorMessage("Message", "Stacktrace")); diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdaterTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdaterTest.java index 3dcd46eaa..07ac1e531 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdaterTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/ConnectorUpdaterTest.java @@ -14,184 +14,171 @@ package de.sovity.edc.ext.brokerserver.services.refreshing; +import de.sovity.edc.client.EdcClient; +import de.sovity.edc.client.gen.model.ContractDefinitionRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.UiAssetCreateRequest; +import de.sovity.edc.client.gen.model.UiCriterion; +import de.sovity.edc.client.gen.model.UiCriterionLiteral; +import de.sovity.edc.client.gen.model.UiCriterionLiteralType; +import de.sovity.edc.client.gen.model.UiCriterionOperator; +import de.sovity.edc.ext.brokerserver.AssertionUtils; import de.sovity.edc.ext.brokerserver.BrokerServerExtensionContext; import de.sovity.edc.ext.brokerserver.TestUtils; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; +import de.sovity.edc.ext.brokerserver.client.BrokerServerClient; +import de.sovity.edc.ext.brokerserver.client.gen.model.CatalogPageQuery; import de.sovity.edc.ext.brokerserver.db.TestDatabase; import de.sovity.edc.ext.brokerserver.db.TestDatabaseFactory; -import de.sovity.edc.ext.brokerserver.db.jooq.Tables; -import de.sovity.edc.ext.brokerserver.db.jooq.enums.ConnectorOnlineStatus; -import io.restassured.path.json.JsonPath; -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.connector.spi.asset.AssetService; +import de.sovity.edc.utils.jsonld.vocab.Prop; 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.spi.asset.AssetSelectorExpression; -import org.eclipse.edc.spi.persistence.EdcPersistenceException; -import org.eclipse.edc.spi.types.domain.DataAddress; -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; import org.junit.jupiter.api.extension.RegisterExtension; -import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import static de.sovity.edc.ext.brokerserver.TestPolicy.createAfterYesterdayConstraint; +import static de.sovity.edc.ext.brokerserver.TestPolicy.createAfterYesterdayPolicyEdcGen; import static de.sovity.edc.ext.brokerserver.TestUtils.createConfiguration; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; @ApiTest -@ExtendWith(EdcExtension.class) class ConnectorUpdaterTest { @RegisterExtension private static final TestDatabase TEST_DATABASE = TestDatabaseFactory.getTestDatabase(); + @RegisterExtension + static EdcExtension consumerEdcContext = new EdcExtension(); + + private EdcClient providerClient; + + private BrokerServerClient brokerServerClient; + @BeforeEach void setUp(EdcExtension extension) { extension.setConfiguration(createConfiguration(TEST_DATABASE, Map.of())); + + providerClient = EdcClient.builder() + .managementApiUrl(TestUtils.MANAGEMENT_ENDPOINT) + .managementApiKey(TestUtils.MANAGEMENT_API_KEY) + .build(); + + brokerServerClient = BrokerServerClient.builder() + .managementApiUrl(TestUtils.MANAGEMENT_ENDPOINT) + .managementApiKey(TestUtils.MANAGEMENT_API_KEY) + .build(); } @Test - void testConnectorUpdate( - AssetService assetService, - PolicyDefinitionStore policyDefinitionStore, - ContractDefinitionStore contractDefinitionStore - ) { + void testConnectorUpdate() { TEST_DATABASE.testTransaction(dsl -> { // arrange - var connectorEndpoint = TestUtils.PROTOCOL_ENDPOINT; var connectorUpdater = BrokerServerExtensionContext.instance.connectorUpdater(); var connectorCreator = BrokerServerExtensionContext.instance.connectorCreator(); + String connectorEndpoint = TestUtils.PROTOCOL_ENDPOINT; - createAlwaysTruePolicyDefinition(policyDefinitionStore); - createAlwaysTrueContractDefinition(contractDefinitionStore); - - var nestedObjProperty = new LinkedHashMap(Map.of( - "test-string", "hello", - "test-uri", "https://w3id.org/idsa/code/AB", - "http://test-uri-key", "value", - - "test-array", new ArrayList<>(List.of("a", "b")), - "test-float", 5.1, - "test-int", 5, - "test-boolean", true, - - "test-obj", new LinkedHashMap<>(Map.of("key", "value")) - )); - nestedObjProperty.put("test-null", null); - - var asset = Asset.Builder.newInstance() - .id("test-asset-1") - .property(AssetProperty.ASSET_ID, "test-asset-1") - .property(AssetProperty.ASSET_NAME, "Test Asset 1") - .property("test-string", "hello") - .property("test-uri", "https://w3id.org/idsa/code/AB") - .property("http://test-uri-key", "value") - - .property("test-array", new ArrayList<>(List.of("a", "b"))) - .property("test-float", 5.1) - .property("test-int", 5) - .property("test-boolean", true) - - .property("test-obj", nestedObjProperty) - .build(); - - assetService.create(asset, dataAddress()); + var policyId = createPolicyDefinition(); + var assetId = createAsset(); + createContractDefinition(policyId, assetId); connectorCreator.addConnector(dsl, connectorEndpoint); // act connectorUpdater.updateConnector(connectorEndpoint); // assert - var connectors = dsl.selectFrom(Tables.CONNECTOR).stream().toList(); - assertThat(connectors.get(0).getOnlineStatus()).isEqualTo(ConnectorOnlineStatus.ONLINE); - assertThat(connectors.get(0).getEndpoint()).isEqualTo(connectorEndpoint); - - var dataOffers = dsl.selectFrom(Tables.DATA_OFFER).stream().toList(); - assertThat(dataOffers).hasSize(1); - - var dataOffer = dataOffers.get(0); - assertThat(dataOffer.getAssetId()).isEqualTo("test-asset-1"); - assertThat(dataOffer.getAssetProperties().data()).contains("Test Asset 1"); - - var props = JsonPath.from(dataOffer.getAssetProperties().data()); - assertThat(props.getString("\"asset:prop:name\"")).isEqualTo("Test Asset 1"); - assertThat(props.getString("test-string")).isEqualTo("hello"); - assertThat(props.getString("test-uri")).isEqualTo("https://w3id.org/idsa/code/AB"); - assertThat(props.getString("http://test-uri-key")).isEqualTo("value"); - - assertThat(props.getString("test-array")).isEqualTo("[\"a\",\"b\"]"); - assertThat(props.getString("test-int")).isEqualTo("5"); - assertThat(props.getString("test-float")).isEqualTo("5.1"); - assertThat(props.getString("test-boolean")).isEqualTo("true"); - - var testObj = JsonPath.from(props.getString("test-obj")); - assertThat((String) testObj.get("test-string")).isEqualTo("hello"); - assertThat((String) testObj.get("test-uri")).isEqualTo("https://w3id.org/idsa/code/AB"); - assertThat((String) testObj.get("http://test-uri-key")).isEqualTo("value"); - - assertThat((List) testObj.get("test-array")).isEqualTo(List.of("a", "b")); - assertThat((Integer) testObj.get("test-int")).isEqualTo(5); - assertThat((Float) testObj.get("test-float")).isEqualTo(5.1f); - assertThat((Boolean) testObj.get("test-boolean")).isTrue(); - assertThat((Map) testObj.get("test-obj")).isEqualTo(Map.of("key", "value")); - - // the nested object's null will have disappeared - assertThat(testObj.getMap("")).containsKey("test-string"); - assertThat(testObj.getMap("")).doesNotContainKey("test-null"); - - var contractOffers = dsl.selectFrom(Tables.DATA_OFFER_CONTRACT_OFFER).stream().toList(); - assertThat(contractOffers).hasSize(1); + var catalog = brokerServerClient.brokerServerApi().catalogPage(new CatalogPageQuery()); + assertThat(catalog.getDataOffers()).hasSize(1); + var dataOffer = catalog.getDataOffers().get(0); + assertThat(dataOffer.getContractOffers()).hasSize(1); + var contractOffer = dataOffer.getContractOffers().get(0); + var asset = dataOffer.getAsset(); + assertThat(asset.getAssetId()).isEqualTo(assetId); + assertThat(asset.getTitle()).isEqualTo("AssetName"); + assertThat(asset.getConnectorEndpoint()).isEqualTo(TestUtils.PROTOCOL_ENDPOINT); + assertThat(asset.getParticipantId()).isEqualTo(TestUtils.PARTICIPANT_ID); + assertThat(asset.getKeywords()).isEqualTo(List.of("keyword1", "keyword2")); + assertThat(asset.getDescription()).isEqualTo("AssetDescription"); + assertThat(asset.getVersion()).isEqualTo("1.0.0"); + assertThat(asset.getLanguage()).isEqualTo("en"); + assertThat(asset.getMediaType()).isEqualTo("application/json"); + assertThat(asset.getDataCategory()).isEqualTo("dataCategory"); + assertThat(asset.getDataSubcategory()).isEqualTo("dataSubcategory"); + assertThat(asset.getDataModel()).isEqualTo("dataModel"); + assertThat(asset.getGeoReferenceMethod()).isEqualTo("geoReferenceMethod"); + assertThat(asset.getTransportMode()).isEqualTo("transportMode"); + assertThat(asset.getLicenseUrl()).isEqualTo("https://license-url"); + assertThat(asset.getKeywords()).isEqualTo(List.of("keyword1", "keyword2")); + assertThat(asset.getCreatorOrganizationName()).isEqualTo(TestUtils.CURATOR_NAME); + assertThat(asset.getPublisherHomepage()).isEqualTo("publisherHomepage"); + assertThat(asset.getHttpDatasourceHintsProxyMethod()).isFalse(); + assertThat(asset.getHttpDatasourceHintsProxyPath()).isFalse(); + assertThat(asset.getHttpDatasourceHintsProxyQueryParams()).isFalse(); + assertThat(asset.getHttpDatasourceHintsProxyBody()).isFalse(); + assertThat(asset.getAdditionalProperties()) + .containsExactlyEntriesOf(Map.of("http://unknown/a", "x")); + assertThat(dataOffer.getAsset().getAdditionalJsonProperties()) + .containsExactlyEntriesOf(Map.of("http://unknown/b", "{\"http://unknown/c\":\"y\"}")); + assertThat(dataOffer.getAsset().getPrivateProperties()).isEmpty(); + assertThat(dataOffer.getAsset().getPrivateJsonProperties()).isEmpty(); + var policy = contractOffer.getContractPolicy(); + assertThat(policy.getConstraints()).hasSize(1); + AssertionUtils.assertEqualUsingJson(policy.getConstraints().get(0), createAfterYesterdayConstraint()); }); } - @Test - void testTopLevelAssetPropertyCannotBeNull(AssetService assetService) { - var asset = Asset.Builder.newInstance() - .id("test-asset-1") - .property("test-null", null) + private String createPolicyDefinition() { + var policyDefinition = PolicyDefinitionCreateRequest.builder() + .policyDefinitionId("policy-1") + .policy(createAfterYesterdayPolicyEdcGen()) .build(); - var dataAddress = dataAddress(); - assertThatThrownBy(() -> assetService.create(asset, dataAddress)) - .isInstanceOf(EdcPersistenceException.class) - .hasMessage("java.lang.NullPointerException: Cannot invoke \"Object.getClass()\" because the return value of \"java.util.Map$Entry.getValue()\" is null"); - } - private DataAddress dataAddress() { - return DataAddress.Builder.newInstance() - .properties(Map.of( - "type", "HttpData", - "baseUrl", "https://jsonplaceholder.typicode.com/todos/1" - )) - .build(); + return providerClient.uiApi().createPolicyDefinition(policyDefinition).getId(); } - private void createAlwaysTruePolicyDefinition(PolicyDefinitionStore policyDefinitionStore) { - var policyDefinition = PolicyDefinition.Builder.newInstance() - .id("always-true") - .policy(Policy.Builder.newInstance().build()) - .build(); - policyDefinitionStore.save(policyDefinition); + public void createContractDefinition(String policyId, String assetId) { + providerClient.uiApi().createContractDefinition(ContractDefinitionRequest.builder() + .contractDefinitionId("cd-1") + .accessPolicyId(policyId) + .contractPolicyId(policyId) + .assetSelector(List.of(UiCriterion.builder() + .operandLeft(Prop.Edc.ID) + .operator(UiCriterionOperator.EQ) + .operandRight(UiCriterionLiteral.builder() + .type(UiCriterionLiteralType.VALUE) + .value(assetId) + .build()) + .build())) + .build()); } - public void createAlwaysTrueContractDefinition(ContractDefinitionStore contractDefinitionStore) { - var contractDefinition = ContractDefinition.Builder.newInstance() - .id("always-true-cd") - .contractPolicyId("always-true") - .accessPolicyId("always-true") - .selectorExpression(AssetSelectorExpression.SELECT_ALL) - .validity(1000) //else throws "validity must be strictly positive" - .build(); - contractDefinitionStore.save(contractDefinition); + private String createAsset() { + return providerClient.uiApi().createAsset(UiAssetCreateRequest.builder() + .id("asset-1") + .title("AssetName") + .description("AssetDescription") + .licenseUrl("https://license-url") + .version("1.0.0") + .language("en") + .mediaType("application/json") + .dataCategory("dataCategory") + .dataSubcategory("dataSubcategory") + .dataModel("dataModel") + .geoReferenceMethod("geoReferenceMethod") + .transportMode("transportMode") + .keywords(List.of("keyword1", "keyword2")) + .publisherHomepage("publisherHomepage") + .dataAddressProperties(Map.of( + Prop.Edc.TYPE, "HttpData", + Prop.Edc.METHOD, "GET", + Prop.Edc.BASE_URL, "http://some.url" + )) + .additionalProperties(Map.of("http://unknown/a", "x")) + .additionalJsonProperties(Map.of("http://unknown/b", "{\"http://unknown/c\":\"y\"}")) + .privateProperties(Map.of("http://unknown/a-private", "x-private")) + .privateJsonProperties(Map.of("http://unknown/b-private", "{\"http://unknown/c-private\":\"y-private\"}")) + .build()).getId(); } - } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferLimitsEnforcerTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferLimitsEnforcerTest.java index 885ad6834..9a0da5f0c 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferLimitsEnforcerTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferLimitsEnforcerTest.java @@ -19,8 +19,8 @@ import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ConnectorRecord; import de.sovity.edc.ext.brokerserver.services.config.BrokerServerSettings; import de.sovity.edc.ext.brokerserver.services.logging.BrokerEventLogger; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedContractOffer; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOfferContractOffer; import org.jooq.DSLContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -58,7 +58,7 @@ void no_limit_and_two_dataofffers_and_contractoffer_should_not_limit() { when(settings.getMaxContractOffersPerDataOffer()).thenReturn(maxContractOffers); var myDataOffer = new FetchedDataOffer(); - myDataOffer.setContractOffers(List.of(new FetchedDataOfferContractOffer(), new FetchedDataOfferContractOffer())); + myDataOffer.setContractOffers(List.of(new FetchedContractOffer(), new FetchedContractOffer())); var dataOffers = List.of(myDataOffer, myDataOffer); // act @@ -104,7 +104,7 @@ void limit_one_and_two_dataoffers_should_result_to_one() { when(settings.getMaxContractOffersPerDataOffer()).thenReturn(maxContractOffers); var myDataOffer = new FetchedDataOffer(); - myDataOffer.setContractOffers(List.of(new FetchedDataOfferContractOffer(), new FetchedDataOfferContractOffer())); + myDataOffer.setContractOffers(List.of(new FetchedContractOffer(), new FetchedContractOffer())); var dataOffers = List.of(myDataOffer, myDataOffer); // act @@ -133,7 +133,7 @@ void verify_logConnectorUpdateDataOfferLimitExceeded() { when(settings.getMaxContractOffersPerDataOffer()).thenReturn(maxContractOffers); var myDataOffer = new FetchedDataOffer(); - myDataOffer.setContractOffers(List.of(new FetchedDataOfferContractOffer(), new FetchedDataOfferContractOffer())); + myDataOffer.setContractOffers(List.of(new FetchedContractOffer(), new FetchedContractOffer())); var dataOffers = List.of(myDataOffer, myDataOffer); // act @@ -157,7 +157,7 @@ void verify_logConnectorUpdateDataOfferLimitOk() { when(settings.getMaxContractOffersPerDataOffer()).thenReturn(maxContractOffers); var myDataOffer = new FetchedDataOffer(); - myDataOffer.setContractOffers(List.of(new FetchedDataOfferContractOffer(), new FetchedDataOfferContractOffer())); + myDataOffer.setContractOffers(List.of(new FetchedContractOffer(), new FetchedContractOffer())); var dataOffers = List.of(myDataOffer, myDataOffer); // act @@ -181,7 +181,7 @@ void verify_logConnectorUpdateContractOfferLimitExceeded() { when(settings.getMaxContractOffersPerDataOffer()).thenReturn(maxContractOffers); var myDataOffer = new FetchedDataOffer(); - myDataOffer.setContractOffers(List.of(new FetchedDataOfferContractOffer(), new FetchedDataOfferContractOffer())); + myDataOffer.setContractOffers(List.of(new FetchedContractOffer(), new FetchedContractOffer())); var dataOffers = List.of(myDataOffer, myDataOffer); // act @@ -205,7 +205,7 @@ void verify_logConnectorUpdateContractOfferLimitOk() { when(settings.getMaxContractOffersPerDataOffer()).thenReturn(maxContractOffers); var myDataOffer = new FetchedDataOffer(); - myDataOffer.setContractOffers(List.of(new FetchedDataOfferContractOffer(), new FetchedDataOfferContractOffer())); + myDataOffer.setContractOffers(List.of(new FetchedContractOffer(), new FetchedContractOffer())); var dataOffers = List.of(myDataOffer, myDataOffer); // act diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTest.java index 78412a0bd..c8792e345 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTest.java @@ -30,6 +30,7 @@ import java.time.temporal.ChronoUnit; import java.util.List; +import static de.sovity.edc.ext.brokerserver.AssertionUtils.assertEqualJson; import static org.assertj.core.api.Assertions.assertThat; class DataOfferWriterTest { @@ -56,7 +57,7 @@ void testDataOfferWriter_allSortsOfUpdates() { testData.fetched(unchanged); var fieldChangedExisting = Do.forName("fieldChanged"); - var fieldChangedFetched = fieldChangedExisting.withAssetName("changed"); + var fieldChangedFetched = fieldChangedExisting.withAssetTitle("changed"); testData.existing(fieldChangedExisting); testData.fetched(fieldChangedFetched); @@ -139,9 +140,9 @@ void testDataOfferWriter_allSortsOfUpdates() { } private void assertAssetPropertiesEqual(DataOfferWriterTestDataHelper testData, DataOfferRecord actual, Do expected) { - var actualAssetJson = actual.getAssetProperties().data(); + var actualAssetJson = actual.getAssetJsonLd().data(); var expectedAssetJson = testData.dummyAssetJson(expected); - assertThat(actualAssetJson).isEqualTo(expectedAssetJson); + assertEqualJson(actualAssetJson, expectedAssetJson); } private void assertPolicyEquals( diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataHelper.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataHelper.java index 227c5a82f..312e83765 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataHelper.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataHelper.java @@ -14,13 +14,14 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers; -import de.sovity.edc.ext.brokerserver.dao.AssetProperty; import de.sovity.edc.ext.brokerserver.dao.ConnectorQueries; -import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferContractOfferRecord; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ContractOfferRecord; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; import de.sovity.edc.ext.brokerserver.services.ConnectorCreator; +import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedContractOffer; import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOffer; -import de.sovity.edc.ext.brokerserver.services.refreshing.offers.model.FetchedDataOfferContractOffer; +import de.sovity.edc.utils.JsonUtils; +import de.sovity.edc.utils.jsonld.vocab.Prop; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -29,16 +30,18 @@ import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import static de.sovity.edc.ext.brokerserver.TestAsset.getAssetJsonLd; import static de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferWriterTestDataModels.Co; import static de.sovity.edc.ext.brokerserver.services.refreshing.offers.DataOfferWriterTestDataModels.Do; class DataOfferWriterTestDataHelper { - String connectorEndpoint = "https://example.com/ids/data"; + String connectorEndpoint = "https://example.com/api/dsp"; OffsetDateTime old = OffsetDateTime.now().withNano(0).withSecond(0).withMinute(0).withHour(0).minusDays(100); - List existingContractOffers = new ArrayList<>(); + List existingContractOffers = new ArrayList<>(); List existingDataOffers = new ArrayList<>(); List fetchedDataOffers = new ArrayList<>(); @@ -75,8 +78,8 @@ public void initialize(DSLContext dsl) { dsl.batchInsert(existingContractOffers).execute(); } - private DataOfferContractOfferRecord dummyContractOffer(Do dataOffer, Co contractOffer) { - var contractOfferRecord = new DataOfferContractOfferRecord(); + private ContractOfferRecord dummyContractOffer(Do dataOffer, Co contractOffer) { + var contractOfferRecord = new ContractOfferRecord(); contractOfferRecord.setConnectorEndpoint(connectorEndpoint); contractOfferRecord.setAssetId(dataOffer.getAssetId()); contractOfferRecord.setContractOfferId(contractOffer.getId()); @@ -87,13 +90,13 @@ private DataOfferContractOfferRecord dummyContractOffer(Do dataOffer, Co contrac } private DataOfferRecord dummyDataOffer(Do dataOffer) { - var assetName = Optional.of(dataOffer.getAssetName()).orElse(dataOffer.getAssetId()); + var assetName = Optional.of(dataOffer.getAssetTitle()).orElse(dataOffer.getAssetId()); var dataOfferRecord = new DataOfferRecord(); dataOfferRecord.setConnectorEndpoint(connectorEndpoint); dataOfferRecord.setAssetId(dataOffer.getAssetId()); - dataOfferRecord.setAssetName(assetName); - dataOfferRecord.setAssetProperties(JSONB.valueOf(dummyAssetJson(dataOffer))); + dataOfferRecord.setAssetTitle(assetName); + dataOfferRecord.setAssetJsonLd(JSONB.valueOf(dummyAssetJson(dataOffer))); dataOfferRecord.setCreatedAt(old); dataOfferRecord.setUpdatedAt(old); return dataOfferRecord; @@ -102,8 +105,8 @@ private DataOfferRecord dummyDataOffer(Do dataOffer) { private FetchedDataOffer dummyFetchedDataOffer(Do dataOffer) { var fetchedDataOffer = new FetchedDataOffer(); fetchedDataOffer.setAssetId(dataOffer.getAssetId()); - fetchedDataOffer.setAssetName(dataOffer.getAssetName()); - fetchedDataOffer.setAssetPropertiesJson(dummyAssetJson(dataOffer)); + fetchedDataOffer.setAssetTitle(dataOffer.getAssetTitle()); + fetchedDataOffer.setAssetJsonLd(dummyAssetJson(dataOffer)); var contractOffersMapped = dataOffer.getContractOffers().stream().map(this::dummyFetchedContractOffer).collect(Collectors.toList()); fetchedDataOffer.setContractOffers(contractOffersMapped); @@ -112,10 +115,8 @@ private FetchedDataOffer dummyFetchedDataOffer(Do dataOffer) { } public String dummyAssetJson(Do dataOffer) { - return "{\"%s\": \"%s\", \"%s\": \"%s\"}".formatted( - AssetProperty.ASSET_ID, dataOffer.getAssetId(), - AssetProperty.ASSET_NAME, dataOffer.getAssetName() - ); + var assetJsonLd = getAssetJsonLd(dataOffer.getAssetId(), Map.of(Prop.Dcterms.TITLE, dataOffer.getAssetTitle())); + return JsonUtils.toJson(assetJsonLd); } public String dummyPolicyJson(String policyValue) { @@ -125,8 +126,8 @@ public String dummyPolicyJson(String policyValue) { } @NotNull - private FetchedDataOfferContractOffer dummyFetchedContractOffer(Co it) { - var contractOffer = new FetchedDataOfferContractOffer(); + private FetchedContractOffer dummyFetchedContractOffer(Co it) { + var contractOffer = new FetchedContractOffer(); contractOffer.setContractOfferId(it.getId()); contractOffer.setPolicyJson(dummyPolicyJson(it.getPolicyValue())); return contractOffer; diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataModels.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataModels.java index ca7343a94..ab15daccb 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataModels.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDataModels.java @@ -29,7 +29,7 @@ static class Do { @With String assetId; @With - String assetName; + String assetTitle; @With List contractOffers; @@ -40,7 +40,7 @@ public Do withContractOffer(Co co) { } public static Do forName(String name) { - return new Do(name, name + " Name", List.of(new Co(name + " CO", name + " Policy"))); + return new Do(name, name + " Title", List.of(new Co(name + " CO", name + " Policy"))); } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDydi.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDydi.java index 962695078..d44383937 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDydi.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestDydi.java @@ -14,7 +14,7 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers; -import de.sovity.edc.ext.brokerserver.dao.DataOfferContractOfferQueries; +import de.sovity.edc.ext.brokerserver.dao.ContractOfferQueries; import de.sovity.edc.ext.brokerserver.dao.DataOfferQueries; import de.sovity.edc.ext.brokerserver.services.config.BrokerServerSettings; import lombok.Value; @@ -27,11 +27,11 @@ class DataOfferWriterTestDydi { Config config = mock(Config.class); BrokerServerSettings brokerServerSettings = mock(BrokerServerSettings.class); DataOfferQueries dataOfferQueries = new DataOfferQueries(); - DataOfferContractOfferQueries dataOfferContractOfferQueries = new DataOfferContractOfferQueries(); + ContractOfferQueries contractOfferQueries = new ContractOfferQueries(); ContractOfferRecordUpdater contractOfferRecordUpdater = new ContractOfferRecordUpdater(); DataOfferRecordUpdater dataOfferRecordUpdater = new DataOfferRecordUpdater(); DataOfferPatchBuilder dataOfferPatchBuilder = new DataOfferPatchBuilder( - dataOfferContractOfferQueries, + contractOfferQueries, dataOfferQueries, dataOfferRecordUpdater, contractOfferRecordUpdater diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestResultHelper.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestResultHelper.java index db42a2e3c..1b2f04c21 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestResultHelper.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/refreshing/offers/DataOfferWriterTestResultHelper.java @@ -15,7 +15,7 @@ package de.sovity.edc.ext.brokerserver.services.refreshing.offers; import de.sovity.edc.ext.brokerserver.db.jooq.Tables; -import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferContractOfferRecord; +import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.ContractOfferRecord; import de.sovity.edc.ext.brokerserver.db.jooq.tables.records.DataOfferRecord; import org.jetbrains.annotations.NotNull; import org.jooq.DSLContext; @@ -28,13 +28,13 @@ class DataOfferWriterTestResultHelper { private final @NotNull Map dataOffers; - private final @NotNull Map> contractOffers; + private final @NotNull Map> contractOffers; DataOfferWriterTestResultHelper(DSLContext dsl) { this.dataOffers = dsl.selectFrom(Tables.DATA_OFFER).fetchMap(Tables.DATA_OFFER.ASSET_ID); - this.contractOffers = dsl.selectFrom(Tables.DATA_OFFER_CONTRACT_OFFER).stream().collect(groupingBy( - DataOfferContractOfferRecord::getAssetId, - Collectors.toMap(DataOfferContractOfferRecord::getContractOfferId, Function.identity()) + this.contractOffers = dsl.selectFrom(Tables.CONTRACT_OFFER).stream().collect(groupingBy( + ContractOfferRecord::getAssetId, + Collectors.toMap(ContractOfferRecord::getContractOfferId, Function.identity()) )); } @@ -50,7 +50,7 @@ public int numContractOffers(String assetId) { return contractOffers.getOrDefault(assetId, Map.of()).size(); } - public DataOfferContractOfferRecord getContractOffer(String assetId, String contractOfferId) { + public ContractOfferRecord getContractOffer(String assetId, String contractOfferId) { return contractOffers.getOrDefault(assetId, Map.of()).get(contractOfferId); } } diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/schedules/OfflineConnectorRemovalJobTest.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/schedules/OfflineConnectorRemovalJobTest.java index 25f51fd7a..feb69efc4 100644 --- a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/schedules/OfflineConnectorRemovalJobTest.java +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/services/schedules/OfflineConnectorRemovalJobTest.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.brokerserver.services.schedules; -import de.sovity.edc.ext.brokerserver.TestUtils; import de.sovity.edc.ext.brokerserver.dao.ConnectorQueries; import de.sovity.edc.ext.brokerserver.db.FlywayTestUtils; import de.sovity.edc.ext.brokerserver.db.TestDatabase; @@ -78,7 +77,7 @@ void test_offlineConnectorKiller_should_be_dead() { // assert dsl.select().from(CONNECTOR).fetch().forEach(record -> { - assertThat(record.get(CONNECTOR.CONNECTOR_ID)).isEqualTo("http://example.org"); + assertThat(record.get(CONNECTOR.ENDPOINT)).isEqualTo("https://my-connector/api/dsp"); assertThat(record.get(CONNECTOR.ONLINE_STATUS)).isEqualTo(ConnectorOnlineStatus.DEAD); }); }); @@ -96,7 +95,7 @@ void test_offlineConnectorKiller_should_not_be_dead() { // assert dsl.select().from(CONNECTOR).fetch().forEach(record -> { - assertThat(record.get(CONNECTOR.CONNECTOR_ID)).isEqualTo("http://example.org"); + assertThat(record.get(CONNECTOR.ENDPOINT)).isEqualTo("https://my-connector/api/dsp"); assertThat(record.get(CONNECTOR.ONLINE_STATUS)).isNotEqualTo(ConnectorOnlineStatus.DEAD); }); }); @@ -104,8 +103,8 @@ void test_offlineConnectorKiller_should_not_be_dead() { private static void createConnector(DSLContext dsl, int createdDaysAgo) { dsl.insertInto(CONNECTOR) - .set(CONNECTOR.CONNECTOR_ID, "http://example.org") - .set(CONNECTOR.ENDPOINT, TestUtils.MANAGEMENT_ENDPOINT) + .set(CONNECTOR.ENDPOINT, "https://my-connector/api/dsp") + .set(CONNECTOR.PARTICIPANT_ID, "my-connector") .set(CONNECTOR.ONLINE_STATUS, ConnectorOnlineStatus.OFFLINE) .set(CONNECTOR.LAST_SUCCESSFUL_REFRESH_AT, OffsetDateTime.now().minusDays(createdDaysAgo)) .set(CONNECTOR.CREATED_AT, OffsetDateTime.now().minusDays(6)) diff --git a/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/utils/JsonUtils2Test.java b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/utils/JsonUtils2Test.java new file mode 100644 index 000000000..1279a31be --- /dev/null +++ b/extensions/broker-server/src/test/java/de/sovity/edc/ext/brokerserver/utils/JsonUtils2Test.java @@ -0,0 +1,34 @@ +/* + * 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.brokerserver.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class JsonUtils2Test { + @Test + void equalityTests() { + assertTrue(JsonUtils2.isEqualJson(null, null)); + assertTrue(JsonUtils2.isEqualJson("null", "null")); + assertTrue(JsonUtils2.isEqualJson("{}", "{}")); + assertTrue(JsonUtils2.isEqualJson("{\"a\": true, \"b\": \"hello\"}", "{\"a\": true,\"b\": \"hello\"}")); + assertTrue(JsonUtils2.isEqualJson("{\"a\": true, \"b\": \"hello\"}", "{\"b\": \"hello\", \"a\": true}")); + + assertFalse(JsonUtils2.isEqualJson(null, "1")); + assertFalse(JsonUtils2.isEqualJson("1", null)); + } +} diff --git a/gradle.properties b/gradle.properties index 833a40846..69a547ff1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,13 +3,13 @@ sovityBrokerServerGroup=de.sovity.broker sovityBrokerServerVersion=0.0.1-SNAPSHOT # Sovity EDC Extensions (for common api model) -sovityEdcExtensionsVersion=4.2.0 +sovityEdcExtensionsVersion=0.0.1-SNAPSHOT sovityEdcExtensionGroup=de.sovity.edc.ext sovityEdcGroup=de.sovity.edc # Eclipse EDC edcGroup=org.eclipse.edc -edcVersion=0.0.1-20230220.patch1 +edcVersion=0.2.1 # Other Dependencies assertj=3.23.1