diff --git a/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformer.java b/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformer.java index 7642802cb03..27dc78aa8ef 100644 --- a/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformer.java +++ b/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformer.java @@ -26,14 +26,12 @@ import java.util.Optional; -import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_DEST_TYPES; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_SOURCE_TYPES; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_TRANSFER_TYPES; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE_TIMESTAMP; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.LAST_ACTIVE; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.PROPERTIES; -import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.TURN_COUNT; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.URL; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; @@ -54,10 +52,8 @@ public JsonObjectFromDataPlaneInstanceTransformer(JsonBuilderFactory jsonFactory .add(ID, dataPlaneInstance.getId()) .add(TYPE, DataPlaneInstance.DATAPLANE_INSTANCE_TYPE) .add(URL, dataPlaneInstance.getUrl().toString()) - .add(LAST_ACTIVE, dataPlaneInstance.getLastActive()) - .add(TURN_COUNT, dataPlaneInstance.getTurnCount()); + .add(LAST_ACTIVE, dataPlaneInstance.getLastActive()); - //properties if (dataPlaneInstance.getProperties() != null && !dataPlaneInstance.getProperties().isEmpty()) { var propBuilder = jsonFactory.createObjectBuilder(); transformProperties(dataPlaneInstance.getProperties(), propBuilder, mapper, context); @@ -67,9 +63,6 @@ public JsonObjectFromDataPlaneInstanceTransformer(JsonBuilderFactory jsonFactory var srcBldr = jsonFactory.createArrayBuilder(dataPlaneInstance.getAllowedSourceTypes()); builder.add(ALLOWED_SOURCE_TYPES, srcBldr); - var dstBldr = jsonFactory.createArrayBuilder(dataPlaneInstance.getAllowedDestTypes()); - builder.add(ALLOWED_DEST_TYPES, dstBldr); - var transferTypesBldr = jsonFactory.createArrayBuilder(dataPlaneInstance.getAllowedTransferTypes()); builder.add(ALLOWED_TRANSFER_TYPES, transferTypesBldr); diff --git a/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceV3Transformer.java b/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceV3Transformer.java new file mode 100644 index 00000000000..57decebe80b --- /dev/null +++ b/core/common/lib/transform-lib/src/main/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceV3Transformer.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.transform.transformer.edc.from; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.json.JsonBuilderFactory; +import jakarta.json.JsonObject; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstanceStates; +import org.eclipse.edc.jsonld.spi.transformer.AbstractJsonLdTransformer; +import org.eclipse.edc.transform.spi.TransformerContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_DEST_TYPES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_SOURCE_TYPES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_TRANSFER_TYPES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE_TIMESTAMP; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.LAST_ACTIVE; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.PROPERTIES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.TURN_COUNT; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.URL; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; + +public class JsonObjectFromDataPlaneInstanceV3Transformer extends AbstractJsonLdTransformer { + private final JsonBuilderFactory jsonFactory; + private final ObjectMapper mapper; + + public JsonObjectFromDataPlaneInstanceV3Transformer(JsonBuilderFactory jsonFactory, ObjectMapper mapper) { + super(DataPlaneInstance.class, JsonObject.class); + this.jsonFactory = jsonFactory; + this.mapper = mapper; + } + + @Override + public @Nullable JsonObject transform(@NotNull DataPlaneInstance dataPlaneInstance, @NotNull TransformerContext context) { + var builder = jsonFactory.createObjectBuilder() + .add(ID, dataPlaneInstance.getId()) + .add(TYPE, DataPlaneInstance.DATAPLANE_INSTANCE_TYPE) + .add(URL, dataPlaneInstance.getUrl().toString()) + .add(LAST_ACTIVE, dataPlaneInstance.getLastActive()) + .add(TURN_COUNT, dataPlaneInstance.getTurnCount()); + + if (dataPlaneInstance.getProperties() != null && !dataPlaneInstance.getProperties().isEmpty()) { + var propBuilder = jsonFactory.createObjectBuilder(); + transformProperties(dataPlaneInstance.getProperties(), propBuilder, mapper, context); + builder.add(PROPERTIES, propBuilder); + } + + var srcBldr = jsonFactory.createArrayBuilder(dataPlaneInstance.getAllowedSourceTypes()); + builder.add(ALLOWED_SOURCE_TYPES, srcBldr); + + var dstBldr = jsonFactory.createArrayBuilder(dataPlaneInstance.getAllowedDestTypes()); + builder.add(ALLOWED_DEST_TYPES, dstBldr); + + var transferTypesBldr = jsonFactory.createArrayBuilder(dataPlaneInstance.getAllowedTransferTypes()); + builder.add(ALLOWED_TRANSFER_TYPES, transferTypesBldr); + + var state = Optional.ofNullable(DataPlaneInstanceStates.from(dataPlaneInstance.getState())) + .map(Enum::name) + .orElse(null); + + addIfNotNull(state, DATAPLANE_INSTANCE_STATE, builder); + + builder.add(DATAPLANE_INSTANCE_STATE_TIMESTAMP, dataPlaneInstance.getStateTimestamp()); + + return builder.build(); + } +} diff --git a/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformerTest.java b/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformerTest.java index 4926563ab1d..024df40d781 100644 --- a/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformerTest.java +++ b/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceTransformerTest.java @@ -24,14 +24,12 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_DEST_TYPES; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_SOURCE_TYPES; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_TRANSFER_TYPES; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE_TIMESTAMP; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.LAST_ACTIVE; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.PROPERTIES; -import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.TURN_COUNT; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.URL; import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstanceStates.AVAILABLE; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; @@ -54,10 +52,8 @@ void transform() { .id("test-id") .url("http://foo.bar") .allowedSourceType("test-source-type") - .allowedDestType("test-dest-type") .allowedTransferType("test-transfer-type") .lastActive(15) - .turnCount(42) .property("foo", "bar") .build(); @@ -67,10 +63,8 @@ void transform() { assertThat(jsonObject.getString(ID)).isEqualTo("test-id"); assertThat(jsonObject.getString(URL)).isEqualTo("http://foo.bar"); assertThat(jsonObject.getJsonArray(ALLOWED_SOURCE_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-source-type")); - assertThat(jsonObject.getJsonArray(ALLOWED_DEST_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-dest-type")); assertThat(jsonObject.getJsonArray(ALLOWED_TRANSFER_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-transfer-type")); assertThat(jsonObject.getJsonNumber(LAST_ACTIVE).intValue()).isEqualTo(15); - assertThat(jsonObject.getJsonNumber(TURN_COUNT).intValue()).isEqualTo(42); assertThat(jsonObject.getJsonObject(PROPERTIES).getJsonString("foo").getString()).isEqualTo("bar"); } @@ -81,10 +75,8 @@ void transform_withState() { .id("test-id") .url("http://foo.bar") .allowedSourceType("test-source-type") - .allowedDestType("test-dest-type") .allowedTransferType("test-transfer-type") .lastActive(15) - .turnCount(42) .state(AVAILABLE.code()) .property("foo", "bar") .build(); @@ -95,10 +87,8 @@ void transform_withState() { assertThat(jsonObject.getString(ID)).isEqualTo("test-id"); assertThat(jsonObject.getString(URL)).isEqualTo("http://foo.bar"); assertThat(jsonObject.getJsonArray(ALLOWED_SOURCE_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-source-type")); - assertThat(jsonObject.getJsonArray(ALLOWED_DEST_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-dest-type")); assertThat(jsonObject.getJsonArray(ALLOWED_TRANSFER_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-transfer-type")); assertThat(jsonObject.getJsonNumber(LAST_ACTIVE).intValue()).isEqualTo(15); - assertThat(jsonObject.getJsonNumber(TURN_COUNT).intValue()).isEqualTo(42); assertThat(jsonObject.getString(DATAPLANE_INSTANCE_STATE)).isEqualTo(AVAILABLE.name()); assertThat(jsonObject.getJsonNumber(DATAPLANE_INSTANCE_STATE_TIMESTAMP).longValue()).isEqualTo(dpi.getStateTimestamp()); assertThat(jsonObject.getJsonObject(PROPERTIES).getJsonString("foo").getString()).isEqualTo("bar"); diff --git a/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceV3TransformerTest.java b/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceV3TransformerTest.java new file mode 100644 index 00000000000..12cf9327921 --- /dev/null +++ b/core/common/lib/transform-lib/src/test/java/org/eclipse/edc/transform/transformer/edc/from/JsonObjectFromDataPlaneInstanceV3TransformerTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.transform.transformer.edc.from; + +import jakarta.json.Json; +import jakarta.json.JsonString; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; +import org.eclipse.edc.transform.spi.TransformerContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_DEST_TYPES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_SOURCE_TYPES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.ALLOWED_TRANSFER_TYPES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_STATE_TIMESTAMP; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.LAST_ACTIVE; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.PROPERTIES; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.TURN_COUNT; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.URL; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstanceStates.AVAILABLE; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.util.JacksonJsonLd.createObjectMapper; +import static org.mockito.Mockito.mock; + +class JsonObjectFromDataPlaneInstanceV3TransformerTest { + + private final TransformerContext context = mock(); + private JsonObjectFromDataPlaneInstanceV3Transformer transformer; + + @BeforeEach + void setUp() { + transformer = new JsonObjectFromDataPlaneInstanceV3Transformer(Json.createBuilderFactory(Map.of()), createObjectMapper()); + } + + @Test + void transform() { + var dpi = DataPlaneInstance.Builder.newInstance() + .id("test-id") + .url("http://foo.bar") + .allowedSourceType("test-source-type") + .allowedDestType("test-dest-type") + .allowedTransferType("test-transfer-type") + .lastActive(15) + .turnCount(42) + .property("foo", "bar") + .build(); + + var jsonObject = transformer.transform(dpi, context); + + assertThat(jsonObject).isNotNull(); + assertThat(jsonObject.getString(ID)).isEqualTo("test-id"); + assertThat(jsonObject.getString(URL)).isEqualTo("http://foo.bar"); + assertThat(jsonObject.getJsonArray(ALLOWED_SOURCE_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-source-type")); + assertThat(jsonObject.getJsonArray(ALLOWED_DEST_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-dest-type")); + assertThat(jsonObject.getJsonArray(ALLOWED_TRANSFER_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-transfer-type")); + assertThat(jsonObject.getJsonNumber(LAST_ACTIVE).intValue()).isEqualTo(15); + assertThat(jsonObject.getJsonNumber(TURN_COUNT).intValue()).isEqualTo(42); + assertThat(jsonObject.getJsonObject(PROPERTIES).getJsonString("foo").getString()).isEqualTo("bar"); + + } + + @Test + void transform_withState() { + var dpi = DataPlaneInstance.Builder.newInstance() + .id("test-id") + .url("http://foo.bar") + .allowedSourceType("test-source-type") + .allowedDestType("test-dest-type") + .allowedTransferType("test-transfer-type") + .lastActive(15) + .turnCount(42) + .state(AVAILABLE.code()) + .property("foo", "bar") + .build(); + + var jsonObject = transformer.transform(dpi, context); + + assertThat(jsonObject).isNotNull(); + assertThat(jsonObject.getString(ID)).isEqualTo("test-id"); + assertThat(jsonObject.getString(URL)).isEqualTo("http://foo.bar"); + assertThat(jsonObject.getJsonArray(ALLOWED_SOURCE_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-source-type")); + assertThat(jsonObject.getJsonArray(ALLOWED_DEST_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-dest-type")); + assertThat(jsonObject.getJsonArray(ALLOWED_TRANSFER_TYPES)).hasSize(1).allMatch(v -> ((JsonString) v).getString().equals("test-transfer-type")); + assertThat(jsonObject.getJsonNumber(LAST_ACTIVE).intValue()).isEqualTo(15); + assertThat(jsonObject.getJsonNumber(TURN_COUNT).intValue()).isEqualTo(42); + assertThat(jsonObject.getString(DATAPLANE_INSTANCE_STATE)).isEqualTo(AVAILABLE.name()); + assertThat(jsonObject.getJsonNumber(DATAPLANE_INSTANCE_STATE_TIMESTAMP).longValue()).isEqualTo(dpi.getStateTimestamp()); + assertThat(jsonObject.getJsonObject(PROPERTIES).getJsonString("foo").getString()).isEqualTo("bar"); + + } +} diff --git a/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json b/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json index 1389c995fd1..7a8bf93746d 100644 --- a/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json +++ b/extensions/common/api/management-api-configuration/src/main/resources/management-api-version.json @@ -1,8 +1,8 @@ [ { - "version": "3.0.4", + "version": "3.0.5", "urlPath": "/v3", - "lastUpdated": "2024-12-19T10:14:00Z", + "lastUpdated": "2025-01-08T14:26:00Z", "maturity": "stable" }, { @@ -14,7 +14,7 @@ { "version": "4.0.0-alpha", "urlPath": "/v4alpha", - "lastUpdated": "2024-12-04T14:24:00Z", + "lastUpdated": "2025-01-08T14:26:00Z", "maturity": "alpha" } ] diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/DataPlaneSelectorApiExtension.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/DataPlaneSelectorApiExtension.java index 310925f8b6b..1da597326ae 100644 --- a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/DataPlaneSelectorApiExtension.java +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/DataPlaneSelectorApiExtension.java @@ -16,9 +16,9 @@ import org.eclipse.edc.connector.dataplane.selector.api.v2.DataplaneSelectorApiV2Controller; import org.eclipse.edc.connector.dataplane.selector.api.v3.DataplaneSelectorApiV3Controller; +import org.eclipse.edc.connector.dataplane.selector.api.v4.DataplaneSelectorApiV4Controller; import org.eclipse.edc.connector.dataplane.selector.api.validation.DataPlaneInstanceValidator; import org.eclipse.edc.connector.dataplane.selector.spi.DataPlaneSelectorService; -import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; import org.eclipse.edc.connector.dataplane.selector.transformer.JsonObjectToSelectionRequestTransformer; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; @@ -27,6 +27,7 @@ import org.eclipse.edc.spi.types.TypeManager; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.eclipse.edc.transform.transformer.edc.from.JsonObjectFromDataPlaneInstanceTransformer; +import org.eclipse.edc.transform.transformer.edc.from.JsonObjectFromDataPlaneInstanceV3Transformer; import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToDataPlaneInstanceTransformer; import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; import org.eclipse.edc.web.spi.WebService; @@ -62,15 +63,22 @@ public class DataPlaneSelectorApiExtension implements ServiceExtension { @Override public void initialize(ServiceExtensionContext context) { - typeManager.registerTypes(DataPlaneInstance.class); - var managementApiTransformerRegistry = transformerRegistry.forContext("management-api"); - + // V2 validatorRegistry.register(DATAPLANE_INSTANCE_TYPE, DataPlaneInstanceValidator.instance()); - managementApiTransformerRegistry.register(new JsonObjectToSelectionRequestTransformer()); - managementApiTransformerRegistry.register(new JsonObjectToDataPlaneInstanceTransformer()); - managementApiTransformerRegistry.register(new JsonObjectFromDataPlaneInstanceTransformer(createBuilderFactory(Map.of()), typeManager.getMapper(JSON_LD))); + var managementApiTransformerRegistryV2 = transformerRegistry.forContext("management-api:v2"); + managementApiTransformerRegistryV2.register(new JsonObjectToSelectionRequestTransformer()); + managementApiTransformerRegistryV2.register(new JsonObjectToDataPlaneInstanceTransformer()); + managementApiTransformerRegistryV2.register(new JsonObjectFromDataPlaneInstanceV3Transformer(createBuilderFactory(Map.of()), typeManager.getMapper(JSON_LD))); + webservice.registerResource(ApiContext.MANAGEMENT, new DataplaneSelectorApiV2Controller(selectionService, managementApiTransformerRegistryV2, validatorRegistry, clock)); + + // V3 + var managementApiTransformerRegistryV3 = transformerRegistry.forContext("management-api:v3"); + managementApiTransformerRegistryV3.register(new JsonObjectFromDataPlaneInstanceV3Transformer(createBuilderFactory(Map.of()), typeManager.getMapper(JSON_LD))); + webservice.registerResource(ApiContext.MANAGEMENT, new DataplaneSelectorApiV3Controller(selectionService, managementApiTransformerRegistryV3)); - webservice.registerResource(ApiContext.MANAGEMENT, new DataplaneSelectorApiV2Controller(selectionService, managementApiTransformerRegistry, validatorRegistry, clock)); - webservice.registerResource(ApiContext.MANAGEMENT, new DataplaneSelectorApiV3Controller(selectionService, managementApiTransformerRegistry)); + // V4 + var managementApiTransformerRegistryV4 = transformerRegistry.forContext("management-api:v4"); + managementApiTransformerRegistryV4.register(new JsonObjectFromDataPlaneInstanceTransformer(createBuilderFactory(Map.of()), typeManager.getMapper(JSON_LD))); + webservice.registerResource(ApiContext.MANAGEMENT, new DataplaneSelectorApiV4Controller(selectionService, managementApiTransformerRegistryV4)); } } diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/schemas/DataPlaneInstanceSchema.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataPlaneInstanceSchemaV2.java similarity index 92% rename from extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/schemas/DataPlaneInstanceSchema.java rename to extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataPlaneInstanceSchemaV2.java index e18dfc2f9a7..e378d86d0ae 100644 --- a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/schemas/DataPlaneInstanceSchema.java +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataPlaneInstanceSchemaV2.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.connector.dataplane.selector.api.schemas; +package org.eclipse.edc.connector.dataplane.selector.api.v2; import io.swagger.v3.oas.annotations.media.Schema; @@ -25,8 +25,8 @@ import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; -@Schema(example = DataPlaneInstanceSchema.DATAPLANE_INSTANCE_EXAMPLE) -public record DataPlaneInstanceSchema( +@Schema(example = DataPlaneInstanceSchemaV2.DATAPLANE_INSTANCE_EXAMPLE) +public record DataPlaneInstanceSchemaV2( @Schema(name = CONTEXT, requiredMode = REQUIRED) Object context, @Schema(name = TYPE, example = DATAPLANE_INSTANCE_TYPE) diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataplaneSelectorApiV2.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataplaneSelectorApiV2.java index d38a696d946..405eb269b56 100644 --- a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataplaneSelectorApiV2.java +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/DataplaneSelectorApiV2.java @@ -28,8 +28,6 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import org.eclipse.edc.api.model.ApiCoreSchema; -import org.eclipse.edc.connector.dataplane.selector.api.schemas.DataPlaneInstanceSchema; -import org.eclipse.edc.connector.dataplane.selector.api.schemas.SelectionRequestSchema; @OpenAPIDefinition(info = @Info(version = "v2")) @Tag(name = "Dataplane Selector V2") @@ -41,7 +39,7 @@ public interface DataplaneSelectorApiV2 { requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = SelectionRequestSchema.class))), responses = { @ApiResponse(responseCode = "200", description = "The DataPlane instance that fits best for the given selection request", - content = @Content(schema = @Schema(implementation = DataPlaneInstanceSchema.class))), + content = @Content(schema = @Schema(implementation = DataPlaneInstanceSchemaV2.class))), @ApiResponse(responseCode = "204", description = "No suitable DataPlane instance was found"), @ApiResponse(responseCode = "400", description = "Request body was malformed", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) @@ -52,7 +50,7 @@ public interface DataplaneSelectorApiV2 { @Operation(method = "POST", description = "Adds one dataplane instance to the internal database of the selector. DEPRECATED: dataplanes should register themselves through control-api", - requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = DataPlaneInstanceSchema.class))), + requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = DataPlaneInstanceSchemaV2.class))), responses = { @ApiResponse(responseCode = "200", description = "Entry was added successfully to the database", content = @Content(schema = @Schema(implementation = ApiCoreSchema.IdResponseSchema.class))), @ApiResponse(responseCode = "400", description = "Request body was malformed", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) @@ -66,7 +64,7 @@ public interface DataplaneSelectorApiV2 { description = "Returns a list of all currently registered data plane instances", responses = { @ApiResponse(responseCode = "200", description = "A (potentially empty) list of currently registered data plane instances", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = DataPlaneInstanceSchema.class)))) + content = @Content(array = @ArraySchema(schema = @Schema(implementation = DataPlaneInstanceSchemaV2.class)))) }, deprecated = true ) diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/schemas/SelectionRequestSchema.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/SelectionRequestSchema.java similarity index 86% rename from extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/schemas/SelectionRequestSchema.java rename to extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/SelectionRequestSchema.java index 67a56b5a5be..e59cb219fcc 100644 --- a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/schemas/SelectionRequestSchema.java +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v2/SelectionRequestSchema.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * Copyright (c) 2024 Cofinity-X * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at @@ -8,11 +8,11 @@ * SPDX-License-Identifier: Apache-2.0 * * Contributors: - * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * Cofinity-X - initial API and implementation * */ -package org.eclipse.edc.connector.dataplane.selector.api.schemas; +package org.eclipse.edc.connector.dataplane.selector.api.v2; import io.swagger.v3.oas.annotations.media.Schema; import org.eclipse.edc.api.model.ApiCoreSchema; diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataPlaneInstanceSchemaV3.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataPlaneInstanceSchemaV3.java new file mode 100644 index 00000000000..e56311708c6 --- /dev/null +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataPlaneInstanceSchemaV3.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.connector.dataplane.selector.api.v3; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.net.URL; +import java.util.Set; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_TYPE; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; + +@Schema(example = DataPlaneInstanceSchemaV3.DATAPLANE_INSTANCE_EXAMPLE) +public record DataPlaneInstanceSchemaV3( + @Schema(name = CONTEXT, requiredMode = REQUIRED) + Object context, + @Schema(name = TYPE, example = DATAPLANE_INSTANCE_TYPE) + String type, + @Schema(name = ID) + String id, + @Schema(requiredMode = REQUIRED) + URL url, + @Schema(requiredMode = REQUIRED) + Set allowedSourceTypes, + @Schema(requiredMode = REQUIRED, deprecated = true) + Set allowedDestTypes, + @Schema(deprecated = true) + Integer turnCount, + Long lastActive, + String state, + Long stateTimestamp) { + public static final String DATAPLANE_INSTANCE_EXAMPLE = """ + { + "@context": { + "@vocab": "https://w3id.org/edc/v0.0.1/ns/" + }, + "@id": "your-dataplane-id", + "url": "http://somewhere.com:1234/api/v1", + "allowedSourceTypes": [ + "source-type1", + "source-type2" + ], + "allowedDestTypes": ["your-dest-type"], + "allowedTransferTypes": ["transfer-type"], + "state": "AVAILABLE", + "stateTimestamp": 1688465655 + } + """; +} diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataplaneSelectorApiV3.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataplaneSelectorApiV3.java index 1ad8e9f5cc5..e79a0036a84 100644 --- a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataplaneSelectorApiV3.java +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataplaneSelectorApiV3.java @@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.json.JsonArray; import jakarta.ws.rs.GET; -import org.eclipse.edc.connector.dataplane.selector.api.schemas.DataPlaneInstanceSchema; @OpenAPIDefinition(info = @Info(version = "v3")) @Tag(name = "Dataplane Selector V3") @@ -34,7 +33,7 @@ public interface DataplaneSelectorApiV3 { description = "Returns a list of all currently registered data plane instances", responses = { @ApiResponse(responseCode = "200", description = "A (potentially empty) list of currently registered data plane instances", - content = @Content(array = @ArraySchema(schema = @Schema(implementation = DataPlaneInstanceSchema.class)))) + content = @Content(array = @ArraySchema(schema = @Schema(implementation = DataPlaneInstanceSchemaV3.class)))) } ) @GET diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneInstanceSchemaV4.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneInstanceSchemaV4.java new file mode 100644 index 00000000000..bfb0307ffa0 --- /dev/null +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneInstanceSchemaV4.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.connector.dataplane.selector.api.v4; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.net.URL; +import java.util.Set; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; +import static org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance.DATAPLANE_INSTANCE_TYPE; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; + +@Schema(example = DataPlaneInstanceSchemaV4.DATAPLANE_INSTANCE_EXAMPLE) +public record DataPlaneInstanceSchemaV4( + @Schema(name = CONTEXT, requiredMode = REQUIRED) + Object context, + @Schema(name = TYPE, example = DATAPLANE_INSTANCE_TYPE) + String type, + @Schema(name = ID) + String id, + @Schema(requiredMode = REQUIRED) + URL url, + @Schema(requiredMode = REQUIRED) + Set allowedSourceTypes, + Long lastActive, + String state, + Long stateTimestamp) { + public static final String DATAPLANE_INSTANCE_EXAMPLE = """ + { + "@context": { + "@vocab": "https://w3id.org/edc/v0.0.1/ns/" + }, + "@id": "your-dataplane-id", + "url": "http://somewhere.com:1234/api/v1", + "allowedSourceTypes": [ + "source-type1", + "source-type2" + ], + "allowedTransferTypes": ["transfer-type"], + "state": "AVAILABLE", + "stateTimestamp": 1688465655 + } + """; +} diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataplaneSelectorApiV4.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataplaneSelectorApiV4.java new file mode 100644 index 00000000000..851ef1241e7 --- /dev/null +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataplaneSelectorApiV4.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.connector.dataplane.selector.api.v4; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.json.JsonArray; +import jakarta.ws.rs.GET; + +@OpenAPIDefinition(info = @Info(version = "v4")) +@Tag(name = "Dataplane Selector V4") +public interface DataplaneSelectorApiV4 { + + @Operation(method = "GET", + description = "Returns a list of all currently registered data plane instances", + responses = { + @ApiResponse(responseCode = "200", description = "A (potentially empty) list of currently registered data plane instances", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = DataPlaneInstanceSchemaV4.class)))) + } + ) + @GET + JsonArray getAllDataPlaneInstancesV4(); + +} diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataplaneSelectorApiV4Controller.java b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataplaneSelectorApiV4Controller.java new file mode 100644 index 00000000000..341de15550a --- /dev/null +++ b/extensions/data-plane-selector/data-plane-selector-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataplaneSelectorApiV4Controller.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.connector.dataplane.selector.api.v4; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.edc.connector.dataplane.selector.spi.DataPlaneSelectorService; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; + +import static jakarta.json.stream.JsonCollectors.toJsonArray; +import static org.eclipse.edc.web.spi.exception.ServiceResultHandler.exceptionMapper; + +@Consumes({ MediaType.APPLICATION_JSON }) +@Produces({ MediaType.APPLICATION_JSON }) +@Path("/v4alpha/dataplanes") +public class DataplaneSelectorApiV4Controller implements DataplaneSelectorApiV4 { + + private final DataPlaneSelectorService selectionService; + private final TypeTransformerRegistry transformerRegistry; + + public DataplaneSelectorApiV4Controller(DataPlaneSelectorService selectionService, TypeTransformerRegistry transformerRegistry) { + this.selectionService = selectionService; + this.transformerRegistry = transformerRegistry; + } + + @Override + @GET + public JsonArray getAllDataPlaneInstancesV4() { + var instances = selectionService.getAll().orElseThrow(exceptionMapper(DataPlaneInstance.class)); + return instances.stream() + .map(i -> transformerRegistry.transform(i, JsonObject.class)) + .filter(Result::succeeded) + .map(Result::getContent) + .collect(toJsonArray()); + } + +} diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/DataPlaneApiSelectorTest.java b/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataPlaneApiSelectorV3Test.java similarity index 71% rename from extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/DataPlaneApiSelectorTest.java rename to extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataPlaneApiSelectorV3Test.java index 1614d846cae..1500c793af2 100644 --- a/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/DataPlaneApiSelectorTest.java +++ b/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v3/DataPlaneApiSelectorV3Test.java @@ -12,12 +12,11 @@ * */ -package org.eclipse.edc.connector.dataplane.selector.api; +package org.eclipse.edc.connector.dataplane.selector.api.v3; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.json.JsonObject; -import org.eclipse.edc.connector.dataplane.selector.api.model.SelectionRequest; import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; import org.eclipse.edc.connector.dataplane.selector.transformer.JsonObjectToSelectionRequestTransformer; import org.eclipse.edc.jsonld.TitaniumJsonLd; @@ -33,11 +32,10 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -import static org.eclipse.edc.connector.dataplane.selector.api.schemas.DataPlaneInstanceSchema.DATAPLANE_INSTANCE_EXAMPLE; -import static org.eclipse.edc.connector.dataplane.selector.api.schemas.SelectionRequestSchema.SELECTION_REQUEST_INPUT_EXAMPLE; +import static org.eclipse.edc.connector.dataplane.selector.api.v3.DataPlaneInstanceSchemaV3.DATAPLANE_INSTANCE_EXAMPLE; import static org.mockito.Mockito.mock; -public class DataPlaneApiSelectorTest { +public class DataPlaneApiSelectorV3Test { private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); private final JsonLd jsonLd = new TitaniumJsonLd(mock()); @@ -70,22 +68,4 @@ void dataPlaneInstanceInputExample() throws JsonProcessingException { }); } - @Test - void selectionRequestInputExample() throws JsonProcessingException { - - var jsonObject = objectMapper.readValue(SELECTION_REQUEST_INPUT_EXAMPLE, JsonObject.class); - assertThat(jsonObject).isNotNull(); - - var expanded = jsonLd.expand(jsonObject); - AbstractResultAssert.assertThat(expanded).isSucceeded() - .extracting(e -> transformer.transform(e, SelectionRequest.class).getContent()) - .isNotNull() - .satisfies(transformed -> { - assertThat(transformed.getStrategy()).isNotBlank(); - assertThat(transformed.getDestination()).isNotNull(); - assertThat(transformed.getSource()).isNotNull(); - assertThat(transformed.getTransferType()).isNotNull(); - }); - } - } diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneApiSelectorV4Test.java b/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneApiSelectorV4Test.java new file mode 100644 index 00000000000..2914906f7d3 --- /dev/null +++ b/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneApiSelectorV4Test.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.connector.dataplane.selector.api.v4; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.json.JsonObject; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; +import org.eclipse.edc.connector.dataplane.selector.transformer.JsonObjectToSelectionRequestTransformer; +import org.eclipse.edc.jsonld.TitaniumJsonLd; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.eclipse.edc.junit.assertions.AbstractResultAssert; +import org.eclipse.edc.transform.TypeTransformerRegistryImpl; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; +import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToDataAddressTransformer; +import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToDataPlaneInstanceTransformer; +import org.eclipse.edc.transform.transformer.edc.to.JsonValueToGenericTypeTransformer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.connector.dataplane.selector.api.v4.DataPlaneInstanceSchemaV4.DATAPLANE_INSTANCE_EXAMPLE; +import static org.mockito.Mockito.mock; + +public class DataPlaneApiSelectorV4Test { + + private final ObjectMapper objectMapper = JacksonJsonLd.createObjectMapper(); + private final JsonLd jsonLd = new TitaniumJsonLd(mock()); + private final TypeTransformerRegistry transformer = new TypeTransformerRegistryImpl(); + + @BeforeEach + void setUp() { + transformer.register(new JsonObjectToDataPlaneInstanceTransformer()); + transformer.register(new JsonObjectToSelectionRequestTransformer()); + transformer.register(new JsonObjectToDataAddressTransformer()); + transformer.register(new JsonValueToGenericTypeTransformer(objectMapper)); + } + + @Test + void dataPlaneInstanceInputExample() throws JsonProcessingException { + + var jsonObject = objectMapper.readValue(DATAPLANE_INSTANCE_EXAMPLE, JsonObject.class); + assertThat(jsonObject).isNotNull(); + + var expanded = jsonLd.expand(jsonObject); + AbstractResultAssert.assertThat(expanded).isSucceeded() + .extracting(e -> transformer.transform(e, DataPlaneInstance.class).getContent()) + .isNotNull() + .satisfies(transformed -> { + assertThat(transformed.getId()).isNotBlank(); + assertThat(transformed.getUrl().toString()).isEqualTo("http://somewhere.com:1234/api/v1"); + assertThat(transformed.getAllowedSourceTypes()).containsExactlyInAnyOrder("source-type1", "source-type2"); + assertThat(transformed.getAllowedTransferTypes()).containsExactlyInAnyOrder("transfer-type"); + }); + } + + +} diff --git a/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneSelectorApiV4ControllerTest.java b/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneSelectorApiV4ControllerTest.java new file mode 100644 index 00000000000..dee8685f058 --- /dev/null +++ b/extensions/data-plane-selector/data-plane-selector-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/api/v4/DataPlaneSelectorApiV4ControllerTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.connector.dataplane.selector.api.v4; + +import io.restassured.specification.RequestSpecification; +import jakarta.json.JsonArray; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.junit.annotations.ApiTest; +import org.eclipse.edc.junit.extensions.RuntimeExtension; +import org.eclipse.edc.junit.extensions.RuntimePerClassExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.List; +import java.util.Map; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.connector.dataplane.selector.TestFunctions.createInstance; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; +import static org.eclipse.edc.util.io.Ports.getFreePort; + +@ApiTest +@ExtendWith(RuntimePerClassExtension.class) +public class DataPlaneSelectorApiV4ControllerTest { + + private final int port = 8181; + + @BeforeEach + void setup(RuntimeExtension extension) { + extension.setConfiguration(Map.of( + "web.http.port", String.valueOf(getFreePort()), + "web.http.management.port", String.valueOf(port), + "web.http.management.path", "/management" + )); + } + + @Test + void getAll(DataPlaneInstanceStore store) { + var list = List.of(createInstance("test-id1"), createInstance("test-id2"), createInstance("test-id3")); + list.forEach(store::save); + + var array = baseRequest() + .get() + .then() + .statusCode(200) + .extract().body().as(JsonArray.class); + + assertThat(array).hasSize(3) + .allSatisfy(jo -> assertThat(jo.asJsonObject().getString(ID)) + .isIn("test-id1", "test-id2", "test-id3")); + } + + @Test + void getAll_noneExist() { + var array = baseRequest() + .get() + .then() + .statusCode(200) + .extract().body().as(JsonArray.class); + + assertThat(array).isNotNull().isEmpty(); + } + + protected RequestSpecification baseRequest() { + return given() + .port(port) + .baseUri("http://localhost:" + port + "/management/v4alpha/dataplanes") + .when(); + } + +} diff --git a/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/instance/DataPlaneInstance.java b/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/instance/DataPlaneInstance.java index 79d94dd6ee1..c74897c8fae 100644 --- a/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/instance/DataPlaneInstance.java +++ b/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/instance/DataPlaneInstance.java @@ -179,6 +179,7 @@ public Builder allowedSourceType(String type) { return this; } + @Deprecated(since = "0.7.0") public Builder allowedDestType(String type) { entity.allowedDestTypes.add(type); return this; @@ -208,6 +209,7 @@ public Builder property(String key, Object value) { return this; } + @Deprecated(since = "0.7.0") public Builder allowedDestTypes(Set types) { entity.allowedDestTypes = types; return this; diff --git a/system-tests/management-api/management-api-test-runner/build.gradle.kts b/system-tests/management-api/management-api-test-runner/build.gradle.kts index 9ac353d78c8..2545ad85e70 100644 --- a/system-tests/management-api/management-api-test-runner/build.gradle.kts +++ b/system-tests/management-api/management-api-test-runner/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { testImplementation(project(":extensions:control-plane:api:management-api:transfer-process-api")) testImplementation(project(":extensions:control-plane:api:management-api:secrets-api")) testImplementation(project(":extensions:control-plane:api:management-api:edr-cache-api")) + testImplementation(project(":extensions:data-plane-selector:data-plane-selector-api")) } edcBuild { diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/DataPlaneSelectorApiEndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/DataPlaneSelectorApiEndToEndTest.java new file mode 100644 index 00000000000..ff8dac297c6 --- /dev/null +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/DataPlaneSelectorApiEndToEndTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * 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: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.test.e2e.managementapi; + +import io.restassured.http.ContentType; +import org.eclipse.edc.connector.dataplane.selector.spi.instance.DataPlaneInstance; +import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore; +import org.eclipse.edc.junit.annotations.EndToEndTest; +import org.eclipse.edc.junit.annotations.PostgresqlIntegrationTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; + +public class DataPlaneSelectorApiEndToEndTest { + + @Nested + @EndToEndTest + @ExtendWith(ManagementEndToEndExtension.InMemory.class) + class InMemory extends Tests { + } + + @Nested + @PostgresqlIntegrationTest + @ExtendWith(ManagementEndToEndExtension.Postgres.class) + class Postgres extends Tests { + } + + private abstract static class Tests { + + @Test + void getAllDataPlaneInstancesV4(ManagementEndToEndTestContext context, DataPlaneInstanceStore store) { + var instance = DataPlaneInstance.Builder.newInstance().url("http://any").build(); + store.save(instance); + + context.baseRequest() + .get("/v4alpha/dataplanes") + .then() + .log().ifValidationFails() + .statusCode(200) + .contentType(ContentType.JSON) + .body("[0].url", equalTo(instance.getUrl().toString())) + .body("[0].allowedDestTypes", nullValue()) + .body("[0].turnCount", nullValue()); + } + + @Test + void getAllDataPlaneInstancesV3(ManagementEndToEndTestContext context, DataPlaneInstanceStore store) { + var instance = DataPlaneInstance.Builder.newInstance().url("http://any").build(); + store.save(instance); + + context.baseRequest() + .get("/v3/dataplanes") + .then() + .log().ifValidationFails() + .statusCode(200) + .contentType(ContentType.JSON) + .body("[0].url", equalTo(instance.getUrl().toString())) + .body("[0].allowedDestTypes", notNullValue()) + .body("[0].turnCount", notNullValue()); + } + } +}