diff --git a/core/data-plane-selector/data-plane-selector-core/src/main/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorService.java b/core/data-plane-selector/data-plane-selector-core/src/main/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorService.java index 6c8b0814504..d308a66f251 100644 --- a/core/data-plane-selector/data-plane-selector-core/src/main/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorService.java +++ b/core/data-plane-selector/data-plane-selector-core/src/main/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorService.java @@ -68,7 +68,6 @@ public ServiceResult select(DataAddress source, String transf }); } - @Override public ServiceResult addInstance(DataPlaneInstance instance) { return transactionContext.execute(() -> { @@ -86,4 +85,15 @@ public ServiceResult addInstance(DataPlaneInstance instance) { public ServiceResult delete(String instanceId) { return transactionContext.execute(() -> ServiceResult.from(store.deleteById(instanceId))).mapEmpty(); } + + @Override + public ServiceResult findById(String id) { + return transactionContext.execute(() -> { + var instance = store.findById(id); + if (instance == null) { + return ServiceResult.notFound("Data Plane instance with id %s not found".formatted(id)); + } + return ServiceResult.success(instance); + }); + } } diff --git a/core/data-plane-selector/data-plane-selector-core/src/test/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorServiceTest.java b/core/data-plane-selector/data-plane-selector-core/src/test/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorServiceTest.java index 2a6a53e0963..1f2338a2dff 100644 --- a/core/data-plane-selector/data-plane-selector-core/src/test/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorServiceTest.java +++ b/core/data-plane-selector/data-plane-selector-core/src/test/java/org/eclipse/edc/connector/dataplane/selector/service/EmbeddedDataPlaneSelectorServiceTest.java @@ -27,9 +27,9 @@ import org.junit.jupiter.api.Test; import java.util.UUID; -import java.util.stream.IntStream; import java.util.stream.Stream; +import static java.util.stream.IntStream.range; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.eclipse.edc.spi.result.ServiceFailure.Reason.BAD_REQUEST; import static org.eclipse.edc.spi.result.ServiceFailure.Reason.NOT_FOUND; @@ -44,39 +44,47 @@ public class EmbeddedDataPlaneSelectorServiceTest { private final SelectionStrategyRegistry selectionStrategyRegistry = mock(); private final DataPlaneSelectorService service = new EmbeddedDataPlaneSelectorService(store, selectionStrategyRegistry, new NoopTransactionContext()); - @Test - void select_shouldUseChosenSelector() { - var instances = IntStream.range(0, 10).mapToObj(i -> createInstanceMock("instance" + i, "srcTestType", "destTestType")).toList(); - when(store.getAll()).thenReturn(instances.stream()); - SelectionStrategy selectionStrategy = mock(); - when(selectionStrategy.apply(any())).thenAnswer(it -> instances.get(0)); - when(selectionStrategyRegistry.find(any())).thenReturn(selectionStrategy); - - var result = service.select(createAddress("srcTestType"), "transferType", "strategy"); + @Nested + class Select { - assertThat(result).isSucceeded().extracting(DataPlaneInstance::getId).isEqualTo("instance0"); - verify(selectionStrategyRegistry).find("strategy"); - } + @Test + void select_shouldUseChosenSelector() { + var instances = range(0, 10) + .mapToObj(i -> createInstanceBuilder("instance" + i).build()) + .toList(); + when(store.getAll()).thenReturn(instances.stream()); + SelectionStrategy selectionStrategy = mock(); + when(selectionStrategy.apply(any())).thenAnswer(it -> instances.get(0)); + when(selectionStrategyRegistry.find(any())).thenReturn(selectionStrategy); + + var result = service.select(createAddress("srcTestType"), "transferType", "strategy"); + + assertThat(result).isSucceeded().extracting(DataPlaneInstance::getId).isEqualTo("instance0"); + verify(selectionStrategyRegistry).find("strategy"); + } - @Test - void select_shouldReturnBadRequest_whenStrategyNotFound() { - var instances = IntStream.range(0, 10).mapToObj(i -> createInstanceMock("instance" + i, "srcTestType", "destTestType")).toList(); - when(store.getAll()).thenReturn(instances.stream()); - when(selectionStrategyRegistry.find(any())).thenReturn(null); + @Test + void select_shouldReturnBadRequest_whenStrategyNotFound() { + var instances = range(0, 10) + .mapToObj(i -> createInstanceBuilder("instance" + i).build()) + .toList(); + when(store.getAll()).thenReturn(instances.stream()); + when(selectionStrategyRegistry.find(any())).thenReturn(null); - var result = service.select(createAddress("srcTestType"), "transferType", "strategy"); + var result = service.select(createAddress("srcTestType"), "transferType", "strategy"); - assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(BAD_REQUEST); - } + assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(BAD_REQUEST); + } - @Test - void select_shouldReturnNotFound_whenInstanceNotFound() { - when(store.getAll()).thenReturn(Stream.empty()); - when(selectionStrategyRegistry.find(any())).thenReturn(mock()); + @Test + void select_shouldReturnNotFound_whenInstanceNotFound() { + when(store.getAll()).thenReturn(Stream.empty()); + when(selectionStrategyRegistry.find(any())).thenReturn(mock()); - var result = service.select(createAddress("srcTestType"), "transferType", "strategy"); + var result = service.select(createAddress("srcTestType"), "transferType", "strategy"); - assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(NOT_FOUND); + assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(NOT_FOUND); + } } @Nested @@ -105,11 +113,27 @@ void shouldReturnNotFound_whenInstanceIsNotFound() { } - private DataPlaneInstance createInstanceMock(String id, String srcType, String destType) { - return createInstanceBuilder(id) - .allowedSourceType(srcType) - .allowedDestType(destType) - .build(); + @Nested + class FindById { + + @Test + void shouldReturnInstance() { + var instance = createInstanceBuilder("instanceId").build(); + when(store.findById(any())).thenReturn(instance); + + var result = service.findById("instanceId"); + + assertThat(result).isSucceeded().isSameAs(instance); + } + + @Test + void shouldFail_whenInstanceDoesNotExist() { + when(store.findById(any())).thenReturn(null); + + var result = service.findById("any"); + + assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(NOT_FOUND); + } } private DataPlaneInstance.Builder createInstanceBuilder(String id) { diff --git a/extensions/control-plane/transfer/transfer-data-plane-signaling/src/main/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowController.java b/extensions/control-plane/transfer/transfer-data-plane-signaling/src/main/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowController.java index def7667e8af..8b3c6d6a89e 100644 --- a/extensions/control-plane/transfer/transfer-data-plane-signaling/src/main/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowController.java +++ b/extensions/control-plane/transfer/transfer-data-plane-signaling/src/main/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowController.java @@ -110,7 +110,6 @@ public boolean canHandle(TransferProcess transferProcess) { .dataPlaneId(dataPlaneInstance.getId()) .build() ); - } @Override @@ -150,17 +149,10 @@ public Set transferTypesFor(Asset asset) { } private StatusResult getClientForDataplane(String id) { - var result = selectorClient.getAll(); - if (result.failed()) { - return StatusResult.failure(FATAL_ERROR, result.getFailureDetail()); - } - - return result.getContent().stream() - .filter(instance -> instance.getId().equals(id)) - .findFirst() + return selectorClient.findById(id) .map(clientFactory::createClient) .map(StatusResult::success) - .orElseGet(() -> StatusResult.failure(FATAL_ERROR, "No data-plane found with id %s".formatted(id))); + .orElse(f -> StatusResult.failure(FATAL_ERROR, "No data-plane found with id %s. %s".formatted(id, f.getFailureDetail()))); } } diff --git a/extensions/control-plane/transfer/transfer-data-plane-signaling/src/test/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowControllerTest.java b/extensions/control-plane/transfer/transfer-data-plane-signaling/src/test/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowControllerTest.java index 04567ce80e7..d61d840e56a 100644 --- a/extensions/control-plane/transfer/transfer-data-plane-signaling/src/test/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowControllerTest.java +++ b/extensions/control-plane/transfer/transfer-data-plane-signaling/src/test/java/org/eclipse/edc/connector/controlplane/transfer/dataplane/flow/DataPlaneSignalingFlowControllerTest.java @@ -223,7 +223,6 @@ class Terminate { @Test void shouldCallTerminateOnTheRightDataPlane() { var dataPlaneInstance = dataPlaneInstanceBuilder().id("dataPlaneId").build(); - var anotherDataPlane = dataPlaneInstanceBuilder().id("anotherId").build(); var transferProcess = transferProcessBuilder() .id("transferProcessId") .contentDataAddress(testDataAddress()) @@ -231,7 +230,7 @@ void shouldCallTerminateOnTheRightDataPlane() { .build(); when(dataPlaneClient.terminate(any())).thenReturn(StatusResult.success()); when(dataPlaneClientFactory.createClient(any())).thenReturn(dataPlaneClient); - when(selectorService.getAll()).thenReturn(ServiceResult.success(List.of(dataPlaneInstance, anotherDataPlane))); + when(selectorService.findById(any())).thenReturn(ServiceResult.success(dataPlaneInstance)); var result = flowController.terminate(transferProcess); @@ -241,8 +240,7 @@ void shouldCallTerminateOnTheRightDataPlane() { } @Test - void shouldFail_withInvalidDataPlaneId() { - var dataPlaneInstance = createDataPlaneInstance(); + void shouldFail_whenDataPlaneNotFound() { var transferProcess = transferProcessBuilder() .id("transferProcessId") .contentDataAddress(testDataAddress()) @@ -250,26 +248,12 @@ void shouldFail_withInvalidDataPlaneId() { .build(); when(dataPlaneClient.terminate(any())).thenReturn(StatusResult.success()); when(dataPlaneClientFactory.createClient(any())).thenReturn(dataPlaneClient); - when(selectorService.getAll()).thenReturn(ServiceResult.success(List.of(dataPlaneInstance))); + when(selectorService.findById(any())).thenReturn(ServiceResult.notFound("not found")); var result = flowController.terminate(transferProcess); assertThat(result).isFailed().detail().contains("Failed to select the data plane for terminating the transfer process"); } - - @Test - void shouldFail_whenCannotGetDataplaneInstances() { - var transferProcess = transferProcessBuilder() - .id("transferProcessId") - .contentDataAddress(testDataAddress()) - .dataPlaneId("invalid") - .build(); - when(selectorService.getAll()).thenReturn(ServiceResult.unexpected("error")); - - var result = flowController.terminate(transferProcess); - - assertThat(result).isFailed(); - } } @Nested @@ -285,26 +269,7 @@ void shouldCallTerminate() { when(dataPlaneClient.suspend(any())).thenReturn(StatusResult.success()); var dataPlaneInstance = dataPlaneInstanceBuilder().id("dataPlaneId").build(); when(dataPlaneClientFactory.createClient(any())).thenReturn(dataPlaneClient); - when(selectorService.getAll()).thenReturn(ServiceResult.success(List.of(dataPlaneInstance))); - - var result = flowController.suspend(transferProcess); - - assertThat(result).isSucceeded(); - verify(dataPlaneClient).suspend("transferProcessId"); - } - - @Test - void shouldCallSuspendOnTheRightDataPlane() { - var dataPlaneInstance = dataPlaneInstanceBuilder().id("dataPlaneId").build(); - var anotherDataPlane = dataPlaneInstanceBuilder().id("anotherDataPlaneId").build(); - var transferProcess = TransferProcess.Builder.newInstance() - .id("transferProcessId") - .contentDataAddress(testDataAddress()) - .dataPlaneId(dataPlaneInstance.getId()) - .build(); - when(dataPlaneClient.suspend(any())).thenReturn(StatusResult.success()); - when(dataPlaneClientFactory.createClient(any())).thenReturn(dataPlaneClient); - when(selectorService.getAll()).thenReturn(ServiceResult.success(List.of(dataPlaneInstance, anotherDataPlane))); + when(selectorService.findById(any())).thenReturn(ServiceResult.success(dataPlaneInstance)); var result = flowController.suspend(transferProcess); @@ -314,8 +279,7 @@ void shouldCallSuspendOnTheRightDataPlane() { } @Test - void shouldFail_withInvalidDataPlaneId() { - var dataPlaneInstance = createDataPlaneInstance(); + void shouldFail_whenDataPlaneDoesNotExist() { var transferProcess = TransferProcess.Builder.newInstance() .id("transferProcessId") .contentDataAddress(testDataAddress()) @@ -323,26 +287,13 @@ void shouldFail_withInvalidDataPlaneId() { .build(); when(dataPlaneClient.suspend(any())).thenReturn(StatusResult.success()); when(dataPlaneClientFactory.createClient(any())).thenReturn(dataPlaneClient); - when(selectorService.getAll()).thenReturn(ServiceResult.success(List.of(dataPlaneInstance))); + when(selectorService.findById(any())).thenReturn(ServiceResult.notFound("not found")); var result = flowController.suspend(transferProcess); assertThat(result).isFailed().detail().contains("Failed to select the data plane for suspending the transfer process"); } - @Test - void shouldFail_whenCannotGetDataplaneInstances() { - var transferProcess = transferProcessBuilder() - .id("transferProcessId") - .contentDataAddress(testDataAddress()) - .dataPlaneId("invalid") - .build(); - when(selectorService.getAll()).thenReturn(ServiceResult.unexpected("error")); - - var result = flowController.suspend(transferProcess); - - assertThat(result).isFailed(); - } } @Nested diff --git a/extensions/data-plane-selector/data-plane-selector-client/src/main/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorService.java b/extensions/data-plane-selector/data-plane-selector-client/src/main/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorService.java index b9fd6cd48ad..6f9ac465905 100644 --- a/extensions/data-plane-selector/data-plane-selector-client/src/main/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorService.java +++ b/extensions/data-plane-selector/data-plane-selector-client/src/main/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorService.java @@ -69,10 +69,9 @@ public RemoteDataPlaneSelectorService(EdcHttpClient httpClient, String url, Obje @Override public ServiceResult> getAll() { - var builder = new Request.Builder().get().url(url); - authenticationProvider.authenticationHeaders().forEach(builder::header); + var requestBuilder = new Request.Builder().get().url(url); - return request(builder.build()) + return request(requestBuilder) .compose(this::toJsonArray) .map(it -> it.stream() .map(j -> typeTransformerRegistry.transform(j, DataPlaneInstance.class)) @@ -95,10 +94,9 @@ public ServiceResult select(DataAddress source, String transf var body = RequestBody.create(jsonObject.toString(), TYPE_JSON); - var builder = new Request.Builder().post(body).url(url + SELECT_PATH); - authenticationProvider.authenticationHeaders().forEach(builder::header); + var requestBuilder = new Request.Builder().post(body).url(url + SELECT_PATH); - return request(builder.build()).compose(this::toJsonObject) + return request(requestBuilder).compose(this::toJsonObject) .map(it -> typeTransformerRegistry.transform(it, DataPlaneInstance.class)) .compose(ServiceResult::from); } @@ -115,22 +113,30 @@ public ServiceResult addInstance(DataPlaneInstance instance) { .build(); var body = RequestBody.create(requestBody.toString(), TYPE_JSON); - var builder = new Request.Builder().post(body).url(url); - authenticationProvider.authenticationHeaders().forEach(builder::header); + var requestBuilder = new Request.Builder().post(body).url(url); - return request(builder.build()).mapEmpty(); + return request(requestBuilder).mapEmpty(); } @Override public ServiceResult delete(String instanceId) { - var request = new Request.Builder().delete().url(url + "/" + instanceId).build(); + var requestBuilder = new Request.Builder().delete().url(url + "/" + instanceId); - return request(request).mapEmpty(); + return request(requestBuilder).mapEmpty(); } - private ServiceResult request(Request request) { + @Override + public ServiceResult findById(String id) { + var requestBuilder = new Request.Builder().get().url(url + "/" + id); + + return request(requestBuilder).compose(this::toJsonObject) + .map(it -> typeTransformerRegistry.transform(it, DataPlaneInstance.class).getContent()); + } + + private ServiceResult request(Request.Builder requestBuilder) { + authenticationProvider.authenticationHeaders().forEach(requestBuilder::header); try ( - var response = httpClient.execute(request); + var response = httpClient.execute(requestBuilder.build()); var responseBody = response.body(); ) { var bodyAsString = responseBody == null ? null : responseBody.string(); diff --git a/extensions/data-plane-selector/data-plane-selector-client/src/test/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorServiceTest.java b/extensions/data-plane-selector/data-plane-selector-client/src/test/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorServiceTest.java index 363f72f3bf1..0b39298523a 100644 --- a/extensions/data-plane-selector/data-plane-selector-client/src/test/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorServiceTest.java +++ b/extensions/data-plane-selector/data-plane-selector-client/src/test/java/org/eclipse/edc/connector/dataplane/selector/RemoteDataPlaneSelectorServiceTest.java @@ -127,15 +127,40 @@ void shouldFail_whenNotFound() { } } - private DataPlaneInstance createInstance(String id) { - return DataPlaneInstance.Builder.newInstance() - .id(id) - .url("http://somewhere.com:1234/api/v1") - .build(); + @Nested + class FindById { + @Test + void shouldReturnInstanceById() { + var instanceId = UUID.randomUUID().toString(); + var instance = DataPlaneInstance.Builder.newInstance().url("http://any").build(); + when(serverService.findById(any())).thenReturn(ServiceResult.success(instance)); + + var result = service.findById(instanceId); + + assertThat(result).isSucceeded().usingRecursiveComparison().isEqualTo(instance); + verify(authenticationProvider).authenticationHeaders(); + } + + @Test + void shouldReturnNotFound_whenInstanceDoesNotExist() { + var instanceId = UUID.randomUUID().toString(); + when(serverService.findById(any())).thenReturn(ServiceResult.notFound("not found")); + + var result = service.findById(instanceId); + + assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(NOT_FOUND); + } } @Override protected Object controller() { return new DataplaneSelectorControlApiController(validator, typeTransformerRegistry, serverService, Clock.systemUTC()); } + + private DataPlaneInstance createInstance(String id) { + return DataPlaneInstance.Builder.newInstance() + .id(id) + .url("http://somewhere.com:1234/api/v1") + .build(); + } } diff --git a/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApi.java b/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApi.java index c745dde92a1..19813611bda 100644 --- a/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApi.java +++ b/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApi.java @@ -24,9 +24,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.json.JsonArray; import jakarta.json.JsonObject; -import jakarta.ws.rs.GET; import jakarta.ws.rs.HttpMethod; -import jakarta.ws.rs.POST; import org.eclipse.edc.api.model.ApiCoreSchema; import java.net.URL; @@ -55,7 +53,6 @@ public interface DataplaneSelectorControlApi { @ApiResponse(responseCode = "409", description = "Resource already exists", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) }) - @POST JsonObject registerDataplane(JsonObject request); @Operation(method = HttpMethod.DELETE, @@ -69,7 +66,6 @@ public interface DataplaneSelectorControlApi { content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) } ) - @POST void unregisterDataplane(String id); @Operation(method = "POST", @@ -83,7 +79,6 @@ public interface DataplaneSelectorControlApi { @ApiResponse(responseCode = "400", description = "Request body was malformed", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) }) - @POST JsonObject selectDataplane(JsonObject request); @Operation(method = "GET", @@ -94,9 +89,21 @@ public interface DataplaneSelectorControlApi { content = @Content(array = @ArraySchema(schema = @Schema(implementation = DataPlaneInstanceSchema.class)))) } ) - @GET JsonArray getAllDataPlaneInstances(); + + @Operation(method = "GET", + operationId = "findDataPlaneById", + description = "Returns the Data Plane Instance with the specified id.", + responses = { + @ApiResponse(responseCode = "200", description = "The Data Plane Instance", + content = @Content(schema = @Schema(implementation = DataPlaneInstanceSchema.class))), + @ApiResponse(responseCode = "404", description = "Resource not found", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))) + } + ) + JsonObject findDataPlaneById(String id); + @Schema(example = DataPlaneInstanceSchema.DATAPLANE_INSTANCE_EXAMPLE) record DataPlaneInstanceSchema( @Schema(name = CONTEXT, requiredMode = REQUIRED) diff --git a/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiController.java b/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiController.java index 2f00b11d342..151b00e0ec0 100644 --- a/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiController.java +++ b/extensions/data-plane-selector/data-plane-selector-control-api/src/main/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiController.java @@ -18,6 +18,7 @@ import jakarta.json.JsonObject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -100,6 +101,7 @@ public JsonObject selectDataplane(JsonObject request) { } @Override + @GET public JsonArray getAllDataPlaneInstances() { var instances = service.getAll().orElseThrow(exceptionMapper(DataPlaneInstance.class)); @@ -110,4 +112,14 @@ public JsonArray getAllDataPlaneInstances() { .collect(toJsonArray()); } + @Override + @GET + @Path("/{id}") + public JsonObject findDataPlaneById(@PathParam("id") String id) { + var instance = service.findById(id).orElseThrow(exceptionMapper(DataPlaneInstance.class, id)); + + return transformerRegistry.transform(instance, JsonObject.class) + .orElseThrow(f -> new EdcException(f.getFailureDetail())); + } + } diff --git a/extensions/data-plane-selector/data-plane-selector-control-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiControllerTest.java b/extensions/data-plane-selector/data-plane-selector-control-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiControllerTest.java index 1263f1ca1aa..214ba982974 100644 --- a/extensions/data-plane-selector/data-plane-selector-control-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiControllerTest.java +++ b/extensions/data-plane-selector/data-plane-selector-control-api/src/test/java/org/eclipse/edc/connector/dataplane/selector/control/api/DataplaneSelectorControlApiControllerTest.java @@ -324,6 +324,56 @@ void shouldReturnInternalServerError_whenServiceFails() { } } + @Nested + class FindById { + + @Test + void shouldReturnDataPlaneInstance() { + var instance = DataPlaneInstance.Builder.newInstance().url("http://any").build(); + var output = Json.createObjectBuilder().add(ID, "anId").build(); + when(service.findById(any())).thenReturn(ServiceResult.success(instance)); + when(typeTransformerRegistry.transform(any(), any())).thenReturn(Result.success(output)); + + given() + .port(port) + .get("/v1/dataplanes/anId") + .then() + .statusCode(200) + .contentType(JSON) + .body(ID, is("anId")); + + verify(service).findById("anId"); + verify(typeTransformerRegistry).transform(instance, JsonObject.class); + } + + @Test + void shouldReturnNotFound_whenInstanceDoesNotExist() { + when(service.findById(any())).thenReturn(ServiceResult.notFound("not found")); + + given() + .port(port) + .get("/v1/dataplanes/anId") + .then() + .statusCode(404) + .contentType(JSON); + + verifyNoInteractions(typeTransformerRegistry); + } + + @Test + void shouldReturnInternalServerError_whenTransformationFails() { + var instance = DataPlaneInstance.Builder.newInstance().url("http://any").build(); + when(service.findById(any())).thenReturn(ServiceResult.success(instance)); + when(typeTransformerRegistry.transform(any(), any())).thenReturn(Result.failure("an error")); + + given() + .port(port) + .get("/v1/dataplanes/anId") + .then() + .statusCode(500); + } + } + @Override protected Object controller() { return new DataplaneSelectorControlApiController(validatorRegistry, typeTransformerRegistry, service, clock); diff --git a/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/DataPlaneSelectorService.java b/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/DataPlaneSelectorService.java index 02fdbacdb9c..9dabc11da8a 100644 --- a/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/DataPlaneSelectorService.java +++ b/spi/data-plane-selector/data-plane-selector-spi/src/main/java/org/eclipse/edc/connector/dataplane/selector/spi/DataPlaneSelectorService.java @@ -45,6 +45,27 @@ public interface DataPlaneSelectorService { */ ServiceResult select(DataAddress source, String transferType, @Nullable String selectionStrategy); + /** + * Add a data plane instance + */ + ServiceResult addInstance(DataPlaneInstance instance); + + /** + * Delete a Data Plane instance. + * + * @param instanceId the instance id. + * @return successful result if operation completed, failure otherwise. + */ + ServiceResult delete(String instanceId); + + /** + * Find a Data Plane instance by id. + * + * @param id the id. + * @return the {@link DataPlaneInstance} if operation is successful, failure otherwise. + */ + ServiceResult findById(String id); + /** * Selects the {@link DataPlaneInstance} that can handle a source and destination {@link DataAddress} using the configured * strategy. @@ -83,17 +104,5 @@ default DataPlaneInstance select(DataAddress source, DataAddress destination, @N } } - /** - * Add a data plane instance - */ - ServiceResult addInstance(DataPlaneInstance instance); - - /** - * Delete a Data Plane instance. - * - * @param instanceId the instance id. - * @return successful result if operation completed, failure otherwise. - */ - ServiceResult delete(String instanceId); }