diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eac36b22..de3b23884 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ please see [changelog_updates.md](docs/dev/changelog_updates.md). #### Major Changes +- The `UiPolicy` model has been adjusted to support complex expressions including `AND`, `OR` and `XONE`. + - The `createPolicyDefinition` has been marked as deprecated in favor of the new `createPolicyDefinitionV2` endpoint that supports complex policies. + - Removed the recently rushed `createPolicyDefinitionUseCase` endpoint in favor of the new `createPolicyDefinitionV2` endpoint. + #### Minor Changes - Both providers and consumers can now terminate their contracts. diff --git a/docs/api/sovity-edc-api-wrapper.yaml b/docs/api/sovity-edc-api-wrapper.yaml index c466cbb97..3f9ca3a7f 100644 --- a/docs/api/sovity-edc-api-wrapper.yaml +++ b/docs/api/sovity-edc-api-wrapper.yaml @@ -121,7 +121,8 @@ paths: post: tags: - UI - description: Create a new Policy Definition + description: "[Deprecated] Create a new Policy Definition from a list of constraints.\ + \ Use createPolicyDefinitionV2 instead." operationId: createPolicyDefinition requestBody: content: @@ -135,6 +136,25 @@ paths: application/json: schema: $ref: '#/components/schemas/IdResponseDto' + deprecated: true + /wrapper/ui/v2/pages/policy-page/policy-definitions: + post: + tags: + - UI + description: Create a new Policy Definition + operationId: createPolicyDefinitionV2 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyDefinitionCreateDto' + responses: + default: + description: default response + content: + application/json: + schema: + $ref: '#/components/schemas/IdResponseDto' /wrapper/ui/pages/asset-page/assets/{assetId}: put: tags: @@ -495,24 +515,6 @@ paths: application/json: schema: $ref: '#/components/schemas/IdResponseDto' - /wrapper/use-case-api/policy-definition: - post: - tags: - - Use Case - description: Create a new Policy Definition - operationId: createPolicyDefinitionUseCase - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PolicyCreateRequest' - responses: - default: - description: default response - content: - application/json: - schema: - $ref: '#/components/schemas/IdResponseDto' /wrapper/use-case-api/kpis: get: tags: @@ -582,11 +584,11 @@ components: DataSourceType: type: string description: Supported Data Source Types by UiDataSource + default: CUSTOM enum: - HTTP_DATA - ON_REQUEST - CUSTOM - default: CUSTOM SecretValue: type: object properties: @@ -719,8 +721,8 @@ components: type: string description: Same as customJsonLdAsString but the data will be stored in the private properties. The same limitations apply. - description: Type-Safe OpenAPI generator friendly Asset Create DTO that supports - an opinionated subset of the original EDC Asset Entity. + description: Type-safe data offer metadata for creating an asset as supported + by the sovity product landscape. Contains extension points. UiDataSource: required: - type @@ -738,8 +740,8 @@ components: type: string description: For all types. Custom Data Address Properties. description: For all types. Custom Data Address Properties. - description: Data Offer Data Source Model. Supports certain Data Address types - but also leaves a backdoor for custom Data Address Properties. + description: Type-safe data source as supported by the sovity product landscape. + Contains extension points for using custom data address properties. UiDataSourceHttpData: required: - baseUrl @@ -790,10 +792,11 @@ components: \ both a request body and a content type. Only Methods POST, PUT and PATCH\ \ allow request bodies." default: false - description: Only for type HTTP_DATA + description: HTTP_DATA type Data Source. UiDataSourceHttpDataMethod: type: string description: Supported HTTP Methods by UiDataSource + default: GET enum: - GET - POST @@ -801,7 +804,6 @@ components: - PATCH - DELETE - OPTIONS - default: GET UiDataSourceOnRequest: required: - contactEmail @@ -899,7 +901,8 @@ components: - LIKE OperatorDto: type: string - description: Operator for policies + description: Type-Safe ODRL Policy Operator as supported by the sovity product + landscape enum: - EQ - NEQ @@ -924,7 +927,8 @@ components: description: Policy Definition ID policy: $ref: '#/components/schemas/UiPolicyCreateRequest' - description: Data for creating a Policy Definition + description: "[Deprecated] Create a Policy Definition. Use PolicyDefinitionCreateDto" + deprecated: true UiPolicyConstraint: required: - left @@ -939,18 +943,19 @@ components: $ref: '#/components/schemas/OperatorDto' right: $ref: '#/components/schemas/UiPolicyLiteral' - description: ODRL AtomicConstraint as supported by our UI + description: "ODRL AtomicConstraint as supported by the sovity product landscape.\ + \ For example 'a EQ b', 'c IN [d, e, f]'" UiPolicyCreateRequest: type: object properties: constraints: type: array - description: Conjunction of required expressions for the policy to evaluate - to TRUE. + description: Conjunction of required constraints + deprecated: true items: $ref: '#/components/schemas/UiPolicyConstraint' - description: Type-Safe OpenAPI generator friendly Policy Create DTO that supports - an opinionated subset of the original EDC Policy Entity. + description: "[Deprecated] Conjunction of constraints (simplified UiPolicyExpression)" + deprecated: true UiPolicyLiteral: required: - type @@ -975,6 +980,48 @@ components: - STRING - STRING_LIST - JSON + PolicyDefinitionCreateDto: + required: + - expression + - policyDefinitionId + type: object + properties: + policyDefinitionId: + type: string + description: Policy Definition ID + expression: + $ref: '#/components/schemas/UiPolicyExpression' + description: Create a Policy Definition + UiPolicyExpression: + required: + - type + type: object + properties: + type: + $ref: '#/components/schemas/UiPolicyExpressionType' + expressions: + type: array + description: "Only for types AND, OR, XONE. List of sub-expressions to be\ + \ evaluated according to the expressionType." + items: + $ref: '#/components/schemas/UiPolicyExpression' + constraint: + $ref: '#/components/schemas/UiPolicyConstraint' + description: ODRL constraint as supported by the sovity product landscape + UiPolicyExpressionType: + type: string + description: | + Ui Policy Expression types: + * `CONSTRAINT` - Expression 'a=b' + * `AND` - Conjunction of several expressions. Evaluates to true iff all child expressions are true. + * `OR` - Disjunction of several expressions. Evaluates to true iff at least one child expression is true. + * `XONE` - XONE operation. Evaluates to true iff exactly one child expression is true. + enum: + - EMPTY + - CONSTRAINT + - AND + - OR + - XONE UiAssetEditRequest: type: object properties: @@ -1087,7 +1134,8 @@ components: type: string description: Same as customJsonLdAsString but the data will be stored in the private properties. The same limitations apply. - description: Data for editing an asset. + description: Type-safe data offer metadata for editing an asset as supported + by the sovity product landscape. Contains extension points. AssetPage: required: - assets @@ -1274,7 +1322,8 @@ components: type: string description: Same as customJsonLdAsString but the data will be stored in the private properties. The same limitations apply. - description: Type-Safe Asset Metadata as needed by our UI + description: Type-safe data offer metadata as supported by the sovity product + landscape. Contains extension points. UiContractOffer: required: - contractOfferId @@ -1319,12 +1368,8 @@ components: type: string description: EDC Policy JSON-LD. This is required because the EDC requires the full policy when initiating contract negotiations. - constraints: - type: array - description: Conjunction of required expressions for the policy to evaluate - to TRUE. - items: - $ref: '#/components/schemas/UiPolicyConstraint' + expression: + $ref: '#/components/schemas/UiPolicyExpression' errors: type: array description: "When trying to reduce the policy JSON-LD to our opinionated\ @@ -1337,8 +1382,8 @@ components: \ subset of functionalities, many fields and functionalities are unsupported.\ \ Should any discrepancies occur during the mapping process, we'll collect\ \ them here." - description: Type-Safe OpenAPI generator friendly Policy DTO as needed by our - UI + description: Type-Safe OpenAPI generator friendly ODLR policy subset as endorsed + by sovity. ContractAgreementCard: required: - asset @@ -1872,69 +1917,6 @@ components: type: string description: A short reason why this contract was terminated description: Data for terminating a Contract Agreement - AtomicConstraintDto: - required: - - leftExpression - - operator - - rightExpression - type: object - properties: - leftExpression: - type: string - description: Left part of the constraint. - operator: - $ref: '#/components/schemas/OperatorDto' - rightExpression: - type: string - description: Right part of the constraint. - description: Type-Safe OpenAPI generator friendly Constraint DTO that supports - an opinionated subset of the original EDC Constraint Entity. - Expression: - type: object - properties: - expressionType: - $ref: '#/components/schemas/ExpressionType' - expressions: - type: array - description: List of policy elements that are evaluated according the expressionType. - items: - $ref: '#/components/schemas/Expression' - atomicConstraint: - $ref: '#/components/schemas/AtomicConstraintDto' - description: Represents a single atomic constraint or a multiplicity constraint. - The atomicConstraint will be evaluated if the constraintType is ATOMIC_CONSTRAINT. - ExpressionType: - type: string - description: | - Expression types: - * `ATOMIC_CONSTRAINT` - A single constraint for the policy - * `AND` - Several constraints, all of which must be respected - * `OR` - Several constraints, of which at least one must be respected - * `XOR` - Several constraints, of which exactly one must be respected - enum: - - ATOMIC_CONSTRAINT - - AND - - OR - - XOR - PermissionDto: - required: - - expression - type: object - properties: - expression: - $ref: '#/components/schemas/Expression' - description: Permission description for the policy to evaluate to TRUE. - PolicyCreateRequest: - required: - - policyDefinitionId - type: object - properties: - policyDefinitionId: - type: string - description: Policy Definition ID - permission: - $ref: '#/components/schemas/PermissionDto' - description: Policy Creation Request Supporting Multiplicity Constraints. KpiResult: required: - assetsCount diff --git a/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java b/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java index db8a7631e..759f65cf4 100644 --- a/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java +++ b/extensions/catalog-crawler/catalog-crawler-e2e-test/src/test/java/de/sovity/edc/ext/catalog/crawler/CrawlerE2eTest.java @@ -18,7 +18,7 @@ import de.sovity.edc.client.gen.model.ContractDefinitionRequest; import de.sovity.edc.client.gen.model.DataSourceType; import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiCriterion; import de.sovity.edc.client.gen.model.UiCriterionLiteral; @@ -27,7 +27,8 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyConstraint; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.ext.catalog.crawler.dao.connectors.ConnectorRef; @@ -49,6 +50,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.stream.Stream; import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.getFreePortRange; @@ -191,14 +193,22 @@ private void createPolicy() { .build()) .build(); - var policyDefinition = PolicyDefinitionCreateRequest.builder() + var expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(Stream.of(afterYesterday, beforeTomorrow) + .map(it -> UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(it) + .build()) + .toList()) + .build(); + + var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(dataOfferId) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of(afterYesterday, beforeTomorrow)) - .build()) + .expression(expression) .build(); - connectorClient.uiApi().createPolicyDefinition(policyDefinition); + connectorClient.uiApi().createPolicyDefinitionV2(policyDefinition); } private void createContractDefinition() { diff --git a/extensions/catalog-crawler/catalog-crawler/src/main/java/de/sovity/edc/ext/catalog/crawler/CrawlerExtensionContextBuilder.java b/extensions/catalog-crawler/catalog-crawler/src/main/java/de/sovity/edc/ext/catalog/crawler/CrawlerExtensionContextBuilder.java index 2437dd751..f95463a9f 100644 --- a/extensions/catalog-crawler/catalog-crawler/src/main/java/de/sovity/edc/ext/catalog/crawler/CrawlerExtensionContextBuilder.java +++ b/extensions/catalog-crawler/catalog-crawler/src/main/java/de/sovity/edc/ext/catalog/crawler/CrawlerExtensionContextBuilder.java @@ -63,7 +63,8 @@ import de.sovity.edc.ext.wrapper.api.common.mappers.dataaddress.http.HttpDataSourceMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.dataaddress.http.HttpHeaderMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.AtomicConstraintMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ConstraintExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.LiteralMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.OperatorMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; @@ -95,12 +96,12 @@ public class CrawlerExtensionContextBuilder { public static CrawlerExtensionContext buildContext( - Config config, - Monitor monitor, - TypeManager typeManager, - TypeTransformerRegistry typeTransformerRegistry, - JsonLd jsonLd, - CatalogService catalogService + Config config, + Monitor monitor, + TypeManager typeManager, + TypeTransformerRegistry typeTransformerRegistry, + JsonLd jsonLd, + CatalogService catalogService ) { // Config var crawlerConfigFactory = new CrawlerConfigFactory(config); @@ -124,9 +125,9 @@ public static CrawlerExtensionContext buildContext( var crawlerEventLogger = new CrawlerEventLogger(); var crawlerExecutionTimeLogger = new CrawlerExecutionTimeLogger(); var dataOfferMappingUtils = new FetchedCatalogMappingUtils( - policyMapper, - assetMapper, - objectMapperJsonLd + policyMapper, + assetMapper, + objectMapperJsonLd ); var contractOfferRecordUpdater = new ContractOfferRecordUpdater(); var shortDescriptionBuilder = new ShortDescriptionBuilder(); @@ -134,34 +135,34 @@ public static CrawlerExtensionContext buildContext( var contractOfferQueries = new ContractOfferQueries(); var dataOfferLimitsEnforcer = new DataOfferLimitsEnforcer(crawlerConfig, crawlerEventLogger); var dataOfferPatchBuilder = new CatalogPatchBuilder( - contractOfferQueries, - dataOfferQueries, - dataOfferRecordUpdater, - contractOfferRecordUpdater + contractOfferQueries, + dataOfferQueries, + dataOfferRecordUpdater, + contractOfferRecordUpdater ); var dataOfferPatchApplier = new CatalogPatchApplier(); var dataOfferWriter = new ConnectorUpdateCatalogWriter(dataOfferPatchBuilder, dataOfferPatchApplier); var connectorUpdateSuccessWriter = new ConnectorUpdateSuccessWriter( - crawlerEventLogger, - dataOfferWriter, - dataOfferLimitsEnforcer + crawlerEventLogger, + dataOfferWriter, + dataOfferLimitsEnforcer ); var fetchedDataOfferBuilder = new FetchedCatalogBuilder(dataOfferMappingUtils); var dspDataOfferBuilder = new DspDataOfferBuilder(jsonLd); var dspCatalogService = new DspCatalogService( - catalogService, - dspDataOfferBuilder + catalogService, + dspDataOfferBuilder ); var dataOfferFetcher = new FetchedCatalogService(dspCatalogService, fetchedDataOfferBuilder); var connectorUpdateFailureWriter = new ConnectorUpdateFailureWriter(crawlerEventLogger, monitor); var connectorUpdater = new ConnectorCrawler( - dataOfferFetcher, - connectorUpdateSuccessWriter, - connectorUpdateFailureWriter, - connectorQueries, - dslContextFactory, - monitor, - crawlerExecutionTimeLogger + dataOfferFetcher, + connectorUpdateSuccessWriter, + connectorUpdateFailureWriter, + connectorQueries, + dslContextFactory, + monitor, + crawlerExecutionTimeLogger ); var threadPoolTaskQueue = new ThreadPoolTaskQueue(); @@ -171,19 +172,19 @@ public static CrawlerExtensionContext buildContext( var connectorStatusUpdater = new ConnectorStatusUpdater(); var catalogCleaner = new CatalogCleaner(); var offlineConnectorCleaner = new OfflineConnectorCleaner( - crawlerConfig, - connectorQueries, - crawlerEventLogger, - connectorStatusUpdater, - catalogCleaner + crawlerConfig, + connectorQueries, + crawlerEventLogger, + connectorStatusUpdater, + catalogCleaner ); // Schedules List> jobs = List.of( - getOnlineConnectorRefreshCronJob(dslContextFactory, connectorQueueFiller), - getOfflineConnectorRefreshCronJob(dslContextFactory, connectorQueueFiller), - getDeadConnectorRefreshCronJob(dslContextFactory, connectorQueueFiller), - getOfflineConnectorCleanerCronJob(dslContextFactory, offlineConnectorCleaner) + getOnlineConnectorRefreshCronJob(dslContextFactory, connectorQueueFiller), + getOfflineConnectorRefreshCronJob(dslContextFactory, connectorQueueFiller), + getDeadConnectorRefreshCronJob(dslContextFactory, connectorQueueFiller), + getOfflineConnectorCleanerCronJob(dslContextFactory, offlineConnectorCleaner) ); // Startup @@ -191,68 +192,70 @@ public static CrawlerExtensionContext buildContext( var crawlerInitializer = new CrawlerInitializer(quartzScheduleInitializer); return new CrawlerExtensionContext( - crawlerInitializer, - dataSource, - dslContextFactory, - connectorUpdater, - policyMapper, - fetchedDataOfferBuilder, - dataOfferRecordUpdater + crawlerInitializer, + dataSource, + dslContextFactory, + connectorUpdater, + policyMapper, + fetchedDataOfferBuilder, + dataOfferRecordUpdater ); } @NotNull - private static PolicyMapper newPolicyMapper(TypeTransformerRegistry typeTransformerRegistry, ObjectMapper objectMapperJsonLd) { + private static PolicyMapper newPolicyMapper( + TypeTransformerRegistry typeTransformerRegistry, + ObjectMapper objectMapperJsonLd + ) { var operatorMapper = new OperatorMapper(); - var literalMapper = new LiteralMapper( - objectMapperJsonLd - ); + var literalMapper = new LiteralMapper(objectMapperJsonLd); var atomicConstraintMapper = new AtomicConstraintMapper( - literalMapper, - operatorMapper + literalMapper, + operatorMapper ); var policyValidator = new PolicyValidator(); - var constraintExtractor = new ConstraintExtractor( - policyValidator, - atomicConstraintMapper + var expressionMapper = new ExpressionMapper(atomicConstraintMapper); + var constraintExtractor = new ExpressionExtractor( + policyValidator, + expressionMapper ); return new PolicyMapper( - constraintExtractor, - atomicConstraintMapper, - typeTransformerRegistry + constraintExtractor, + expressionMapper, + typeTransformerRegistry ); } @NotNull private static AssetMapper newAssetMapper( - TypeTransformerRegistry typeTransformerRegistry, - JsonLd jsonLd + TypeTransformerRegistry typeTransformerRegistry, + JsonLd jsonLd ) { var edcPropertyUtils = new EdcPropertyUtils(); var assetJsonLdUtils = new AssetJsonLdUtils(); var assetEditRequestMapper = new AssetEditRequestMapper(); var shortDescriptionBuilder = new ShortDescriptionBuilder(); var assetJsonLdParser = new AssetJsonLdParser( - assetJsonLdUtils, - shortDescriptionBuilder, - endpoint -> false + assetJsonLdUtils, + shortDescriptionBuilder, + endpoint -> false ); var httpHeaderMapper = new HttpHeaderMapper(); var httpDataSourceMapper = new HttpDataSourceMapper(httpHeaderMapper); var dataSourceMapper = new DataSourceMapper( - edcPropertyUtils, - httpDataSourceMapper + edcPropertyUtils, + httpDataSourceMapper ); var assetJsonLdBuilder = new AssetJsonLdBuilder( - dataSourceMapper, - assetJsonLdParser, - assetEditRequestMapper + dataSourceMapper, + assetJsonLdParser, + assetEditRequestMapper ); return new AssetMapper( - typeTransformerRegistry, - assetJsonLdBuilder, - assetJsonLdParser, - jsonLd + typeTransformerRegistry, + assetJsonLdBuilder, + assetJsonLdParser, + jsonLd ); } @@ -260,33 +263,33 @@ private static AssetMapper newAssetMapper( private static CronJobRef getOfflineConnectorCleanerCronJob(DslContextFactory dslContextFactory, OfflineConnectorCleaner offlineConnectorCleaner) { return new CronJobRef<>( - CrawlerExtension.SCHEDULED_KILL_OFFLINE_CONNECTORS, - OfflineConnectorCleanerJob.class, - () -> new OfflineConnectorCleanerJob(dslContextFactory, offlineConnectorCleaner) + CrawlerExtension.SCHEDULED_KILL_OFFLINE_CONNECTORS, + OfflineConnectorCleanerJob.class, + () -> new OfflineConnectorCleanerJob(dslContextFactory, offlineConnectorCleaner) ); } @NotNull private static CronJobRef getOnlineConnectorRefreshCronJob( - DslContextFactory dslContextFactory, - ConnectorQueueFiller connectorQueueFiller + DslContextFactory dslContextFactory, + ConnectorQueueFiller connectorQueueFiller ) { return new CronJobRef<>( - CrawlerExtension.CRON_ONLINE_CONNECTOR_REFRESH, - OnlineConnectorRefreshJob.class, - () -> new OnlineConnectorRefreshJob(dslContextFactory, connectorQueueFiller) + CrawlerExtension.CRON_ONLINE_CONNECTOR_REFRESH, + OnlineConnectorRefreshJob.class, + () -> new OnlineConnectorRefreshJob(dslContextFactory, connectorQueueFiller) ); } @NotNull private static CronJobRef getOfflineConnectorRefreshCronJob( - DslContextFactory dslContextFactory, - ConnectorQueueFiller connectorQueueFiller + DslContextFactory dslContextFactory, + ConnectorQueueFiller connectorQueueFiller ) { return new CronJobRef<>( - CrawlerExtension.CRON_OFFLINE_CONNECTOR_REFRESH, - OfflineConnectorRefreshJob.class, - () -> new OfflineConnectorRefreshJob(dslContextFactory, connectorQueueFiller) + CrawlerExtension.CRON_OFFLINE_CONNECTOR_REFRESH, + OfflineConnectorRefreshJob.class, + () -> new OfflineConnectorRefreshJob(dslContextFactory, connectorQueueFiller) ); } @@ -294,9 +297,9 @@ private static CronJobRef getOfflineConnectorRefresh private static CronJobRef getDeadConnectorRefreshCronJob(DslContextFactory dslContextFactory, ConnectorQueueFiller connectorQueueFiller) { return new CronJobRef<>( - CrawlerExtension.CRON_DEAD_CONNECTOR_REFRESH, - DeadConnectorRefreshJob.class, - () -> new DeadConnectorRefreshJob(dslContextFactory, connectorQueueFiller) + CrawlerExtension.CRON_DEAD_CONNECTOR_REFRESH, + DeadConnectorRefreshJob.class, + () -> new DeadConnectorRefreshJob(dslContextFactory, connectorQueueFiller) ); } diff --git a/extensions/wrapper/clients/java-client/README.md b/extensions/wrapper/clients/java-client/README.md index 9eb0cd231..1c419272a 100644 --- a/extensions/wrapper/clients/java-client/README.md +++ b/extensions/wrapper/clients/java-client/README.md @@ -49,14 +49,14 @@ import de.sovity.edc.client.gen.model.KpiResult; */ public class WrapperClientExample { - public static final String CONNECTOR_ENDPOINT = "http://localhost:11002/api/management/v2"; - public static final String CONNECTOR_API_KEY = "..."; + public static final String MANAGEMENT_API_URL = "http://localhost:11002/api/management"; + public static final String MANAGEMENT_API_KEY = "..."; public static void main(String[] args) { // Configure Client EdcClient client = EdcClient.builder() - .managementApiUrl(CONNECTOR_ENDPOINT) - .managementApiKey(CONNECTOR_API_KEY) + .managementApiUrl(MANAGEMENT_API_URL) + .managementApiKey(MANAGEMENT_API_KEY) .build(); // EDC API Wrapper APIs are now available for use @@ -80,15 +80,15 @@ import de.sovity.edc.client.oauth2.SovityKeycloakUrl; */ public class WrapperClientExample { - public static final String CONNECTOR_ENDPOINT = - "https://{{your-connector}}.prod-sovity.azure.sovity.io/control/data"; + public static final String MANAGEMENT_API_URL = + "https://{{your-connector}}.prod-sovity.azure.sovity.io/control/api/management"; public static final String CLIENT_ID = "{{your-connector}}-app"; public static final String CLIENT_SECRET = "..."; public static void main(String[] args) { // Configure Client EdcClient client = EdcClient.builder() - .managementApiUrl(CONNECTOR_ENDPOINT) + .managementApiUrl(MANAGEMENT_API_URL) .oauth2ClientCredentials(OAuth2ClientCredentials.builder() .tokenUrl(SovityKeycloakUrl.PRODUCTION) .clientId(CLIENT_ID) @@ -107,50 +107,66 @@ public class WrapperClientExample { Below are the examples of various tasks and the corresponding methods to be used from the Java-client. -| Task | Java-Client method | -|----------------------------------------------------------|-----------------------------------------------------------------------| -| Create Policy - uiAPI | `EdcClient.uiApi().createPolicyDefinition(policyDefinition)` | -| Create Policy - useCaseApi (allows AND/OR/XOR operators) | `EdcClient.useCaseApi().createPolicyDefinitionUseCase(createRequest)` | -| Create asset (Asset Creation after activate) | `EdcClient.uiApi().createAsset(uiAssetRequest)` | -| Create contract definition | `EdcClient.uiApi().createContractDefinition(contractDefinition)` | -| Create Offer on consumer dashboard (Catalog Browser) | `EdcClient.uiApi().getCatalogPageDataOffers(PROTOCOL_ENDPOINT)` | -| Accept contract (Contract Negotiation) | `EdcClient.uiApi().initiateContractNegotiation(negotiationRequest)` | -| Transfer Data (Initiate Transfer) | `EdcClient.uiApi().initiateTransfer(negotiation)` | +| Task | Java-Client method | +|------------------------------------------------------|---------------------------------------------------------------------| +| Create Policy | `EdcClient.uiApi().createPolicyDefinitionV2(policyDefinition)` | +| Create asset (Asset Creation after activate) | `EdcClient.uiApi().createAsset(uiAssetRequest)` | +| Create contract definition | `EdcClient.uiApi().createContractDefinition(contractDefinition)` | +| Create Offer on consumer dashboard (Catalog Browser) | `EdcClient.uiApi().getCatalogPageDataOffers(PROTOCOL_ENDPOINT)` | +| Accept contract (Contract Negotiation) | `EdcClient.uiApi().initiateContractNegotiation(negotiationRequest)` | +| Transfer Data (Initiate Transfer) | `EdcClient.uiApi().initiateTransfer(negotiation)` | These methods facilitate various operations such as creating policies, assets, contract definitions, browsing offers, accepting contracts, and initiating data transfers. -### Example Creating a Catena-Policy using operators (AND/OR/XOR) +### Example Creating a Catena-Policy using operators (AND/OR/XONE) The following example demonstrates how to create a Catena-Policy with linked conditions using the Java-client. ```java -var policyId = UUID.randomUUID().toString(); -var membershipElement = buildAtomicElement("Membership", OperatorDto.EQ, "active"); -var purposeElement = buildAtomicElement("PURPOSE", OperatorDto.EQ, "ID 3.1 Trace"); -var andElement = new Expression() - .expressionType(ExpressionTypeDto.AND) - .expressions(List.of(membershipElement, purposeElement)); -var permissionDto = new PermissionDto(andElement); -var createRequest = new PolicyCreateRequest(policyId, permissionDto); - -var response = client.useCaseApi().createPolicyDefinitionUseCase(createRequest); - -private Expression buildAtomicElement( +public String createCatenaXPolicy() { + var policyId = UUID.randomUUID().toString(); + + var expression = buildAnd( + buildConstraint("Membership", OperatorDto.EQ, "active"), + buildConstraint("PURPOSE", OperatorDto.EQ, "ID 3.1 Trace") + ); + + var policyCreateRequest = PolicyDefinitionCreateDto.builder() + .policyDefinitionId(policyId) + .expression(expression) + .build(); + + client.uiApi().createPolicyDefinition(policyCreateRequest); + + return policyId; +} + +private UiPolicyExpression buildAnd(UiPolicyExpression... expressions) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(Arrays.asList(expressions)) + .build(); +} + +private UiPolicyExpression buildConstraint( String left, OperatorDto operator, - String right) { - var atomicConstraint = new AtomicConstraintDto() - .leftExpression(left) - .operator(operator) - .rightExpression(right); - return new Expression() - .expressionType(ExpressionTypeDto.ATOMIC_CONSTRAINT) - .atomicConstraint(atomicConstraint); + String right +) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() + .left(left) + .operator(operator) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(right) + .build()) + .build()) + .build(); } ``` -The complete example can be seen in [this test](https://github.com/sovity/edc-ce/blob/main/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java). - ## License Apache License 2.0 - see [LICENSE](../../../../LICENSE) diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java index dd09224c1..81013da0c 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.ui; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import de.sovity.edc.ext.wrapper.api.common.model.UiAssetCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.UiAssetEditRequest; @@ -30,6 +29,8 @@ import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; import de.sovity.edc.ext.wrapper.api.ui.model.InitiateCustomTransferRequest; import de.sovity.edc.ext.wrapper.api.ui.model.InitiateTransferRequest; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateDto; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateRequest; import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionPage; import de.sovity.edc.ext.wrapper.api.ui.model.TransferHistoryPage; import de.sovity.edc.ext.wrapper.api.ui.model.UiContractNegotiation; @@ -97,9 +98,18 @@ interface UiResource { @Path("pages/policy-page/policy-definitions") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - @Operation(description = "Create a new Policy Definition") + @Deprecated + @Operation(description = "[Deprecated] Create a new Policy Definition from a list of constraints. " + + "Use createPolicyDefinitionV2 instead.", deprecated = true) IdResponseDto createPolicyDefinition(PolicyDefinitionCreateRequest policyDefinitionDtoDto); + @POST + @Path("v2/pages/policy-page/policy-definitions") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Operation(description = "Create a new Policy Definition") + IdResponseDto createPolicyDefinitionV2(PolicyDefinitionCreateDto policyDefinitionCreateDto); + @DELETE @Path("pages/policy-page/policy-definitions/{policyId}") @Produces(MediaType.APPLICATION_JSON) diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PolicyDefinitionCreateRequest.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionCreateDto.java similarity index 70% rename from extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PolicyDefinitionCreateRequest.java rename to extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionCreateDto.java index 70392fff6..8bc4d076d 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PolicyDefinitionCreateRequest.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionCreateDto.java @@ -12,9 +12,10 @@ * */ -package de.sovity.edc.ext.wrapper.api.common.model; +package de.sovity.edc.ext.wrapper.api.ui.model; import com.fasterxml.jackson.annotation.JsonInclude; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; @@ -26,12 +27,12 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Data for creating a Policy Definition") -public class PolicyDefinitionCreateRequest { +@Schema(description = "Create a Policy Definition") +public class PolicyDefinitionCreateDto { @Schema(description = "Policy Definition ID", requiredMode = Schema.RequiredMode.REQUIRED) private String policyDefinitionId; - @Schema(description = "Policy Contents", requiredMode = Schema.RequiredMode.REQUIRED) - private UiPolicyCreateRequest policy; + @Schema(description = "Policy Expression", requiredMode = Schema.RequiredMode.REQUIRED) + private UiPolicyExpression expression; } diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/PolicyCreateRequest.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionCreateRequest.java similarity index 62% rename from extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/PolicyCreateRequest.java rename to extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionCreateRequest.java index da6b75996..911d90db6 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/model/PolicyCreateRequest.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionCreateRequest.java @@ -12,10 +12,10 @@ * */ -package de.sovity.edc.ext.wrapper.api.usecase.model; +package de.sovity.edc.ext.wrapper.api.ui.model; import com.fasterxml.jackson.annotation.JsonInclude; -import de.sovity.edc.ext.wrapper.api.common.model.PermissionDto; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyCreateRequest; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; @@ -27,13 +27,14 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Policy Creation Request Supporting Multiplicity Constraints.") -public class PolicyCreateRequest { - +@Deprecated +@Schema(description = "[Deprecated] Create a Policy Definition. Use PolicyDefinitionCreateDto", deprecated = true) +public class PolicyDefinitionCreateRequest { @Schema(description = "Policy Definition ID", requiredMode = Schema.RequiredMode.REQUIRED) private String policyDefinitionId; - @Schema(description = "Permission description for the policy to evaluate to TRUE.") - private PermissionDto permission; - + @Schema(description = "[Deprecated] Conjunction of constraints (simplified UiPolicyExpression)", + requiredMode = Schema.RequiredMode.REQUIRED, deprecated = true) + private UiPolicyCreateRequest policy; } + diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PolicyDefinitionDto.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionDto.java similarity index 90% rename from extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PolicyDefinitionDto.java rename to extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionDto.java index a0e917f2d..3c69aca84 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PolicyDefinitionDto.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionDto.java @@ -12,9 +12,10 @@ * */ -package de.sovity.edc.ext.wrapper.api.common.model; +package de.sovity.edc.ext.wrapper.api.ui.model; import com.fasterxml.jackson.annotation.JsonInclude; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionPage.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionPage.java index 285e338b9..9b77b3c36 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionPage.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/ui/model/PolicyDefinitionPage.java @@ -15,7 +15,6 @@ package de.sovity.edc.ext.wrapper.api.ui.model; import com.fasterxml.jackson.annotation.JsonInclude; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionDto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java index 51408dfce..b959ac0ec 100644 --- a/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java +++ b/extensions/wrapper/wrapper-api/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResource.java @@ -14,11 +14,9 @@ package de.sovity.edc.ext.wrapper.api.usecase; -import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; import de.sovity.edc.ext.wrapper.api.ui.model.UiDataOffer; import de.sovity.edc.ext.wrapper.api.usecase.model.CatalogQuery; import de.sovity.edc.ext.wrapper.api.usecase.model.KpiResult; -import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -61,11 +59,4 @@ List queryCatalog( @NotNull CatalogQuery catalogQuery ); - - @POST - @Path("policy-definition") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation(description = "Create a new Policy Definition") - IdResponseDto createPolicyDefinitionUseCase(PolicyCreateRequest policyCreateRequest); } diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AssetDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AssetDto.java deleted file mode 100644 index 32b28eafb..000000000 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AssetDto.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.common.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.RequiredArgsConstructor; - -import java.time.OffsetDateTime; -import java.util.Map; - -@Data -@AllArgsConstructor -@RequiredArgsConstructor -@Builder(toBuilder = true) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Asset Details") -public class AssetDto { - @Schema(description = "ID of asset", requiredMode = Schema.RequiredMode.REQUIRED) - private String assetId; - - @Schema(description = "Creation Date of asset", requiredMode = Schema.RequiredMode.REQUIRED) - private OffsetDateTime createdAt; - - @Schema(description = "Asset properties", requiredMode = Schema.RequiredMode.REQUIRED) - private Map properties; -} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.java deleted file mode 100644 index 8419b712a..000000000 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/AtomicConstraintDto.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 - init - * - */ - -package de.sovity.edc.ext.wrapper.api.common.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.RequiredArgsConstructor; - - -@Data -@AllArgsConstructor -@RequiredArgsConstructor -@Builder(toBuilder = true) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = - "Type-Safe OpenAPI generator friendly Constraint DTO that supports an opinionated" - + " subset of the original EDC Constraint Entity.") -public class AtomicConstraintDto { - - @Schema(description = "Left part of the constraint.", - requiredMode = Schema.RequiredMode.REQUIRED) - private String leftExpression; - @Schema(description = "Operator to connect both parts of the constraint.", - requiredMode = Schema.RequiredMode.REQUIRED) - private OperatorDto operator; - @Schema(description = "Right part of the constraint.", - requiredMode = Schema.RequiredMode.REQUIRED) - private String rightExpression; -} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/Expression.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/Expression.java deleted file mode 100644 index 9fc30e0de..000000000 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/Expression.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.common.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.RequiredArgsConstructor; - -import java.util.List; - -@Data -@AllArgsConstructor -@RequiredArgsConstructor -@Builder(toBuilder = true) -@JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = - "Represents a single atomic constraint or a multiplicity constraint. The atomicConstraint" + - " will be evaluated if the constraintType is ATOMIC_CONSTRAINT.") -public class Expression { - - @Schema(description = "Either ATOMIC_CONSTRAINT or one of the multiplicity constraint types.") - private ExpressionType expressionType; - - @Schema(description = - "List of policy elements that are evaluated according the expressionType.") - private List expressions; - - @Schema(description = - "A single atomic constraint. Will be evaluated if the expressionType is set to " + - "ATOMIC_CONSTRAINT.") - private AtomicConstraintDto atomicConstraint; -} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionType.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionType.java deleted file mode 100644 index 33e21f83f..000000000 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/ExpressionType.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.sovity.edc.ext.wrapper.api.common.model; - -import io.swagger.v3.oas.annotations.media.Schema; - -/** - * Sum type enum. - */ -@Schema(description = """ - Expression types: - * `ATOMIC_CONSTRAINT` - A single constraint for the policy - * `AND` - Several constraints, all of which must be respected - * `OR` - Several constraints, of which at least one must be respected - * `XOR` - Several constraints, of which exactly one must be respected - """, enumAsRef = true) -public enum ExpressionType { - ATOMIC_CONSTRAINT, AND, OR, XOR -} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java index 0e31e0ff7..7eda3a545 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/OperatorDto.java @@ -8,7 +8,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * sovity GmbH - init + * Fraunhofer ISST - initial implementation + * sovity GmbH - documentation changes * */ @@ -17,11 +18,9 @@ import io.swagger.v3.oas.annotations.media.Schema; /** - * Equivalent of ODRL Policy Operator for our API Wrapper API. - * * @author tim.dahlmanns@isst.fraunhofer.de */ -@Schema(description = "Operator for policies", enumAsRef = true) +@Schema(description = "Type-Safe ODRL Policy Operator as supported by the sovity product landscape", enumAsRef = true) public enum OperatorDto { EQ, NEQ, diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java deleted file mode 100644 index a783f1348..000000000 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/PermissionDto.java +++ /dev/null @@ -1,36 +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 - init - * - */ - -package de.sovity.edc.ext.wrapper.api.common.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.RequiredArgsConstructor; - - -@Data -@AllArgsConstructor -@RequiredArgsConstructor -@Builder(toBuilder = true) -@JsonInclude(JsonInclude.Include.NON_NULL) -public class PermissionDto { - - @Schema(description = "Possible constraints for the permission", - requiredMode = RequiredMode.REQUIRED) - private Expression expression; -} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAsset.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAsset.java index bf28fc1a9..0ed4590b9 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAsset.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAsset.java @@ -29,7 +29,7 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Type-Safe Asset Metadata as needed by our UI") +@Schema(description = "Type-safe data offer metadata as supported by the sovity product landscape. Contains extension points.") public class UiAsset { @Schema(description = "'Live' vs 'On Request'", requiredMode = Schema.RequiredMode.REQUIRED) private DataSourceAvailability dataSourceAvailability; @@ -170,22 +170,22 @@ public class UiAsset { private String assetJsonLd; @Schema(description = "Contains serialized custom properties in the JSON format.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String customJsonAsString; @Schema(description = "Contains serialized custom properties in the JSON LD format. " + - "Contrary to the customJsonAsString field, this string must represent a JSON LD object " + - "and will be affected by JSON LD compaction and expansion. " + - "Due to a technical limitation, the properties can't be booleans.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + "Contrary to the customJsonAsString field, this string must represent a JSON LD object " + + "and will be affected by JSON LD compaction and expansion. " + + "Due to a technical limitation, the properties can't be booleans.", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String customJsonLdAsString; @Schema(description = "Same as customJsonAsString but the data will be stored in the private properties.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String privateCustomJsonAsString; @Schema(description = "Same as customJsonLdAsString but the data will be stored in the private properties. " + - "The same limitations apply.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + "The same limitations apply.", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String privateCustomJsonLdAsString; } diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetCreateRequest.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetCreateRequest.java index c49b7af1f..8ee241616 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetCreateRequest.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetCreateRequest.java @@ -29,7 +29,7 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Type-Safe OpenAPI generator friendly Asset Create DTO that supports an opinionated subset of the original EDC Asset Entity.") +@Schema(description = "Type-safe data offer metadata for creating an asset as supported by the sovity product landscape. Contains extension points.") public class UiAssetCreateRequest { @Schema(description = "Data Source", requiredMode = Schema.RequiredMode.REQUIRED) private UiDataSource dataSource; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetEditRequest.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetEditRequest.java index 87257c694..31fd15d74 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetEditRequest.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiAssetEditRequest.java @@ -29,7 +29,7 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Data for editing an asset.") +@Schema(description = "Type-safe data offer metadata for editing an asset as supported by the sovity product landscape. Contains extension points.") public class UiAssetEditRequest { @Schema(description = "Data Source", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private UiDataSource dataSourceOverrideOrNull; @@ -107,22 +107,22 @@ public class UiAssetEditRequest { private LocalDate temporalCoverageToInclusive; @Schema(description = "Contains serialized custom properties in the JSON format.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String customJsonAsString; @Schema(description = "Contains serialized custom properties in the JSON LD format. " + - "Contrary to the customJsonAsString field, this string must represent a JSON LD object " + - "and will be affected by JSON LD compaction and expansion. " + - "Due to a technical limitation, the properties can't be booleans.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + "Contrary to the customJsonAsString field, this string must represent a JSON LD object " + + "and will be affected by JSON LD compaction and expansion. " + + "Due to a technical limitation, the properties can't be booleans.", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String customJsonLdAsString; @Schema(description = "Same as customJsonAsString but the data will be stored in the private properties.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String privateCustomJsonAsString; @Schema(description = "Same as customJsonLdAsString but the data will be stored in the private properties. " + - "The same limitations apply.", - requiredMode = Schema.RequiredMode.NOT_REQUIRED) + "The same limitations apply.", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String privateCustomJsonLdAsString; } diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSource.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSource.java index bb57db00c..8feef9ae8 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSource.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSource.java @@ -28,7 +28,7 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Data Offer Data Source Model. Supports certain Data Address types but also leaves a backdoor for custom Data Address Properties.") +@Schema(description = "Type-safe data source as supported by the sovity product landscape. Contains extension points for using custom data address properties.") public class UiDataSource { @Schema( description = "Data Address Type.", diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpData.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpData.java index 381dcdb73..c995248d5 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpData.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpData.java @@ -28,6 +28,7 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "HTTP_DATA type Data Source.") public class UiDataSourceHttpData { @Schema( description = "HTTP Request Method", diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpDataMethod.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpDataMethod.java index 0244a47ab..013848562 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpDataMethod.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiDataSourceHttpDataMethod.java @@ -11,7 +11,7 @@ * sovity GmbH - initial API and implementation * */ - + package de.sovity.edc.ext.wrapper.api.common.model; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicy.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicy.java index 4118c7434..2b6317edc 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicy.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicy.java @@ -29,17 +29,17 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Type-Safe OpenAPI generator friendly Policy DTO as needed by our UI") +@Schema(description = "Type-Safe OpenAPI generator friendly ODLR policy subset as endorsed by sovity.") public class UiPolicy { @Schema(description = "EDC Policy JSON-LD. This is required because the EDC requires the " + - "full policy when initiating contract negotiations.", requiredMode = RequiredMode.REQUIRED) + "full policy when initiating contract negotiations.", requiredMode = RequiredMode.REQUIRED) private String policyJsonLd; - @Schema(description = "Conjunction of required expressions for the policy to evaluate to TRUE.") - private List constraints; + @Schema(description = "Policy expression") + private UiPolicyExpression expression; @Schema(description = "When trying to reduce the policy JSON-LD to our opinionated subset of functionalities, " + - "many fields and functionalities are unsupported. Should any discrepancies occur during " + - "the mapping process, we'll collect them here.", requiredMode = RequiredMode.REQUIRED) + "many fields and functionalities are unsupported. Should any discrepancies occur during " + + "the mapping process, we'll collect them here.", requiredMode = RequiredMode.REQUIRED) private List errors; } diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyConstraint.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyConstraint.java index 1df6cd1dc..58fc11f22 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyConstraint.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyConstraint.java @@ -27,7 +27,7 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "ODRL AtomicConstraint as supported by our UI") +@Schema(description = "ODRL AtomicConstraint as supported by the sovity product landscape. For example 'a EQ b', 'c IN [d, e, f]'") public class UiPolicyConstraint { @Schema(description = "Left side of the expression.", requiredMode = RequiredMode.REQUIRED) private String left; diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java index b1f18465a..e27806608 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyCreateRequest.java @@ -28,9 +28,10 @@ @RequiredArgsConstructor @Builder(toBuilder = true) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "Type-Safe OpenAPI generator friendly Policy Create DTO that supports an opinionated" - + " subset of the original EDC Policy Entity.") +@Deprecated +@Schema(description = "[Deprecated] Conjunction of constraints (simplified UiPolicyExpression)", + deprecated = true) public class UiPolicyCreateRequest { - @Schema(description = "Conjunction of required expressions for the policy to evaluate to TRUE.") + @Schema(description = "Conjunction of required constraints", deprecated = true) private List constraints; } diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpression.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpression.java new file mode 100644 index 000000000..4d30e337d --- /dev/null +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpression.java @@ -0,0 +1,66 @@ +package de.sovity.edc.ext.wrapper.api.common.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.util.List; + + +@Data +@AllArgsConstructor +@RequiredArgsConstructor +@Builder(toBuilder = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "ODRL constraint as supported by the sovity product landscape") +public class UiPolicyExpression { + + @Schema(description = "Expression type", requiredMode = Schema.RequiredMode.REQUIRED) + private UiPolicyExpressionType type; + + @Schema(description = "Only for types AND, OR, XONE. List of sub-expressions " + + "to be evaluated according to the expressionType.", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private List expressions; + + @Schema(description = "Only for type CONSTRAINT. A single constraint.", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private UiPolicyConstraint constraint; + + public static UiPolicyExpression empty() { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.EMPTY) + .build(); + } + + public static UiPolicyExpression constraint(UiPolicyConstraint constraint) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(constraint) + .build(); + } + + public static UiPolicyExpression and(List expressions) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(expressions) + .build(); + } + + public static UiPolicyExpression or(List expressions) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.OR) + .expressions(expressions) + .build(); + } + + public static UiPolicyExpression xone(List expressions) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.XONE) + .expressions(expressions) + .build(); + } +} diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpressionType.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpressionType.java new file mode 100644 index 000000000..2267a4abc --- /dev/null +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyExpressionType.java @@ -0,0 +1,20 @@ +package de.sovity.edc.ext.wrapper.api.common.model; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = """ + Ui Policy Expression types: + * `CONSTRAINT` - Expression 'a=b' + * `AND` - Conjunction of several expressions. Evaluates to true iff all child expressions are true. + * `OR` - Disjunction of several expressions. Evaluates to true iff at least one child expression is true. + * `XONE` - XONE operation. Evaluates to true iff exactly one child expression is true. + """, enumAsRef = true) +public enum UiPolicyExpressionType { + EMPTY, + CONSTRAINT, + AND, + OR, + XONE +} + + diff --git a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyLiteral.java b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyLiteral.java index 7cb251703..08176e9ae 100644 --- a/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyLiteral.java +++ b/extensions/wrapper/wrapper-common-api/src/main/java/de/sovity/edc/ext/wrapper/api/common/model/UiPolicyLiteral.java @@ -45,22 +45,22 @@ public class UiPolicyLiteral { public static UiPolicyLiteral ofString(String string) { return UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(string) - .build(); + .type(UiPolicyLiteralType.STRING) + .value(string) + .build(); } public static UiPolicyLiteral ofJson(String jsonString) { return UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.JSON) - .value(jsonString) - .build(); + .type(UiPolicyLiteralType.JSON) + .value(jsonString) + .build(); } public static UiPolicyLiteral ofStringList(Collection strings) { return UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING_LIST) - .valueList(new ArrayList<>(strings)) - .build(); + .type(UiPolicyLiteralType.STRING_LIST) + .valueList(new ArrayList<>(strings)) + .build(); } } diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java index 03c45f5af..4ac252075 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/AssetMapper.java @@ -11,7 +11,7 @@ * sovity GmbH - initial API and implementation * */ - + package de.sovity.edc.ext.wrapper.api.common.mappers; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.AssetJsonLdBuilder; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/LegacyPolicyMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/LegacyPolicyMapper.java new file mode 100644 index 000000000..22d95bf34 --- /dev/null +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/LegacyPolicyMapper.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.common.mappers; + +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.UiPolicyExpression; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@RequiredArgsConstructor +public class LegacyPolicyMapper { + /** + * Builds a {@link UiPolicyExpression} from the legacy {@link UiPolicyCreateRequest}. + * + * @param createRequest {@link UiPolicyCreateRequest} + * @return {@link UiPolicyExpression} + */ + @Deprecated + public UiPolicyExpression buildUiPolicyExpression(UiPolicyCreateRequest createRequest) { + if (createRequest == null) { + return UiPolicyExpression.empty(); + } + + return buildUiPolicyExpression(createRequest.getConstraints()); + } + + private UiPolicyExpression buildUiPolicyExpression(List expressions) { + UiPolicyExpression expression; + if (expressions == null || expressions.isEmpty()) { + expression = UiPolicyExpression.empty(); + } else if (expressions.size() == 1) { + expression = UiPolicyExpression.constraint(expressions.get(0)); + } else { + expression = UiPolicyExpression.and( + expressions.stream().map(UiPolicyExpression::constraint).toList() + ); + } + return expression; + } +} diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java index 168dc5666..3b69efa56 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java @@ -15,37 +15,27 @@ package de.sovity.edc.ext.wrapper.api.common.mappers; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.utils.FailedMappingException; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.AtomicConstraintMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ConstraintExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; -import de.sovity.edc.ext.wrapper.api.common.model.Expression; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicy; -import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyCreateRequest; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; import de.sovity.edc.utils.JsonUtils; -import de.sovity.edc.utils.jsonld.vocab.Prop; import jakarta.json.JsonObject; import lombok.RequiredArgsConstructor; import org.eclipse.edc.policy.model.Action; -import org.eclipse.edc.policy.model.AndConstraint; -import org.eclipse.edc.policy.model.Constraint; -import org.eclipse.edc.policy.model.OrConstraint; import org.eclipse.edc.policy.model.Permission; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.policy.model.PolicyType; -import org.eclipse.edc.policy.model.XoneConstraint; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; import static de.sovity.edc.utils.JsonUtils.toJson; @RequiredArgsConstructor public class PolicyMapper { - private final ConstraintExtractor constraintExtractor; - private final AtomicConstraintMapper atomicConstraintMapper; + private final ExpressionExtractor expressionExtractor; + private final ExpressionMapper expressionMapper; private final TypeTransformerRegistry typeTransformerRegistry; /** @@ -59,13 +49,13 @@ public class PolicyMapper { public UiPolicy buildUiPolicy(Policy policy) { MappingErrors errors = MappingErrors.root(); - var constraints = constraintExtractor.getPermissionConstraints(policy, errors); + var expression = expressionExtractor.getPermissionExpression(policy, errors); return UiPolicy.builder() - .policyJsonLd(toJson(buildPolicyJsonLd(policy))) - .constraints(constraints) - .errors(errors.getErrors()) - .build(); + .policyJsonLd(toJson(buildPolicyJsonLd(policy))) + .expression(expression) + .errors(errors.getErrors()) + .build(); } /** @@ -73,62 +63,23 @@ public UiPolicy buildUiPolicy(Policy policy) { *

* This operation is lossless. * - * @param policyCreateDto policy + * @param expression policy * @return ODRL policy */ - public Policy buildPolicy(UiPolicyCreateRequest policyCreateDto) { - var constraints = new ArrayList(atomicConstraintMapper.buildAtomicConstraints( - policyCreateDto.getConstraints())); + public Policy buildPolicy(UiPolicyExpression expression) { + var constraints = expressionMapper.buildConstraint(expression); var action = Action.Builder.newInstance().type(PolicyValidator.ALLOWED_ACTION).build(); var permission = Permission.Builder.newInstance() - .action(action) - .constraints(constraints) - .build(); - - return Policy.Builder.newInstance() - .type(PolicyType.SET) - .permission(permission) - .build(); - } - - public Policy buildPolicy(List constraintElements) { - var constraints = buildConstraints(constraintElements); - var action = Action.Builder.newInstance().type(Prop.Odrl.USE).build(); - var permission = Permission.Builder.newInstance() - .action(action) - .constraints(constraints) - .build(); + .action(action) + .constraints(constraints.stream().toList()) + .build(); return Policy.Builder.newInstance() - .type(PolicyType.SET) - .permission(permission) - .build(); - } - - @NotNull - private List buildConstraints(List expressions) { - return expressions.stream() - .map(this::buildConstraint) - .toList(); - } - - private Constraint buildConstraint(Expression expression) { - var subExpressions = expression.getExpressions(); - return switch (expression.getExpressionType()) { - case ATOMIC_CONSTRAINT -> - atomicConstraintMapper.buildAtomicConstraint(expression.getAtomicConstraint()); - case AND -> AndConstraint.Builder.newInstance() - .constraints(buildConstraints(subExpressions)) - .build(); - case OR -> OrConstraint.Builder.newInstance() - .constraints(buildConstraints(subExpressions)) - .build(); - case XOR -> XoneConstraint.Builder.newInstance() - .constraints(buildConstraints(subExpressions)) - .build(); - }; + .type(PolicyType.SET) + .permission(permission) + .build(); } /** @@ -141,7 +92,7 @@ private Constraint buildConstraint(Expression expression) { */ public Policy buildPolicy(JsonObject policyJsonLd) { return typeTransformerRegistry.transform(policyJsonLd, Policy.class) - .orElseThrow(FailedMappingException::ofFailure); + .orElseThrow(FailedMappingException::ofFailure); } /** @@ -166,6 +117,6 @@ public Policy buildPolicy(String policyJsonLd) { */ public JsonObject buildPolicyJsonLd(Policy policy) { return typeTransformerRegistry.transform(policy, JsonObject.class) - .orElseThrow(FailedMappingException::ofFailure); + .orElseThrow(FailedMappingException::ofFailure); } } diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java index a182b75a0..7e22d9f59 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/asset/utils/JsonBuilderUtils.java @@ -52,8 +52,8 @@ public static void addNonNull(JsonObjectBuilder builder, String key, LocalDate v * Adds non-null non-blank trimmed items as a JSON Array * * @param builder target object - * @param key key - * @param values list of values + * @param key key + * @param values list of values */ public static void addNotBlankStringArray(JsonObjectBuilder builder, String key, List values) { var filteredItems = (values == null ? Stream.of() : values.stream()) diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/dataaddress/http/HttpHeaderMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/dataaddress/http/HttpHeaderMapper.java index b679687df..cde71667d 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/dataaddress/http/HttpHeaderMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/dataaddress/http/HttpHeaderMapper.java @@ -11,7 +11,7 @@ * sovity GmbH - initial API and implementation * */ - + package de.sovity.edc.ext.wrapper.api.common.mappers.dataaddress.http; import de.sovity.edc.utils.jsonld.vocab.Prop; diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java index 7586a2081..2a4c45a2b 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapper.java @@ -14,7 +14,6 @@ package de.sovity.edc.ext.wrapper.api.common.mappers.policy; -import de.sovity.edc.ext.wrapper.api.common.model.AtomicConstraintDto; import de.sovity.edc.ext.wrapper.api.common.model.OperatorDto; import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; import lombok.NonNull; @@ -22,7 +21,6 @@ import org.eclipse.edc.policy.model.AtomicConstraint; import org.eclipse.edc.policy.model.LiteralExpression; -import java.util.List; import java.util.Optional; @RequiredArgsConstructor @@ -31,53 +29,56 @@ public class AtomicConstraintMapper { private final OperatorMapper operatorMapper; /** - * Create ODRL {@link AtomicConstraint}s from {@link UiPolicyConstraint}s + * Create ODRL {@link AtomicConstraint} from {@link UiPolicyConstraint} *

* This operation is lossless. * - * @param constraints ui constraints - * @return ODRL constraints + * @param constraint ui constraint + * @return ODRL constraint */ - public List buildAtomicConstraints(List constraints) { - if (constraints == null) { - return List.of(); - } + public AtomicConstraint buildAtomicConstraint(UiPolicyConstraint constraint) { + var left = constraint.getLeft(); + var operator = operatorMapper.getOperator(constraint.getOperator()); + var right = literalMapper.getUiLiteralValue(constraint.getRight()); - return constraints.stream() - .map(this::buildAtomicConstraint) - .toList(); + return AtomicConstraint.Builder.newInstance() + .leftExpression(new LiteralExpression(left)) + .operator(operator) + .rightExpression(new LiteralExpression(right)) + .build(); } + /** * Create {@link UiPolicyConstraint} from ODRL {@link AtomicConstraint} *

* This operation is lossy. * * @param atomicConstraint atomic contraints - * @param errors errors + * @param errors errors * @return ui policy constraint */ public Optional buildUiConstraint( - @NonNull AtomicConstraint atomicConstraint, - MappingErrors errors + @NonNull AtomicConstraint atomicConstraint, + MappingErrors errors ) { var leftValue = literalMapper.getExpressionString(atomicConstraint.getLeftExpression(), - errors.forChildObject("leftExpression")); + errors.forChildObject("leftExpression")); var operator = getOperator(atomicConstraint, errors); var rightValue = literalMapper.getExpressionValue(atomicConstraint.getRightExpression(), - errors.forChildObject("rightExpression")); + errors.forChildObject("rightExpression")); if (leftValue.isEmpty() || rightValue.isEmpty() || operator.isEmpty()) { return Optional.empty(); } UiPolicyConstraint result = UiPolicyConstraint.builder() - .left(leftValue.get()) - .operator(operator.get()) - .right(rightValue.get()) - .build(); + .left(leftValue.get()) + .operator(operator.get()) + .right(rightValue.get()) + .build(); return Optional.of(result); } @@ -92,28 +93,4 @@ private Optional getOperator(AtomicConstraint atomicConstraint, Map return Optional.of(operatorMapper.getOperatorDto(operator)); } - - private AtomicConstraint buildAtomicConstraint(UiPolicyConstraint constraint) { - var left = constraint.getLeft(); - var operator = operatorMapper.getOperator(constraint.getOperator()); - var right = literalMapper.getUiLiteralValue(constraint.getRight()); - - return AtomicConstraint.Builder.newInstance() - .leftExpression(new LiteralExpression(left)) - .operator(operator) - .rightExpression(new LiteralExpression(right)) - .build(); - } - - public AtomicConstraint buildAtomicConstraint(AtomicConstraintDto atomicConstraint) { - var left = atomicConstraint.getLeftExpression(); - var operator = operatorMapper.getOperator(atomicConstraint.getOperator()); - var right = atomicConstraint.getRightExpression(); - - return AtomicConstraint.Builder.newInstance() - .leftExpression(new LiteralExpression(left)) - .operator(operator) - .rightExpression(new LiteralExpression(right)) - .build(); - } } diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java deleted file mode 100644 index 405d166dc..000000000 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractor.java +++ /dev/null @@ -1,114 +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 - init - * - */ - -package de.sovity.edc.ext.wrapper.api.common.mappers.policy; - -import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; -import lombok.RequiredArgsConstructor; -import org.eclipse.edc.policy.model.AndConstraint; -import org.eclipse.edc.policy.model.AtomicConstraint; -import org.eclipse.edc.policy.model.Constraint; -import org.eclipse.edc.policy.model.OrConstraint; -import org.eclipse.edc.policy.model.Permission; -import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.policy.model.XoneConstraint; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -@RequiredArgsConstructor -public class ConstraintExtractor { - private final PolicyValidator policyValidator; - private final AtomicConstraintMapper atomicConstraintMapper; - - /** - * Build {@link UiPolicyConstraint}s from an ODRL {@link Policy}. - *

- * This operation is lossy which is why we document warnings / errors in {@link MappingErrors}. - * - * @param policy ODRL policy - * @param errors mapping errors - * @return ui policy constraints - */ - public List getPermissionConstraints(Policy policy, MappingErrors errors) { - policyValidator.validateOtherPolicyFieldsUnset(policy, errors); - - var permissions = policy.getPermissions(); - if (permissions == null) { - return List.of(); - } - - - List constraints = new ArrayList<>(); - for (int iPermission = 0; iPermission < permissions.size(); iPermission++) { - var permissionErrors = errors.forChildObject("permissions").forChildArrayElement(iPermission); - var permission = permissions.get(iPermission); - constraints.addAll(getPermissionConstraints(permission, permissionErrors)); - } - return constraints; - } - - private List getPermissionConstraints(Permission permission, MappingErrors errors) { - policyValidator.validateOtherPermissionFieldsUnset(permission, errors); - - if (permission == null) { - return List.of(); - } - - var constraints = permission.getConstraints(); - if (constraints == null) { - return List.of(); - } - - var constraintsMapped = new ArrayList(); - for (int i = 0; i < constraints.size(); i++) { - var constraintErrors = errors.forChildObject("constraints").forChildArrayElement(i); - var constraint = constraints.get(i); - - var constraintMapped = buildConstraint(constraint, constraintErrors); - constraintMapped.ifPresent(constraintsMapped::add); - } - return constraintsMapped; - } - - private Optional buildConstraint(Constraint constraint, MappingErrors errors) { - if (constraint == null) { - errors.add("Constraint is null."); - return Optional.empty(); - } - - if (constraint instanceof XoneConstraint) { - errors.add("XoneConstraints are currently unsupported."); - return Optional.empty(); - } - - if (constraint instanceof AndConstraint) { - errors.add("AndConstraints are currently unsupported."); - return Optional.empty(); - } - - if (constraint instanceof OrConstraint) { - errors.add("OrConstraints are currently unsupported."); - return Optional.empty(); - } - - if (!(constraint instanceof AtomicConstraint)) { - errors.add("Unknown constraint type %s.".formatted(constraint.getClass().getName())); - return Optional.empty(); - } - - return atomicConstraintMapper.buildUiConstraint((AtomicConstraint) constraint, errors); - } -} diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionExtractor.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionExtractor.java new file mode 100644 index 000000000..496659e11 --- /dev/null +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionExtractor.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - init + */ + +package de.sovity.edc.ext.wrapper.api.common.mappers.policy; + +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; +import lombok.RequiredArgsConstructor; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.edc.policy.model.Policy; + +import java.util.ArrayList; +import java.util.List; + +@RequiredArgsConstructor +public class ExpressionExtractor { + private final PolicyValidator policyValidator; + private final ExpressionMapper expressionMapper; + + /** + * Build {@link UiPolicyExpression} from an ODRL {@link Policy}. + *

+ * This operation is lossy which is why we document warnings / errors in {@link MappingErrors}. + * + * @param policy ODRL policy + * @param errors mapping errors + * @return ui policy expression + */ + public UiPolicyExpression getPermissionExpression(Policy policy, MappingErrors errors) { + var expressions = getPermissionExpressions(policy, errors); + if (expressions.isEmpty()) { + return UiPolicyExpression.empty(); + } else if (expressions.size() == 1) { + return expressions.get(0); + } else { + return UiPolicyExpression.and(expressions); + } + } + + /** + * Build {@link UiPolicyExpression}s from an ODRL {@link Policy}. + *

+ * This operation is lossy which is why we document warnings / errors in {@link MappingErrors}. + * + * @param policy ODRL policy + * @param errors mapping errors + * @return ui policy expressions + */ + private List getPermissionExpressions(Policy policy, MappingErrors errors) { + policyValidator.validateOtherPolicyFieldsUnset(policy, errors); + + var permissions = policy.getPermissions(); + if (permissions == null) { + return List.of(); + } + + if (permissions.size() > 1) { + errors.add("Multiple permissions were present. Prefer using a conjunction using AND."); + } + + List expressions = new ArrayList<>(); + for (int iPermission = 0; iPermission < permissions.size(); iPermission++) { + var permissionErrors = errors.forChildObject("permissions").forChildArrayElement(iPermission); + var permission = permissions.get(iPermission); + expressions.addAll(getPermissionExpressions(permission, permissionErrors)); + } + return expressions; + } + + private List getPermissionExpressions(Permission permission, MappingErrors errors) { + policyValidator.validateOtherPermissionFieldsUnset(permission, errors); + + if (permission == null) { + return List.of(); + } + + var constraints = permission.getConstraints(); + if (constraints != null && constraints.size() > 1) { + errors.forChildObject("constraints") + .add("Multiple constraints were present. Prefer using a conjunction using AND."); + } + + return expressionMapper.buildUiPolicyExpressions( + constraints, + errors.forChildObject("constraints") + ); + } +} diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionMapper.java new file mode 100644 index 000000000..025ce1488 --- /dev/null +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionMapper.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - init + */ + +package de.sovity.edc.ext.wrapper.api.common.mappers.policy; + +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpressionType; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.eclipse.edc.policy.model.AndConstraint; +import org.eclipse.edc.policy.model.AtomicConstraint; +import org.eclipse.edc.policy.model.Constraint; +import org.eclipse.edc.policy.model.OrConstraint; +import org.eclipse.edc.policy.model.XoneConstraint; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@RequiredArgsConstructor +public class ExpressionMapper { + private final AtomicConstraintMapper atomicConstraintMapper; + + public List buildConstraints( + @Nullable List expressions + ) { + if (expressions == null) { + return List.of(); + } + + return expressions.stream() + .map(this::buildConstraint) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + } + + @NotNull + public List buildUiPolicyExpressions( + @Nullable List constraints, + @NonNull MappingErrors errors + ) { + if (constraints == null) { + errors.add("Constraints are null."); + return List.of(); + } + + var expressions = new ArrayList(); + for (int i = 0; i < constraints.size(); i++) { + var constraintErrors = errors.forChildArrayElement(i); + var constraint = constraints.get(i); + + buildUiPolicyExpression(constraint, constraintErrors).ifPresent(expressions::add); + } + return expressions; + } + + public Optional buildConstraint(UiPolicyExpression expression) { + if (expression == null || expression.getType() == null) { + return Optional.empty(); + } + + return switch (expression.getType()) { + case EMPTY -> Optional.empty(); + case AND -> Optional.of(AndConstraint.Builder.newInstance() + .constraints(buildConstraints(expression.getExpressions())) + .build()); + case OR -> Optional.of(OrConstraint.Builder.newInstance() + .constraints(buildConstraints(expression.getExpressions())) + .build()); + case XONE -> Optional.of(XoneConstraint.Builder.newInstance() + .constraints(buildConstraints(expression.getExpressions())) + .build()); + case CONSTRAINT -> Optional.of(atomicConstraintMapper + .buildAtomicConstraint(expression.getConstraint())); + }; + } + + private Optional buildUiPolicyExpression(Constraint constraint, MappingErrors errors) { + if (constraint == null) { + errors.add("Expression is null."); + return Optional.empty(); + } + + if (constraint instanceof XoneConstraint xone) { + return buildMultiUiPolicyExpression( + UiPolicyExpressionType.XONE, + xone.getConstraints(), + errors.forChildObject("constraints") + ); + } else if (constraint instanceof AndConstraint and) { + return buildMultiUiPolicyExpression( + UiPolicyExpressionType.AND, + and.getConstraints(), + errors.forChildObject("constraints") + ); + } else if (constraint instanceof OrConstraint or) { + return buildMultiUiPolicyExpression( + UiPolicyExpressionType.OR, + or.getConstraints(), + errors.forChildObject("constraints") + ); + } else if (constraint instanceof AtomicConstraint atomic) { + return atomicConstraintMapper.buildUiConstraint(atomic, errors) + .map(this::buildConstraintUiPolicyExpression); + } + + errors.add("Unknown expression type %s.".formatted(constraint.getClass().getName())); + return Optional.empty(); + } + + private Optional buildMultiUiPolicyExpression( + UiPolicyExpressionType type, + List constraints, + MappingErrors errors + ) { + var expressions = buildUiPolicyExpressions(constraints, errors); + var expression = UiPolicyExpression.builder() + .type(type) + .expressions(expressions) + .build(); + return Optional.of(expression); + } + + private UiPolicyExpression buildConstraintUiPolicyExpression(UiPolicyConstraint constraint) { + return UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(constraint) + .build(); + } +} diff --git a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java index f271cd773..a733d13a7 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java +++ b/extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/LiteralMapper.java @@ -42,23 +42,23 @@ public Object getUiLiteralValue(UiPolicyLiteral literal) { } public Optional getExpressionString( - Expression expression, - MappingErrors errors + Expression expression, + MappingErrors errors ) { return getLiteralExpression(expression, errors).flatMap(literalExpression -> - getLiteralExpressionString(literalExpression, errors)); + getLiteralExpressionString(literalExpression, errors)); } public Optional getExpressionValue( - Expression expression, - MappingErrors errors + Expression expression, + MappingErrors errors ) { return getLiteralExpression(expression, errors).flatMap(this::getLiteralExpressionValue); } private Optional getLiteralExpressionString( - LiteralExpression literalExpression, - MappingErrors errors + LiteralExpression literalExpression, + MappingErrors errors ) { var value = literalExpression.getValue(); if (value == null) { @@ -84,7 +84,7 @@ private Optional getLiteralExpressionValue(LiteralExpression li } boolean isStringList = value instanceof Collection && ((Collection) value).stream() - .allMatch(it -> it == null || it instanceof String); + .allMatch(it -> it == null || it instanceof String); if (isStringList) { return Optional.of(UiPolicyLiteral.ofStringList((Collection) value)); } diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/LegacyPolicyMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/LegacyPolicyMapperTest.java new file mode 100644 index 000000000..43f5a883a --- /dev/null +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/LegacyPolicyMapperTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.common.mappers; + +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.UiPolicyExpression; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@SuppressWarnings("deprecated") +@ExtendWith(MockitoExtension.class) +public class LegacyPolicyMapperTest { + @InjectMocks + LegacyPolicyMapper legacyPolicyMapper; + + @Test + void buildUiPolicyExpression_null() { + // arrange + UiPolicyCreateRequest request = null; + + // act + UiPolicyExpression result = legacyPolicyMapper.buildUiPolicyExpression(request); + + // assert + assertThat(result).isEqualTo(UiPolicyExpression.empty()); + } + + @Test + void buildUiPolicyExpression_expressionsNull() { + // arrange + var request = new UiPolicyCreateRequest(); + request.setConstraints(null); + + // act + UiPolicyExpression result = legacyPolicyMapper.buildUiPolicyExpression(request); + + // assert + assertThat(result).isEqualTo(UiPolicyExpression.empty()); + } + + @Test + void buildUiPolicyExpression_emptyExpressions() { + // arrange + var request = new UiPolicyCreateRequest(); + request.setConstraints(List.of()); + + // act + UiPolicyExpression result = legacyPolicyMapper.buildUiPolicyExpression(request); + + // assert + assertThat(result).isEqualTo(UiPolicyExpression.empty()); + } + + @Test + void buildUiPolicyExpression_singleExpression() { + // arrange + var request = new UiPolicyCreateRequest(); + var expression = new UiPolicyConstraint(); + request.setConstraints(List.of(expression)); + + // act + UiPolicyExpression result = legacyPolicyMapper.buildUiPolicyExpression(request); + + // assert + assertThat(result).isEqualTo(UiPolicyExpression.constraint(expression)); + } + + @Test + void buildUiPolicyExpression_multipleExpressions() { + // arrange + var request = new UiPolicyCreateRequest(); + var constraint1 = mock(UiPolicyConstraint.class); + var constraint2 = mock(UiPolicyConstraint.class); + request.setConstraints(List.of(constraint1, constraint2)); + + // act + UiPolicyExpression result = legacyPolicyMapper.buildUiPolicyExpression(request); + + // assert + assertThat(result).isEqualTo(UiPolicyExpression.and(List.of( + UiPolicyExpression.constraint(constraint1), + UiPolicyExpression.constraint(constraint2) + ))); + } +} diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java index 2d01fe7e7..7ef734cfe 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapperTest.java @@ -14,127 +14,106 @@ package de.sovity.edc.ext.wrapper.api.common.mappers; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.AtomicConstraintMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ConstraintExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.MappingErrors; -import de.sovity.edc.ext.wrapper.api.common.model.AtomicConstraintDto; -import de.sovity.edc.ext.wrapper.api.common.model.Expression; -import de.sovity.edc.ext.wrapper.api.common.model.ExpressionType; 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.UiPolicyExpression; +import jakarta.json.Json; import jakarta.json.JsonObject; -import lombok.SneakyThrows; +import org.eclipse.edc.policy.model.AndConstraint; import org.eclipse.edc.policy.model.AtomicConstraint; +import org.eclipse.edc.policy.model.Constraint; +import org.eclipse.edc.policy.model.OrConstraint; import org.eclipse.edc.policy.model.Policy; import org.eclipse.edc.policy.model.PolicyType; +import org.eclipse.edc.policy.model.XoneConstraint; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; +import java.util.Optional; -import static de.sovity.edc.ext.wrapper.api.common.model.ExpressionType.ATOMIC_CONSTRAINT; -import static de.sovity.edc.utils.JsonUtils.parseJsonObj; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class PolicyMapperTest { @InjectMocks PolicyMapper policyMapper; - @Mock - TypeTransformerRegistry transformerRegistry; - + ExpressionExtractor expressionExtractor; @Mock - ConstraintExtractor constraintExtractor; - + ExpressionMapper expressionMapper; @Mock - AtomicConstraintMapper atomicConstraintMapper; - + TypeTransformerRegistry typeTransformerRegistry; @Test - @SneakyThrows - void test_buildPolicyDto() { - try (MockedStatic mappingErrors = mockStatic(MappingErrors.class)) { - // arrange - var policy = mock(Policy.class); - var errors = mock(MappingErrors.class); - var constraints = List.of(mock(UiPolicyConstraint.class)); - - when(errors.getErrors()).thenReturn(List.of("error1")); - - mappingErrors.when(MappingErrors::root).thenReturn(errors); - when(constraintExtractor.getPermissionConstraints(policy, errors)).thenReturn(constraints); - when(transformerRegistry.transform(policy, JsonObject.class)).thenReturn(Result.success(parseJsonObj("{}"))); - - // act - var actual = policyMapper.buildUiPolicy(policy); - - // assert - assertThat(actual.getPolicyJsonLd()).isEqualTo("{}"); - assertThat(actual.getConstraints()).isEqualTo(constraints); - assertThat(actual.getErrors()).isEqualTo(List.of("error1")); - } + void buildUiPolicy() { + // arrange + var policy = mock(Policy.class); + var expression = mock(UiPolicyExpression.class); + + when(expressionExtractor.getPermissionExpression(eq(policy), any())).thenAnswer(i -> { + var errors = i.getArgument(1, MappingErrors.class); + errors.add("test"); + return expression; + }); + + when(typeTransformerRegistry.transform(eq(policy), eq(JsonObject.class))) + .thenReturn(Result.success(Json.createObjectBuilder().add("a", "b").build())); + + // act + var actual = policyMapper.buildUiPolicy(policy); + + // assert + assertThat(actual.getExpression()).isEqualTo(expression); + assertThat(actual.getErrors()).containsExactly("$: test"); + assertThat(actual.getPolicyJsonLd()).isEqualTo("{\"a\":\"b\"}"); } @Test - void test_buildPolicy() { + void buildPolicy_constraintExtracted() { // arrange - var constraint = mock(UiPolicyConstraint.class); - var createRequest = new UiPolicyCreateRequest(List.of(constraint)); - - var expected = mock(AtomicConstraint.class); - when(atomicConstraintMapper.buildAtomicConstraints(eq(List.of(constraint)))) - .thenReturn(List.of(expected)); + var uiExpression = mock(UiPolicyExpression.class); + var constraint = mock(Constraint.class); + when(expressionMapper.buildConstraint(uiExpression)) + .thenReturn(Optional.of(constraint)); // act - var actual = policyMapper.buildPolicy(createRequest); + var actual = policyMapper.buildPolicy(uiExpression); // assert assertThat(actual.getType()).isEqualTo(PolicyType.SET); assertThat(actual.getPermissions()).hasSize(1); - assertThat(actual.getPermissions().get(0).getConstraints()).hasSize(1); assertThat(actual.getPermissions().get(0).getAction().getType()).isEqualTo("USE"); - assertThat(actual.getPermissions().get(0).getConstraints().get(0)).isSameAs(expected); + assertThat(actual.getPermissions().get(0).getConstraints()).hasSize(1); + assertThat(actual.getPermissions().get(0).getConstraints()).containsExactly(constraint); } - @ParameterizedTest - @ValueSource(strings = {"AND", "OR", "XOR"}) - void buildGenericPolicy(String constraintTypeString) { + @Test + void buildPolicy_noConstraint() { // arrange - var expressionType = ExpressionType.valueOf(constraintTypeString); - var incomingConstraint = mock(AtomicConstraintDto.class); - var mappedAtomicConstraint = mock(AtomicConstraint.class); - var atomicConstraint = new Expression(ATOMIC_CONSTRAINT, List.of(), incomingConstraint); - var atomicConstraints = List.of(atomicConstraint, atomicConstraint); - var baseConstraintElement = new Expression(expressionType, atomicConstraints, null); + var uiExpression = mock(UiPolicyExpression.class); + when(expressionMapper.buildConstraint(uiExpression)) + .thenReturn(Optional.empty()); // act - when(atomicConstraintMapper - .buildAtomicConstraint(eq(incomingConstraint))) - .thenReturn(mappedAtomicConstraint); - var policy = policyMapper.buildPolicy(List.of(baseConstraintElement)); + var actual = policyMapper.buildPolicy(uiExpression); // assert - assertThat(policy.getType()).isEqualTo(PolicyType.SET); - assertThat(policy.getPermissions()).hasSize(1); - var permission = policy.getPermissions().get(0); - assertThat(permission.getConstraints()).hasSize(1); - assertThat(permission.getAction().getType()).isEqualTo("USE"); - - var constraintObject = permission.getConstraints().get(0); - assertNotNull(constraintObject); + assertThat(actual.getType()).isEqualTo(PolicyType.SET); + assertThat(actual.getPermissions()).hasSize(1); + assertThat(actual.getPermissions().get(0).getConstraints()).isEmpty(); + assertThat(actual.getPermissions().get(0).getAction().getType()).isEqualTo("USE"); } } diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapperTest.java index 0a3b718f4..04eac28c7 100644 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapperTest.java +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/AtomicConstraintMapperTest.java @@ -38,18 +38,6 @@ class AtomicConstraintMapperTest { - @Test - void test_buildAtomicConstraint_null() { - // arrange - var atomicConstraintMapper = newAtomicConstraintMapper(); - - // act - var actual = atomicConstraintMapper.buildAtomicConstraints(null); - - // assert - assertThat(actual).isEmpty(); - } - @Test void test_buildAtomicConstraint() { // arrange @@ -62,16 +50,14 @@ void test_buildAtomicConstraint() { when(literalMapper.getUiLiteralValue(right)).thenReturn("right"); // act - var actual = atomicConstraintMapper.buildAtomicConstraints(List.of(constraint)); + var actual = atomicConstraintMapper.buildAtomicConstraint(constraint); // assert - assertThat(actual).hasSize(1); - var atomicConstraint = actual.get(0); - assertThat(atomicConstraint.getLeftExpression()).isInstanceOfSatisfying(LiteralExpression.class, literalExpression -> + assertThat(actual.getLeftExpression()).isInstanceOfSatisfying(LiteralExpression.class, literalExpression -> assertThat(literalExpression.getValue()).isEqualTo("left")); - assertThat(atomicConstraint.getRightExpression()).isInstanceOfSatisfying(LiteralExpression.class, literalExpression -> + assertThat(actual.getRightExpression()).isInstanceOfSatisfying(LiteralExpression.class, literalExpression -> assertThat(literalExpression.getValue()).isEqualTo("right")); - assertThat(atomicConstraint.getOperator()).isEqualTo(Operator.EQ); + assertThat(actual.getOperator()).isEqualTo(Operator.EQ); } @Test diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java deleted file mode 100644 index 0245b6bb0..000000000 --- a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ConstraintExtractorTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2022 sovity GmbH - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * sovity GmbH - initial API and implementation - * - */ - -package de.sovity.edc.ext.wrapper.api.common.mappers.policy; - -import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; -import org.eclipse.edc.policy.model.AndConstraint; -import org.eclipse.edc.policy.model.AtomicConstraint; -import org.eclipse.edc.policy.model.OrConstraint; -import org.eclipse.edc.policy.model.Permission; -import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.policy.model.XoneConstraint; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class ConstraintExtractorTest { - @InjectMocks - ConstraintExtractor constraintExtractor; - - @Mock - PolicyValidator policyValidator; - - @Mock - AtomicConstraintMapper atomicConstraintMapper; - - @Test - void test_getPermissionConstraints_null() { - // arrange - var policy = Policy.Builder.newInstance().build(); - var errors = MappingErrors.root(); - - // act - var actual = constraintExtractor.getPermissionConstraints(policy, errors); - - // assert - assertThat(actual).isEmpty(); - verify(policyValidator).validateOtherPolicyFieldsUnset(policy, errors); - } - - @Test - void test_getPermissionConstraints_many_constraints() { - // arrange - var first = mock(AtomicConstraint.class); - var other = mock(AtomicConstraint.class); - var permission = Permission.Builder.newInstance() - .constraint(null) - .constraint(first) - .constraint(other) - .constraint(mock(AndConstraint.class)) - .constraint(mock(OrConstraint.class)) - .constraint(mock(XoneConstraint.class)) - .build(); - var policy = Policy.Builder.newInstance() - .permission(null) - .permission(permission) - .permission(Permission.Builder.newInstance().build()) - .build(); - var errors = MappingErrors.root(); - - var expected = mock(UiPolicyConstraint.class); - when(atomicConstraintMapper.buildUiConstraint(same(first), any())).thenReturn(Optional.of(expected)); - when(atomicConstraintMapper.buildUiConstraint(same(other), any())).thenReturn(Optional.empty()); - - // act - var actual = constraintExtractor.getPermissionConstraints(policy, errors); - - // assert - verify(policyValidator).validateOtherPermissionFieldsUnset(same(permission), any()); - verify(policyValidator).validateOtherPermissionFieldsUnset(eq(null), any()); - assertThat(actual).containsExactly(expected); - assertThat(errors.getErrors()).containsExactlyInAnyOrder( - "$.permissions[1].constraints[0]: Constraint is null.", - "$.permissions[1].constraints[3]: AndConstraints are currently unsupported.", - "$.permissions[1].constraints[4]: OrConstraints are currently unsupported.", - "$.permissions[1].constraints[5]: XoneConstraints are currently unsupported." - ); - } -} diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionExtractorTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionExtractorTest.java new file mode 100644 index 000000000..b4e96b340 --- /dev/null +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionExtractorTest.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.common.mappers.policy; + +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpressionType; +import org.eclipse.edc.policy.model.Constraint; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.edc.policy.model.Policy; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ExpressionExtractorTest { + @InjectMocks + ExpressionExtractor expressionExtractor; + + @Mock + PolicyValidator policyValidator; + + @Mock + ExpressionMapper expressionMapper; + + @Test + void test_getPermissionConstraints_null() { + // arrange + var policy = Policy.Builder.newInstance().build(); + var errors = MappingErrors.root(); + + // act + var actual = expressionExtractor.getPermissionExpression(policy, errors); + + // assert + assertThat(actual.getType()).isEqualTo(UiPolicyExpressionType.EMPTY); + verify(policyValidator).validateOtherPolicyFieldsUnset(policy, errors); + } + + @Test + void test_getPermissionConstraints_no_constraints() { + // arrange + var permission = Permission.Builder.newInstance() + .build(); + var policy = Policy.Builder.newInstance() + .permissions(List.of(permission)) + .build(); + var errors = MappingErrors.root(); + + // act + var actual = expressionExtractor.getPermissionExpression(policy, errors); + + // assert + assertThat(actual.getType()).isEqualTo(UiPolicyExpressionType.EMPTY); + verify(policyValidator).validateOtherPolicyFieldsUnset(policy, errors); + } + + @Test + void test_getPermissionConstraints_single_constraint() { + // arrange + var constraint = mock(Constraint.class); + var permission = Permission.Builder.newInstance() + .constraint(constraint) + .build(); + + var policy = Policy.Builder.newInstance() + .permission(permission) + .build(); + var errors = MappingErrors.root(); + + var uiExpression = mock(UiPolicyExpression.class); + when(expressionMapper.buildUiPolicyExpressions(eq(List.of(constraint)), any())).thenReturn(List.of(uiExpression)); + + // act + var actual = expressionExtractor.getPermissionExpression(policy, errors); + + // assert + verify(policyValidator).validateOtherPermissionFieldsUnset(same(permission), any()); + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(uiExpression); + assertThat(errors.getErrors()).isEmpty(); + } + + @Test + void test_getPermissionConstraints_merge_constraints() { + // arrange + var first = mock(Constraint.class); + var firstPermission = Permission.Builder.newInstance() + .constraint(first) + .build(); + + var second = mock(Constraint.class); + var secondPermission = Permission.Builder.newInstance() + .constraint(second) + .build(); + + var policy = Policy.Builder.newInstance() + .permission(firstPermission) + .permission(secondPermission) + .build(); + var errors = MappingErrors.root(); + + var firstUiExpression = mock(UiPolicyExpression.class); + var secondUiExpression = mock(UiPolicyExpression.class); + when(expressionMapper.buildUiPolicyExpressions(eq(List.of(first)), any())).thenReturn(List.of(firstUiExpression)); + when(expressionMapper.buildUiPolicyExpressions(eq(List.of(second)), any())).thenReturn(List.of(secondUiExpression)); + + // act + var actual = expressionExtractor.getPermissionExpression(policy, errors); + + // assert + verify(policyValidator).validateOtherPermissionFieldsUnset(same(firstPermission), any()); + verify(policyValidator).validateOtherPermissionFieldsUnset(same(secondPermission), any()); + var expected = UiPolicyExpression.and(List.of(firstUiExpression, secondUiExpression)); + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(expected); + assertThat(errors.getErrors()).containsExactly( + "$: Multiple permissions were present. Prefer using a conjunction using AND." + ); + } + + @Test + void test_getPermissionConstraints_merge_constraints2() { + // arrange + var first = mock(Constraint.class); + var second = mock(Constraint.class); + var permission = Permission.Builder.newInstance() + .constraints(List.of(first, second)) + .build(); + + var policy = Policy.Builder.newInstance() + .permission(permission) + .build(); + + var errors = MappingErrors.root(); + + var firstUiExpression = mock(UiPolicyExpression.class); + var secondUiExpression = mock(UiPolicyExpression.class); + when(expressionMapper.buildUiPolicyExpressions(eq(List.of(first, second)), any())) + .thenReturn(List.of(firstUiExpression, secondUiExpression)); + + // act + var actual = expressionExtractor.getPermissionExpression(policy, errors); + + // assert + verify(policyValidator).validateOtherPermissionFieldsUnset(same(permission), any()); + var expected = UiPolicyExpression.and(List.of(firstUiExpression, secondUiExpression)); + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(expected); + assertThat(errors.getErrors()).containsExactly( + "$.permissions[0].constraints: Multiple constraints were present. Prefer using a conjunction using AND." + ); + } + + @Test + void test_getPermissionConstraints_error_mapping() { + // arrange + var constraint = mock(Constraint.class); + var permission = Permission.Builder.newInstance() + .constraint(constraint) + .build(); + + var policy = Policy.Builder.newInstance() + .permission(permission) + .build(); + var errors = MappingErrors.root(); + + when(expressionMapper.buildUiPolicyExpressions(eq(List.of(constraint)), any())).thenAnswer(i -> { + i.getArgument(1, MappingErrors.class).add("test"); + return List.of(); + }); + + // act + var actual = expressionExtractor.getPermissionExpression(policy, errors); + + // assert + verify(policyValidator).validateOtherPermissionFieldsUnset(same(permission), any()); + assertThat(actual) + .usingRecursiveComparison() + .isEqualTo(UiPolicyExpression.empty()); + assertThat(errors.getErrors()).containsExactlyInAnyOrder( + "$.permissions[0].constraints: test" + ); + } +} diff --git a/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionMapperTest.java b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionMapperTest.java new file mode 100644 index 000000000..6a481887c --- /dev/null +++ b/extensions/wrapper/wrapper-common-mappers/src/test/java/de/sovity/edc/ext/wrapper/api/common/mappers/policy/ExpressionMapperTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2022 sovity GmbH + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * sovity GmbH - initial API and implementation + * + */ + +package de.sovity.edc.ext.wrapper.api.common.mappers.policy; + +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyConstraint; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; +import org.eclipse.edc.policy.model.AndConstraint; +import org.eclipse.edc.policy.model.AtomicConstraint; +import org.eclipse.edc.policy.model.Constraint; +import org.eclipse.edc.policy.model.OrConstraint; +import org.eclipse.edc.policy.model.XoneConstraint; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ExpressionMapperTest { + @InjectMocks + ExpressionMapper expressionMapper; + + @Mock + AtomicConstraintMapper atomicConstraintMapper; + + @Test + void buildUiConstraint_errorPropagation() { + // arrange + var errors = MappingErrors.root(); + var atomicConstraint = mock(AtomicConstraint.class); + when(atomicConstraintMapper.buildUiConstraint(same(atomicConstraint), any())) + .thenAnswer(i -> { + i.getArgument(1, MappingErrors.class).add("test"); + return Optional.empty(); + }); + + var constraints = List.of(atomicConstraint); + + // act + var actual = expressionMapper.buildUiPolicyExpressions(constraints, errors); + + // assert + assertThat(actual).isEmpty(); + assertThat(errors.getErrors()).containsExactly("$[0]: test"); + } + + @Test + void buildUiConstraint_simpleAtomicConstraint() { + // arrange + var atomicConstraint = mock(AtomicConstraint.class); + var uiConstraint = mock(UiPolicyConstraint.class); + when(atomicConstraintMapper.buildUiConstraint(same(atomicConstraint), any())) + .thenReturn(Optional.of(uiConstraint)); + + var constraints = List.of(atomicConstraint); + + // act + var actual = expressionMapper.buildUiPolicyExpressions(constraints, MappingErrors.root()); + + // assert + assertThat(actual).containsExactly( + UiPolicyExpression.constraint(uiConstraint) + ); + } + + @Test + void buildUiConstraint_andConstraint() { + // arrange + var atomicConstraint = mock(AtomicConstraint.class); + var uiConstraint = mock(UiPolicyConstraint.class); + when(atomicConstraintMapper.buildUiConstraint(same(atomicConstraint), any())) + .thenReturn(Optional.of(uiConstraint)); + + var constraints = List.of( + AndConstraint.Builder.newInstance() + .constraint(atomicConstraint) + .build() + ); + + // act + var actual = expressionMapper.buildUiPolicyExpressions(constraints, MappingErrors.root()); + + // assert + assertThat(actual).containsExactly( + UiPolicyExpression.and(List.of( + UiPolicyExpression.constraint(uiConstraint) + )) + ); + } + + @Test + void buildUiConstraint_orConstraint() { + // arrange + var atomicConstraint = mock(AtomicConstraint.class); + var uiConstraint = mock(UiPolicyConstraint.class); + when(atomicConstraintMapper.buildUiConstraint(same(atomicConstraint), any())) + .thenReturn(Optional.of(uiConstraint)); + + var constraints = List.of( + OrConstraint.Builder.newInstance() + .constraint(atomicConstraint) + .build() + ); + + // act + var actual = expressionMapper.buildUiPolicyExpressions(constraints, MappingErrors.root()); + + // assert + assertThat(actual).containsExactly( + UiPolicyExpression.or(List.of( + UiPolicyExpression.constraint(uiConstraint) + )) + ); + } + + @Test + void buildUiConstraint_xoneConstraint() { + // arrange + var atomicConstraint = mock(AtomicConstraint.class); + var uiConstraint = mock(UiPolicyConstraint.class); + when(atomicConstraintMapper.buildUiConstraint(same(atomicConstraint), any())) + .thenReturn(Optional.of(uiConstraint)); + + var constraints = List.of( + XoneConstraint.Builder.newInstance() + .constraint(atomicConstraint) + .build() + ); + + // act + var actual = expressionMapper.buildUiPolicyExpressions(constraints, MappingErrors.root()); + + // assert + assertThat(actual).containsExactly( + UiPolicyExpression.xone(List.of( + UiPolicyExpression.constraint(uiConstraint) + )) + ); + } + + @Test + void buildConstraint_atomicConstraint() { + // arrange + var uiConstraint = mock(UiPolicyConstraint.class); + var expression = UiPolicyExpression.constraint(uiConstraint); + + var atomicConstraint = mock(AtomicConstraint.class); + when(atomicConstraintMapper.buildAtomicConstraint(uiConstraint)) + .thenReturn(atomicConstraint); + + // act + var actual = expressionMapper.buildConstraints(List.of(expression)); + + // assert + assertThat(actual).hasSize(1); + assertThat(actual.get(0)).isEqualTo(atomicConstraint); + } + + @Test + void buildConstraint_andConstraint() { + // arrange + var uiConstraint = mock(UiPolicyConstraint.class); + var expression = UiPolicyExpression.and(List.of( + UiPolicyExpression.constraint(uiConstraint) + )); + + var atomicConstraint = mock(AtomicConstraint.class); + when(atomicConstraintMapper.buildAtomicConstraint(uiConstraint)) + .thenReturn(atomicConstraint); + + // act + var actual = expressionMapper.buildConstraints(List.of(expression)); + + // assert + assertThat(actual).hasSize(1); + assertThat(actual.get(0)).isInstanceOf(AndConstraint.class); + + var constraints = ((AndConstraint) actual.get(0)).getConstraints(); + assertThat(constraints).hasSize(1); + assertThat(constraints.get(0)).isEqualTo(atomicConstraint); + } + + @Test + void buildConstraint_orConstraint() { + // arrange + var uiConstraint = mock(UiPolicyConstraint.class); + var expression = UiPolicyExpression.or(List.of( + UiPolicyExpression.constraint(uiConstraint) + )); + + var atomicConstraint = mock(AtomicConstraint.class); + when(atomicConstraintMapper.buildAtomicConstraint(uiConstraint)) + .thenReturn(atomicConstraint); + + // act + var actual = expressionMapper.buildConstraints(List.of(expression)); + + // assert + assertThat(actual).hasSize(1); + assertThat(actual.get(0)).isInstanceOf(OrConstraint.class); + + var constraints = ((OrConstraint) actual.get(0)).getConstraints(); + assertThat(constraints).hasSize(1); + assertThat(constraints.get(0)).isEqualTo(atomicConstraint); + } + + @Test + void buildConstraint_xoneConstraint() { + // arrange + var uiConstraint = mock(UiPolicyConstraint.class); + var expression = UiPolicyExpression.xone(List.of( + UiPolicyExpression.constraint(uiConstraint) + )); + + var atomicConstraint = mock(AtomicConstraint.class); + when(atomicConstraintMapper.buildAtomicConstraint(uiConstraint)) + .thenReturn(atomicConstraint); + + // act + var actual = expressionMapper.buildConstraints(List.of(expression)); + + // assert + assertThat(actual).hasSize(1); + assertThat(actual.get(0)).isInstanceOf(XoneConstraint.class); + + var constraints = ((XoneConstraint) actual.get(0)).getConstraints(); + assertThat(constraints).hasSize(1); + assertThat(constraints.get(0)).isEqualTo(atomicConstraint); + } +} diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java index 9613f64e1..d554dd74f 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.AssetMapper; +import de.sovity.edc.ext.wrapper.api.common.mappers.LegacyPolicyMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.AssetEditRequestMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.asset.AssetJsonLdBuilder; @@ -28,7 +29,8 @@ import de.sovity.edc.ext.wrapper.api.common.mappers.dataaddress.http.HttpDataSourceMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.dataaddress.http.HttpHeaderMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.AtomicConstraintMapper; -import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ConstraintExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionExtractor; +import de.sovity.edc.ext.wrapper.api.common.mappers.policy.ExpressionMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.LiteralMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.OperatorMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.policy.PolicyValidator; @@ -143,18 +145,11 @@ public static WrapperExtensionContext buildContext( var criterionOperatorMapper = new CriterionOperatorMapper(); var criterionLiteralMapper = new CriterionLiteralMapper(); var criterionMapper = new CriterionMapper(criterionOperatorMapper, criterionLiteralMapper); - var literalMapper = new LiteralMapper(objectMapper); - var atomicConstraintMapper = new AtomicConstraintMapper(literalMapper, operatorMapper); - var policyValidator = new PolicyValidator(); - var constraintExtractor = new ConstraintExtractor(policyValidator, atomicConstraintMapper); - var policyMapper = new PolicyMapper( - constraintExtractor, - atomicConstraintMapper, - typeTransformerRegistry); var edcPropertyUtils = new EdcPropertyUtils(); var selfDescriptionService = new SelfDescriptionService(config, monitor); var ownConnectorEndpointService = new OwnConnectorEndpointServiceImpl(selfDescriptionService); var assetMapper = newAssetMapper(typeTransformerRegistry, jsonLd, ownConnectorEndpointService); + var policyMapper = newPolicyMapper(objectMapper, typeTransformerRegistry, operatorMapper); var transferProcessStateService = new TransferProcessStateService(); var contractNegotiationUtils = new ContractNegotiationUtils( contractNegotiationService, @@ -218,9 +213,11 @@ public static WrapperExtensionContext buildContext( var agreementDetailsQuery = new ContractAgreementTerminationDetailsQuery(); var terminateContractQuery = new TerminateContractQuery(); var contractAgreementTerminationApiService = new ContractAgreementTerminationApiService(contractAgreementTerminationService); + var legacyPolicyMapper = new LegacyPolicyMapper(); var policyDefinitionApiService = new PolicyDefinitionApiService( policyDefinitionService, - policyMapper + policyMapper, + legacyPolicyMapper ); var dataOfferBuilder = new DspDataOfferBuilder(jsonLd); var uiDataOfferBuilder = new UiDataOfferBuilder(assetMapper, policyMapper); @@ -295,8 +292,7 @@ public static WrapperExtensionContext buildContext( var useCaseResource = new UseCaseResourceImpl( kpiApiService, supportedPolicyApiService, - useCaseCatalogApiService, - policyDefinitionApiService + useCaseCatalogApiService ); // Collect all JAX-RS resources @@ -339,4 +335,22 @@ private static AssetMapper newAssetMapper( jsonLd ); } + + @NotNull + private static PolicyMapper newPolicyMapper( + ObjectMapper objectMapper, + TypeTransformerRegistry typeTransformerRegistry, + OperatorMapper operatorMapper + ) { + var literalMapper = new LiteralMapper(objectMapper); + var atomicConstraintMapper = new AtomicConstraintMapper(literalMapper, operatorMapper); + var policyValidator = new PolicyValidator(); + var expressionMapper = new ExpressionMapper(atomicConstraintMapper); + var constraintExtractor = new ExpressionExtractor(policyValidator, expressionMapper); + return new PolicyMapper( + constraintExtractor, + expressionMapper, + typeTransformerRegistry + ); + } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java index 1d7af06fe..e43a992fd 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResourceImpl.java @@ -14,7 +14,8 @@ package de.sovity.edc.ext.wrapper.api.ui; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateDto; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.UiAsset; import de.sovity.edc.ext.wrapper.api.common.model.UiAssetCreateRequest; import de.sovity.edc.ext.wrapper.api.common.model.UiAssetEditRequest; @@ -103,10 +104,16 @@ public PolicyDefinitionPage getPolicyDefinitionPage() { } @Override + @Deprecated public IdResponseDto createPolicyDefinition(PolicyDefinitionCreateRequest policyDefinitionDtoDto) { return policyDefinitionApiService.createPolicyDefinition(policyDefinitionDtoDto); } + @Override + public IdResponseDto createPolicyDefinitionV2(PolicyDefinitionCreateDto policyDefinitionCreateDto) { + return policyDefinitionApiService.createPolicyDefinitionV2(policyDefinitionCreateDto); + } + @Override public IdResponseDto deletePolicyDefinition(String policyId) { return policyDefinitionApiService.deletePolicyDefinition(policyId); diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java index 0ce0b737e..87a17cbcb 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiService.java @@ -16,11 +16,13 @@ import de.sovity.edc.ext.wrapper.api.ServiceException; +import de.sovity.edc.ext.wrapper.api.common.mappers.LegacyPolicyMapper; import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyMapper; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionCreateRequest; -import de.sovity.edc.ext.wrapper.api.common.model.PolicyDefinitionDto; +import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyExpression; import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; -import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateDto; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.ext.wrapper.api.ui.model.PolicyDefinitionDto; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.eclipse.edc.connector.policy.spi.PolicyDefinition; @@ -36,18 +38,28 @@ public class PolicyDefinitionApiService { private final PolicyDefinitionService policyDefinitionService; private final PolicyMapper policyMapper; + private final LegacyPolicyMapper legacyPolicyMapper; public List getPolicyDefinitions() { var policyDefinitions = getAllPolicyDefinitions(); return policyDefinitions.stream() - .sorted(Comparator.comparing(PolicyDefinition::getCreatedAt).reversed()) - .map(this::buildPolicyDefinitionDto) - .toList(); + .sorted(Comparator.comparing(PolicyDefinition::getCreatedAt).reversed()) + .map(this::buildPolicyDefinitionDto) + .toList(); } @NotNull + @Deprecated public IdResponseDto createPolicyDefinition(PolicyDefinitionCreateRequest request) { - var policyDefinition = buildPolicyDefinition(request); + var uiPolicyExpression = legacyPolicyMapper.buildUiPolicyExpression(request.getPolicy()); + var policyDefinition = buildPolicyDefinition(request.getPolicyDefinitionId(), uiPolicyExpression); + policyDefinition = policyDefinitionService.create(policyDefinition).orElseThrow(ServiceException::new); + return new IdResponseDto(policyDefinition.getId()); + } + + @NotNull + public IdResponseDto createPolicyDefinitionV2(PolicyDefinitionCreateDto request) { + var policyDefinition = buildPolicyDefinition(request.getPolicyDefinitionId(), request.getExpression()); policyDefinition = policyDefinitionService.create(policyDefinition).orElseThrow(ServiceException::new); return new IdResponseDto(policyDefinition.getId()); } @@ -61,34 +73,20 @@ public IdResponseDto deletePolicyDefinition(String policyDefinitionId) { private List getAllPolicyDefinitions() { return policyDefinitionService.query(QuerySpec.max()).orElseThrow(ServiceException::new).toList(); } + public PolicyDefinitionDto buildPolicyDefinitionDto(PolicyDefinition policyDefinition) { var policy = policyMapper.buildUiPolicy(policyDefinition.getPolicy()); return PolicyDefinitionDto.builder() - .policyDefinitionId(policyDefinition.getId()) - .policy(policy) - .build(); - } - - public PolicyDefinition buildPolicyDefinition(PolicyDefinitionCreateRequest policyDefinitionDto) { - var policy = policyMapper.buildPolicy(policyDefinitionDto.getPolicy()); - return PolicyDefinition.Builder.newInstance() - .id(policyDefinitionDto.getPolicyDefinitionId()) - .policy(policy) - .build(); - } - - public IdResponseDto createPolicyDefinition(PolicyCreateRequest policyCreateRequest) { - var policyDefinition = buildPolicyDefinition(policyCreateRequest); - policyDefinition = policyDefinitionService.create(policyDefinition).orElseThrow(ServiceException::new); - return new IdResponseDto(policyDefinition.getId()); + .policyDefinitionId(policyDefinition.getId()) + .policy(policy) + .build(); } - private PolicyDefinition buildPolicyDefinition(PolicyCreateRequest policyCreateRequest) { - var permissionExpression = policyCreateRequest.getPermission().getExpression(); - var policy = policyMapper.buildPolicy(List.of(permissionExpression)); + public PolicyDefinition buildPolicyDefinition(String id, UiPolicyExpression uiPolicyExpression) { + var policy = policyMapper.buildPolicy(uiPolicyExpression); return PolicyDefinition.Builder.newInstance() - .id(policyCreateRequest.getPolicyDefinitionId()) - .policy(policy) - .build(); + .id(id) + .policy(policy) + .build(); } } diff --git a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java index 076c0db12..7f1bf7d74 100644 --- a/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java +++ b/extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseResourceImpl.java @@ -14,12 +14,9 @@ package de.sovity.edc.ext.wrapper.api.usecase; -import de.sovity.edc.ext.wrapper.api.ui.model.IdResponseDto; import de.sovity.edc.ext.wrapper.api.ui.model.UiDataOffer; -import de.sovity.edc.ext.wrapper.api.ui.pages.policy.PolicyDefinitionApiService; import de.sovity.edc.ext.wrapper.api.usecase.model.CatalogQuery; import de.sovity.edc.ext.wrapper.api.usecase.model.KpiResult; -import de.sovity.edc.ext.wrapper.api.usecase.model.PolicyCreateRequest; import de.sovity.edc.ext.wrapper.api.usecase.pages.catalog.UseCaseCatalogApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.KpiApiService; import de.sovity.edc.ext.wrapper.api.usecase.services.SupportedPolicyApiService; @@ -36,7 +33,6 @@ public class UseCaseResourceImpl implements UseCaseResource { private final KpiApiService kpiApiService; private final SupportedPolicyApiService supportedPolicyApiService; private final UseCaseCatalogApiService useCaseCatalogApiService; - private final PolicyDefinitionApiService policyDefinitionApiService; @Override public KpiResult getKpis() { @@ -52,9 +48,4 @@ public List getSupportedFunctions() { public List queryCatalog(CatalogQuery catalogQuery) { return useCaseCatalogApiService.fetchDataOffers(catalogQuery); } - - @Override - public IdResponseDto createPolicyDefinitionUseCase(PolicyCreateRequest policyCreateRequest) { - return policyDefinitionApiService.createPolicyDefinition(policyCreateRequest); - } } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java index fa71fe209..101a76fdb 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/catalog/CatalogApiTest.java @@ -17,7 +17,7 @@ import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.ContractDefinitionRequest; import de.sovity.edc.client.gen.model.DataSourceType; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiCriterion; import de.sovity.edc.client.gen.model.UiCriterionLiteral; @@ -25,7 +25,8 @@ import de.sovity.edc.client.gen.model.UiCriterionOperator; import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; @@ -107,14 +108,12 @@ private void createAsset() { } private void createPolicy() { - var policyDefinition = PolicyDefinitionCreateRequest.builder() + var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(dataOfferId) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of()) - .build()) + .expression(UiPolicyExpression.builder().type(UiPolicyExpressionType.EMPTY).build()) .build(); - client.uiApi().createPolicyDefinition(policyDefinition); + client.uiApi().createPolicyDefinitionV2(policyDefinition); } private void createContractDefinition() { diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java index 9b6536366..a69824768 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/contract_agreement/ContractAgreementPageTest.java @@ -18,6 +18,7 @@ import de.sovity.edc.client.gen.model.ContractAgreementDirection; import de.sovity.edc.client.gen.model.OperatorDto; import de.sovity.edc.client.gen.model.TransferProcessSimplifiedState; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.extension.e2e.connector.ConnectorRemote; import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; @@ -121,7 +122,10 @@ void testContractAgreementPage( assertThat(transfer.getState().getSimplifiedState()).isEqualTo(TransferProcessSimplifiedState.OK); assertThat(transfer.getErrorMessage()).isEqualTo("my-error-message-1"); - var constraint = agreement.getContractPolicy().getConstraints().get(0); + var expression = agreement.getContractPolicy().getExpression(); + assertThat(expression.getType()).isEqualTo(UiPolicyExpressionType.CONSTRAINT); + + var constraint = expression.getConstraint(); assertThat(constraint.getLeft()).isEqualTo("ALWAYS_TRUE"); assertThat(constraint.getOperator()).isEqualTo(OperatorDto.EQ); assertThat(constraint.getRight().getValue()).isEqualTo("true"); diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java index d80ac3cbd..f6e3344df 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/ui/pages/policy/PolicyDefinitionApiServiceTest.java @@ -17,17 +17,17 @@ import de.sovity.edc.client.EdcClient; import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.PolicyDefinitionDto; import de.sovity.edc.client.gen.model.UiPolicyConstraint; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.ext.db.jooq.Tables; import de.sovity.edc.extension.db.directaccess.DslContextFactory; import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import lombok.SneakyThrows; import lombok.val; import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.junit.annotations.ApiTest; @@ -37,7 +37,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import java.util.List; import java.util.Map; import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; @@ -62,12 +61,15 @@ class PolicyDefinitionApiServiceTest { } ); - UiPolicyConstraint constraint = UiPolicyConstraint.builder() - .left("a") - .operator(OperatorDto.EQ) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value("b") + UiPolicyExpression expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() + .left("a") + .operator(OperatorDto.EQ) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value("b") + .build()) .build()) .build(); @@ -86,10 +88,7 @@ void getPolicyList() { .filter(it -> it.getPolicyDefinitionId().equals("my-policy-def-1")) .findFirst().get(); assertThat(policyDefinition.getPolicyDefinitionId()).isEqualTo("my-policy-def-1"); - assertThat(policyDefinition.getPolicy().getConstraints()).hasSize(1); - - var constraintEntry = policyDefinition.getPolicy().getConstraints().get(0); - assertThat(constraintEntry).usingRecursiveComparison().isEqualTo(constraint); + assertThat(policyDefinition.getPolicy().getExpression()).usingRecursiveComparison().isEqualTo(expression); } @Test @@ -144,9 +143,8 @@ void test_delete(PolicyDefinitionService policyDefinitionService) { } private void createPolicyDefinition(String policyDefinitionId) { - var policy = new UiPolicyCreateRequest(List.of(constraint)); - var policyDefinition = new PolicyDefinitionCreateRequest(policyDefinitionId, policy); - client.uiApi().createPolicyDefinition(policyDefinition); + var policyDefinition = new PolicyDefinitionCreateDto(policyDefinitionId, expression); + client.uiApi().createPolicyDefinitionV2(policyDefinition); } } diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java deleted file mode 100644 index a6215b6ad..000000000 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/PolicyDefinitionApiServiceTest.java +++ /dev/null @@ -1,125 +0,0 @@ -package de.sovity.edc.ext.wrapper.api.usecase; - -import de.sovity.edc.client.EdcClient; -import de.sovity.edc.client.gen.model.AtomicConstraintDto; -import de.sovity.edc.client.gen.model.Expression; -import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PermissionDto; -import de.sovity.edc.client.gen.model.PolicyCreateRequest; -import de.sovity.edc.client.gen.model.PolicyDefinitionDto; -import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; -import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; -import de.sovity.edc.utils.jsonld.vocab.Prop; -import jakarta.json.Json; -import jakarta.json.JsonObject; -import org.eclipse.edc.junit.annotations.ApiTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import java.io.StringReader; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static de.sovity.edc.client.gen.model.ExpressionType.AND; -import static de.sovity.edc.client.gen.model.ExpressionType.ATOMIC_CONSTRAINT; -import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.forTestDatabase; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - - -@ApiTest -public class PolicyDefinitionApiServiceTest { - - private static ConnectorConfig config; - private static EdcClient client; - - @RegisterExtension - static EdcRuntimeExtensionWithTestDatabase providerExtension = new EdcRuntimeExtensionWithTestDatabase( - ":launchers:connectors:sovity-dev", - "provider", - testDatabase -> { - config = forTestDatabase("my-edc-participant-id", testDatabase); - client = EdcClient.builder() - .managementApiUrl(config.getManagementEndpoint().getUri().toString()) - .managementApiKey(config.getProperties().get("edc.api.auth.key")) - .build(); - return config.getProperties(); - } - ); - - @Test - void createTraceXPolicy() { - // arrange - var policyId = UUID.randomUUID().toString(); - var membershipElement = buildAtomicElement("Membership", OperatorDto.EQ, "active"); - var purposeElement = buildAtomicElement("PURPOSE", OperatorDto.EQ, "ID 3.1 Trace"); - var andElement = new Expression() - .expressionType(AND) - .expressions(List.of(membershipElement, purposeElement)); - var permissionDto = new PermissionDto(andElement); - var createRequest = new PolicyCreateRequest(policyId, permissionDto); - - // act - var response = client.useCaseApi().createPolicyDefinitionUseCase(createRequest); - - // assert - assertThat(response.getId()).isEqualTo(policyId); - var policyById = getPolicyById(policyId); - assertThat(policyById).isPresent(); - var policyDefinitionDto = policyById.get(); - assertEquals(policyId, policyDefinitionDto.getPolicyDefinitionId()); - assertPolicyJsonLd(policyDefinitionDto); - } - - private void assertPolicyJsonLd(PolicyDefinitionDto policyDefinitionDto) { - var permission = getPermissionJsonObject(policyDefinitionDto.getPolicy().getPolicyJsonLd()); - var action = permission.get(Prop.Odrl.ACTION); - assertEquals(Prop.Odrl.USE, action.asJsonObject().getString(Prop.Odrl.TYPE)); - - var permissionConstraints = permission.get(Prop.Odrl.CONSTRAINT).asJsonArray(); - assertThat(permissionConstraints).hasSize(1); - var andConstraint = permissionConstraints.get(0).asJsonObject(); - var andConstraints = andConstraint.get(Prop.Odrl.AND).asJsonArray(); - assertThat(andConstraints).hasSize(2); - - var membershipConstraint = andConstraints.get(0).asJsonObject(); - var purposeConstraint = andConstraints.get(1).asJsonObject(); - assertAtomicConstraint(membershipConstraint, "Membership", "active"); - assertAtomicConstraint(purposeConstraint, "PURPOSE", "ID 3.1 Trace"); - } - - private static JsonObject getPermissionJsonObject(String policyJsonLdString) { - var jsonReader = Json.createReader(new StringReader(policyJsonLdString)); - var jsonObject = jsonReader.readObject(); - var permissionList = jsonObject.get(Prop.Odrl.PERMISSION); - return permissionList.asJsonArray().get(0).asJsonObject(); - } - - private void assertAtomicConstraint(JsonObject atomicConstraint, String left, String right) { - var leftOperand = atomicConstraint.getJsonObject(Prop.Odrl.LEFT_OPERAND); - assertEquals(left, leftOperand.getString("@value")); - var rightOperand = atomicConstraint.getJsonObject(Prop.Odrl.RIGHT_OPERAND); - assertEquals(right, rightOperand.getString("@value")); - } - - private Expression buildAtomicElement( - String left, - OperatorDto operator, - String right) { - var atomicConstraint = new AtomicConstraintDto() - .leftExpression(left) - .operator(operator) - .rightExpression(right); - return new Expression() - .expressionType(ATOMIC_CONSTRAINT) - .atomicConstraint(atomicConstraint); - } - - private Optional getPolicyById(String policyId) { - var policyDefinitionsResponse = client.uiApi().getPolicyDefinitionPage(); - return policyDefinitionsResponse.getPolicies().stream() - .filter(policy -> policy.getPolicyDefinitionId().equals(policyId)) - .findFirst(); - } -} diff --git a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java index e8cefe982..4a4dbfd43 100644 --- a/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java +++ b/extensions/wrapper/wrapper/src/test/java/de/sovity/edc/ext/wrapper/api/usecase/UseCaseApiWrapperTest.java @@ -22,7 +22,7 @@ import de.sovity.edc.client.gen.model.CatalogQuery; import de.sovity.edc.client.gen.model.ContractDefinitionRequest; import de.sovity.edc.client.gen.model.DataSourceType; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiCriterion; import de.sovity.edc.client.gen.model.UiCriterionLiteral; @@ -30,7 +30,8 @@ import de.sovity.edc.client.gen.model.UiCriterionOperator; import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; import de.sovity.edc.extension.e2e.db.EdcRuntimeExtensionWithTestDatabase; import de.sovity.edc.extension.utils.junit.DisabledOnGithub; @@ -201,11 +202,11 @@ private void setupAssets() { .mediaType("application/json") .build()).getId(); - policyId = client.uiApi().createPolicyDefinition(PolicyDefinitionCreateRequest.builder() + policyId = client.uiApi().createPolicyDefinitionV2(PolicyDefinitionCreateDto.builder() .policyDefinitionId("policy-1") - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of()) - .build()) + .expression(UiPolicyExpression.builder() + .type(UiPolicyExpressionType.EMPTY) + .build()) .build()).getId(); } } diff --git a/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java b/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java index 436be683b..71143851d 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/ApiWrapperDemoTest.java @@ -21,7 +21,7 @@ import de.sovity.edc.client.gen.model.DataSourceType; import de.sovity.edc.client.gen.model.InitiateTransferRequest; import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiContractNegotiation; import de.sovity.edc.client.gen.model.UiContractOffer; @@ -33,7 +33,8 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyConstraint; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.extension.e2e.connector.ConnectorRemote; @@ -146,32 +147,41 @@ private void createAsset() { } private void createPolicy() { - var afterYesterday = UiPolicyConstraint.builder() - .left("POLICY_EVALUATION_TIME") - .operator(OperatorDto.GT) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(OffsetDateTime.now().minusDays(1).toString()) + var afterYesterday = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.GT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(OffsetDateTime.now().minusDays(1).toString()) + .build()) .build()) .build(); - var beforeTomorrow = UiPolicyConstraint.builder() - .left("POLICY_EVALUATION_TIME") - .operator(OperatorDto.LT) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(OffsetDateTime.now().plusDays(1).toString()) + var beforeTomorrow = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.LT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(OffsetDateTime.now().plusDays(1).toString()) + .build()) .build()) .build(); - var policyDefinition = PolicyDefinitionCreateRequest.builder() + var expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(List.of(afterYesterday, beforeTomorrow)) + .build(); + + var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(dataOfferId) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of(afterYesterday, beforeTomorrow)) - .build()) + .expression(expression) .build(); - providerClient.uiApi().createPolicyDefinition(policyDefinition); + providerClient.uiApi().createPolicyDefinitionV2(policyDefinition); } private void createContractDefinition() { diff --git a/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java b/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java index 9df67d5d7..f0bdd6ea3 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/DataSourceParameterizationTest.java @@ -21,7 +21,7 @@ import de.sovity.edc.client.gen.model.DataSourceType; import de.sovity.edc.client.gen.model.InitiateCustomTransferRequest; import de.sovity.edc.client.gen.model.InitiateTransferRequest; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.TransferHistoryEntry; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiContractNegotiation; @@ -33,7 +33,8 @@ import de.sovity.edc.client.gen.model.UiDataOffer; import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.extension.e2e.connector.ConnectorRemote; import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; import de.sovity.edc.extension.e2e.extension.Consumer; @@ -448,14 +449,14 @@ private String createAssetWithParameterizedMethod(EdcClient providerClient, Test } private void createPolicy(EdcClient providerClient, TestCase testCase) { - var policyDefinition = PolicyDefinitionCreateRequest.builder() + var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(testCase.id) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of()) + .expression(UiPolicyExpression.builder() + .type(UiPolicyExpressionType.EMPTY) .build()) .build(); - providerClient.uiApi().createPolicyDefinition(policyDefinition); + providerClient.uiApi().createPolicyDefinitionV2(policyDefinition); } private String createContractDefinition(EdcClient providerClient, TestCase testCase) { @@ -550,4 +551,5 @@ private String initiateTransferWithParameters( return consumerClient.uiApi().initiateTransfer(transferRequest).getId(); } + } diff --git a/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java b/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java index 9c4e79360..790e0c268 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/UiApiWrapperTest.java @@ -22,7 +22,7 @@ import de.sovity.edc.client.gen.model.InitiateCustomTransferRequest; import de.sovity.edc.client.gen.model.InitiateTransferRequest; import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.TransferProcessSimplifiedState; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiAssetEditRequest; @@ -36,7 +36,8 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyConstraint; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.extension.e2e.connector.ConnectorRemote; @@ -102,20 +103,21 @@ void provide_consume_assetMapping_policyMapping_agreements( var data = "expected data 123"; var yesterday = OffsetDateTime.now().minusDays(1); - var constraintRequest = UiPolicyConstraint.builder() - .left("POLICY_EVALUATION_TIME") - .operator(OperatorDto.GT) - .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(yesterday.toString()) + var expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() + .left("POLICY_EVALUATION_TIME") + .operator(OperatorDto.GT) + .right(UiPolicyLiteral.builder() + .type(UiPolicyLiteralType.STRING) + .value(yesterday.toString()) + .build()) .build()) .build(); - var policyId = providerClient.uiApi().createPolicyDefinition(PolicyDefinitionCreateRequest.builder() + var policyId = providerClient.uiApi().createPolicyDefinitionV2(PolicyDefinitionCreateDto.builder() .policyDefinitionId("policy-1") - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of(constraintRequest)) - .build()) + .expression(expression) .build()).getId(); var dataSource = UiDataSource.builder() @@ -276,8 +278,8 @@ void provide_consume_assetMapping_policyMapping_agreements( assertThat(providerAgreement.getCounterPartyId()).isEqualTo(CONSUMER_PARTICIPANT_ID); assertThat(providerAgreement.getAsset().getAssetId()).isEqualTo(assetId); - var providingContractPolicyConstraint = providerAgreement.getContractPolicy().getConstraints().get(0); - assertThat(providingContractPolicyConstraint).usingRecursiveComparison().isEqualTo(providingContractPolicyConstraint); + var providingContractPolicyConstraint = providerAgreement.getContractPolicy().getExpression(); + assertThat(providingContractPolicyConstraint).usingRecursiveComparison().isEqualTo(expression); assertThat(providerAgreement.getAsset().getAssetId()).isEqualTo(assetId); assertThat(providerAgreement.getAsset().getKeywords()).isEqualTo(List.of("keyword1", "keyword2")); @@ -291,15 +293,15 @@ void provide_consume_assetMapping_policyMapping_agreements( assertThat(consumerAgreement.getCounterPartyId()).isEqualTo(PROVIDER_PARTICIPANT_ID); assertThat(consumerAgreement.getAsset().getAssetId()).isEqualTo(assetId); - var consumingContractPolicyConstraint = consumerAgreement.getContractPolicy().getConstraints().get(0); - assertThat(consumingContractPolicyConstraint).usingRecursiveComparison().isEqualTo(consumingContractPolicyConstraint); + var consumingContractPolicyConstraint = consumerAgreement.getContractPolicy().getExpression(); + assertThat(consumingContractPolicyConstraint).usingRecursiveComparison().isEqualTo(expression); assertThat(consumerAgreement.getAsset().getAssetId()).isEqualTo(assetId); assertThat(consumerAgreement.getAsset().getTitle()).isEqualTo(assetId); // Test Policy - assertThat(contractOffer.getPolicy().getConstraints()).hasSize(1); - var constraint = contractOffer.getPolicy().getConstraints().get(0); + assertThat(contractOffer.getPolicy().getExpression().getType()).isEqualTo(UiPolicyExpressionType.CONSTRAINT); + var constraint = contractOffer.getPolicy().getExpression().getConstraint(); assertThat(constraint.getLeft()).isEqualTo("POLICY_EVALUATION_TIME"); assertThat(constraint.getOperator()).isEqualTo(OperatorDto.GT); assertThat(constraint.getRight().getType()).isEqualTo(UiPolicyLiteralType.STRING); @@ -381,10 +383,10 @@ void customTransferRequest( .build()).getId(); assertThat(assetId).isEqualTo("asset-1"); - var policyId = providerClient.uiApi().createPolicyDefinition(PolicyDefinitionCreateRequest.builder() + var policyId = providerClient.uiApi().createPolicyDefinitionV2(PolicyDefinitionCreateDto.builder() .policyDefinitionId("policy-1") - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of()) + .expression(UiPolicyExpression.builder() + .type(UiPolicyExpressionType.EMPTY) .build()) .build()).getId(); diff --git a/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java index 2e8fa6630..3231fda3d 100644 --- a/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java +++ b/tests/src/test/java/de/sovity/edc/e2e/UseCaseApiWrapperTest.java @@ -23,7 +23,7 @@ import de.sovity.edc.client.gen.model.ContractDefinitionRequest; import de.sovity.edc.client.gen.model.DataSourceType; import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiCriterion; import de.sovity.edc.client.gen.model.UiCriterionLiteral; @@ -32,7 +32,8 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyConstraint; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.extension.e2e.connector.ConnectorRemote; @@ -96,17 +97,19 @@ private CatalogQuery criterion( String rightOperand) { return CatalogQuery.builder() - .connectorEndpoint(getProtocolEndpoint(providerConnector)) - .filterExpressions( - List.of( - CatalogFilterExpression.builder() - .operandLeft(leftOperand) - .operator(operator) - .operandRight(CatalogFilterExpressionLiteral.builder().value(rightOperand).type(CatalogFilterExpressionLiteralType.VALUE).build()) - .build() - ) + .connectorEndpoint(getProtocolEndpoint(providerConnector)) + .filterExpressions( + List.of( + CatalogFilterExpression.builder() + .operandLeft(leftOperand) + .operator(operator) + .operandRight( + CatalogFilterExpressionLiteral.builder().value(rightOperand).type(CatalogFilterExpressionLiteralType.VALUE) + .build()) + .build() ) - .build(); + ) + .build(); } private void createAsset(EdcClient providerClient) { @@ -132,48 +135,57 @@ private void createAsset(EdcClient providerClient) { } private void createPolicy(EdcClient providerClient) { - var afterYesterday = UiPolicyConstraint.builder() + var afterYesterday = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() .left("POLICY_EVALUATION_TIME") .operator(OperatorDto.GT) .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(OffsetDateTime.now().minusDays(1).toString()) - .build()) - .build(); + .type(UiPolicyLiteralType.STRING) + .value(OffsetDateTime.now().minusDays(1).toString()) + .build()) + .build()) + .build(); - var beforeTomorrow = UiPolicyConstraint.builder() + var beforeTomorrow = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(UiPolicyConstraint.builder() .left("POLICY_EVALUATION_TIME") .operator(OperatorDto.LT) .right(UiPolicyLiteral.builder() - .type(UiPolicyLiteralType.STRING) - .value(OffsetDateTime.now().plusDays(1).toString()) - .build()) - .build(); - - var policyDefinition = PolicyDefinitionCreateRequest.builder() - .policyDefinitionId(dataOfferId) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of(afterYesterday, beforeTomorrow)) - .build()) - .build(); - - providerClient.uiApi().createPolicyDefinition(policyDefinition); + .type(UiPolicyLiteralType.STRING) + .value(OffsetDateTime.now().plusDays(1).toString()) + .build()) + .build()) + .build(); + + var expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(List.of(afterYesterday, beforeTomorrow)) + .build(); + + var policyDefinition = PolicyDefinitionCreateDto.builder() + .policyDefinitionId(dataOfferId) + .expression(expression) + .build(); + + providerClient.uiApi().createPolicyDefinitionV2(policyDefinition); } private void createContractDefinition(EdcClient providerClient) { var contractDefinition = ContractDefinitionRequest.builder() - .contractDefinitionId(dataOfferId) - .accessPolicyId(dataOfferId) - .contractPolicyId(dataOfferId) - .assetSelector(List.of(UiCriterion.builder() - .operandLeft(Prop.Edc.ID) - .operator(UiCriterionOperator.EQ) - .operandRight(UiCriterionLiteral.builder() - .type(UiCriterionLiteralType.VALUE) - .value(dataOfferId) - .build()) - .build())) - .build(); + .contractDefinitionId(dataOfferId) + .accessPolicyId(dataOfferId) + .contractPolicyId(dataOfferId) + .assetSelector(List.of(UiCriterion.builder() + .operandLeft(Prop.Edc.ID) + .operator(UiCriterionOperator.EQ) + .operandRight(UiCriterionLiteral.builder() + .type(UiCriterionLiteralType.VALUE) + .value(dataOfferId) + .build()) + .build())) + .build(); providerClient.uiApi().createContractDefinition(contractDefinition); } diff --git a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java index a4bc6317d..346e256e6 100644 --- a/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java +++ b/utils/test-utils/src/main/java/de/sovity/edc/extension/e2e/extension/E2eScenario.java @@ -24,7 +24,7 @@ import de.sovity.edc.client.gen.model.InitiateCustomTransferRequest; import de.sovity.edc.client.gen.model.InitiateTransferRequest; import de.sovity.edc.client.gen.model.OperatorDto; -import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest; +import de.sovity.edc.client.gen.model.PolicyDefinitionCreateDto; import de.sovity.edc.client.gen.model.UiAssetCreateRequest; import de.sovity.edc.client.gen.model.UiContractNegotiation; import de.sovity.edc.client.gen.model.UiCriterion; @@ -34,7 +34,8 @@ import de.sovity.edc.client.gen.model.UiDataSource; import de.sovity.edc.client.gen.model.UiDataSourceHttpData; import de.sovity.edc.client.gen.model.UiPolicyConstraint; -import de.sovity.edc.client.gen.model.UiPolicyCreateRequest; +import de.sovity.edc.client.gen.model.UiPolicyExpression; +import de.sovity.edc.client.gen.model.UiPolicyExpressionType; import de.sovity.edc.client.gen.model.UiPolicyLiteral; import de.sovity.edc.client.gen.model.UiPolicyLiteralType; import de.sovity.edc.extension.e2e.connector.config.ConnectorConfig; @@ -51,6 +52,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; import static de.sovity.edc.client.gen.model.TransferProcessSimplifiedState.RUNNING; import static de.sovity.edc.extension.policy.AlwaysTruePolicyConstants.POLICY_DEFINITION_ID; @@ -144,15 +146,22 @@ public String createPolicyDefinition(String policyId, UiPolicyConstraint... cons } private IdResponseDto createPolicyDefinition(String policyId, List constraints) { - var policyDefinition = PolicyDefinitionCreateRequest.builder() + var expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(constraints.stream() + .map(it -> UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(it) + .build()) + .toList()) + .build(); + + var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(policyId) - .policy(UiPolicyCreateRequest.builder() - .constraints(constraints) - .build() - ) + .expression(expression) .build(); - return providerClient.uiApi().createPolicyDefinition(policyDefinition); + return providerClient.uiApi().createPolicyDefinitionV2(policyDefinition); } public String createContractDefinition(String assetId) { @@ -226,14 +235,22 @@ public void createPolicy(String id, OffsetDateTime from, OffsetDateTime until) { .build()) .build(); - var policyDefinition = PolicyDefinitionCreateRequest.builder() + val expression = UiPolicyExpression.builder() + .type(UiPolicyExpressionType.AND) + .expressions(Stream.of(startConstraint, endConstraint) + .map(it -> UiPolicyExpression.builder() + .type(UiPolicyExpressionType.CONSTRAINT) + .constraint(it) + .build()) + .toList()) + .build(); + + var policyDefinition = PolicyDefinitionCreateDto.builder() .policyDefinitionId(id) - .policy(UiPolicyCreateRequest.builder() - .constraints(List.of(startConstraint, endConstraint)) - .build()) + .expression(expression) .build(); - providerClient.uiApi().createPolicyDefinition(policyDefinition); + providerClient.uiApi().createPolicyDefinitionV2(policyDefinition); } public String transferAndAwait(InitiateTransferRequest transferRequest) {