Skip to content

Commit

Permalink
refactor(api): move data plane select functionality to control api (#…
Browse files Browse the repository at this point in the history
…4189)

* refactor(api): move data plane select functionality to control api

* pr remarks
  • Loading branch information
ndr-brt authored May 17, 2024
1 parent 162f5fe commit 0ca80ac
Show file tree
Hide file tree
Showing 36 changed files with 869 additions and 388 deletions.
6 changes: 3 additions & 3 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ maven/mavencentral/javax.ws.rs/javax.ws.rs-api/2.1, (CDDL-1.1 OR GPL-2.0 WITH Cl
maven/mavencentral/joda-time/joda-time/2.10.5, Apache-2.0, approved, clearlydefined
maven/mavencentral/junit/junit/4.13.2, EPL-2.0, approved, CQ23636
maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.14.1, Apache-2.0, approved, #7164
maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.14.12, Apache-2.0, approved, #7164
maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.14.15, Apache-2.0, approved, #7164
maven/mavencentral/net.bytebuddy/byte-buddy/1.14.1, Apache-2.0 AND BSD-3-Clause, approved, #7163
maven/mavencentral/net.bytebuddy/byte-buddy/1.14.11, Apache-2.0 AND BSD-3-Clause, approved, #7163
maven/mavencentral/net.bytebuddy/byte-buddy/1.14.12, Apache-2.0 AND BSD-3-Clause, approved, #7163
maven/mavencentral/net.bytebuddy/byte-buddy/1.14.15, Apache-2.0 AND BSD-3-Clause, approved, #7163
maven/mavencentral/net.java.dev.jna/jna/5.13.0, Apache-2.0 AND LGPL-2.1-or-later, approved, #6709
maven/mavencentral/net.javacrumbs.json-unit/json-unit-core/2.36.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/net.minidev/accessors-smart/2.4.7, Apache-2.0, approved, #7515
Expand Down Expand Up @@ -324,7 +324,7 @@ maven/mavencentral/org.lz4/lz4-java/1.8.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/org.mock-server/mockserver-client-java/5.15.0, Apache-2.0 AND LGPL-3.0-only, approved, #9324
maven/mavencentral/org.mock-server/mockserver-core/5.15.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/org.mock-server/mockserver-netty/5.15.0, Apache-2.0, approved, #9276
maven/mavencentral/org.mockito/mockito-core/5.11.0, MIT AND (Apache-2.0 AND MIT) AND Apache-2.0, approved, #13505
maven/mavencentral/org.mockito/mockito-core/5.12.0, MIT AND (Apache-2.0 AND MIT) AND Apache-2.0, approved, #14678
maven/mavencentral/org.mockito/mockito-core/5.2.0, MIT AND (Apache-2.0 AND MIT) AND Apache-2.0, approved, #7401
maven/mavencentral/org.mockito/mockito-inline/5.2.0, MIT, approved, clearlydefined
maven/mavencentral/org.mozilla/rhino/1.7.7.2, MPL-2.0 AND BSD-3-Clause AND ISC, approved, CQ16320
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies {
implementation(project(":core:common:lib:util-lib"))

testImplementation(testFixtures(project(":spi:data-plane-selector:data-plane-selector-spi")))

testImplementation(project(":core:common:junit"))
}


Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.edc.spi.result.StoreResult;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.transaction.spi.TransactionContext;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.Optional;
Expand All @@ -39,26 +40,30 @@ public EmbeddedDataPlaneSelectorService(DataPlaneInstanceStore store, SelectionS
}

@Override
public List<DataPlaneInstance> getAll() {
public ServiceResult<List<DataPlaneInstance>> getAll() {
return transactionContext.execute(() -> {
try (var stream = store.getAll()) {
return stream.toList();
return ServiceResult.success(stream.toList());
}
});
}

@Override
public DataPlaneInstance select(DataAddress source, DataAddress destination, String selectionStrategy, String transferType) {
public ServiceResult<DataPlaneInstance> select(DataAddress source, String transferType, @Nullable String selectionStrategy) {
var sanitizedSelectionStrategy = Optional.ofNullable(selectionStrategy).orElse(DEFAULT_STRATEGY);
var strategy = selectionStrategyRegistry.find(sanitizedSelectionStrategy);
if (strategy == null) {
throw new IllegalArgumentException("Strategy " + sanitizedSelectionStrategy + " was not found");
return ServiceResult.badRequest("Strategy " + sanitizedSelectionStrategy + " was not found");
}

return transactionContext.execute(() -> {
try (var stream = store.getAll()) {
var dataPlanes = stream.filter(dataPlane -> dataPlane.canHandle(source, transferType)).toList();
return strategy.apply(dataPlanes);
var dataPlane = strategy.apply(dataPlanes);
if (dataPlane == null) {
return ServiceResult.notFound("DataPlane not found");
}
return ServiceResult.success(dataPlane);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@
import org.eclipse.edc.connector.dataplane.selector.spi.store.DataPlaneInstanceStore;
import org.eclipse.edc.connector.dataplane.selector.spi.strategy.SelectionStrategy;
import org.eclipse.edc.connector.dataplane.selector.spi.strategy.SelectionStrategyRegistry;
import org.eclipse.edc.spi.result.ServiceFailure;
import org.eclipse.edc.transaction.spi.NoopTransactionContext;
import org.junit.jupiter.api.Test;

import java.util.stream.IntStream;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.eclipse.edc.connector.dataplane.selector.spi.testfixtures.TestFunctions.createAddress;
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;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
Expand All @@ -46,20 +49,31 @@ void select_shouldUseChosenSelector() {
when(selectionStrategy.apply(any())).thenAnswer(it -> instances.get(0));
when(selectionStrategyRegistry.find(any())).thenReturn(selectionStrategy);

var result = selector.select(createAddress("srcTestType"), createAddress("destTestType"), "strategy", "transferType");
var result = selector.select(createAddress("srcTestType"), "transferType", "strategy");

assertThat(result).isNotNull().extracting(DataPlaneInstance::getId).isEqualTo("instance0");
assertThat(result).isSucceeded().extracting(DataPlaneInstance::getId).isEqualTo("instance0");
verify(selectionStrategyRegistry).find("strategy");
}

@Test
void select_shouldThrowException_whenStrategyNotFound() {
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);

assertThatThrownBy(() -> selector.select(createAddress("srcTestType"), createAddress("destTestType"), "strategy", "transferType"))
.isInstanceOf(IllegalArgumentException.class);
var result = selector.select(createAddress("srcTestType"), "transferType", "strategy");

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());

var result = selector.select(createAddress("srcTestType"), "transferType", "strategy");

assertThat(result).isFailed().extracting(ServiceFailure::getReason).isEqualTo(NOT_FOUND);
}

private DataPlaneInstance createInstanceMock(String id, String srcType, String destType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import io.swagger.v3.oas.annotations.media.Schema;
import org.eclipse.edc.spi.query.SortOrder;
import org.eclipse.edc.spi.types.domain.DataAddress;

import java.util.List;

Expand Down Expand Up @@ -103,4 +104,21 @@ record ApiErrorDetailSchema(
}
""";
}

@Schema(name = "DataAddress", additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
record DataAddressSchema(
@Schema(name = TYPE, example = DataAddress.EDC_DATA_ADDRESS_TYPE)
String type,
@Schema(name = "type")
String typeProperty
) {
public static final String DATA_ADDRESS_EXAMPLE = """
{
"@context": { "@vocab": "https://w3id.org/edc/v0.0.1/ns/" },
"@type": "https://w3id.org/edc/v0.0.1/ns/DataAddress",
"type": "HttpData",
"baseUrl": "http://example.com"
}
""";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonObject;
import org.eclipse.edc.api.validation.DataAddressValidator;
import org.eclipse.edc.jsonld.TitaniumJsonLd;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.jsonld.util.JacksonJsonLd;
import org.eclipse.edc.query.CriterionOperatorRegistryImpl;
import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.CriterionOperatorRegistry;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.transform.TypeTransformerRegistryImpl;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToCriterionTransformer;
import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToDataAddressTransformer;
import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToQuerySpecTransformer;
import org.eclipse.edc.transform.transformer.edc.to.JsonValueToGenericTypeTransformer;
import org.eclipse.edc.validator.jsonobject.validators.model.CriterionValidator;
Expand All @@ -35,7 +38,9 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.map;
import static org.eclipse.edc.api.model.ApiCoreSchema.CriterionSchema.CRITERION_EXAMPLE;
import static org.eclipse.edc.api.model.ApiCoreSchema.DataAddressSchema.DATA_ADDRESS_EXAMPLE;
import static org.eclipse.edc.api.model.ApiCoreSchema.IdResponseSchema.ID_RESPONSE_EXAMPLE;
import static org.eclipse.edc.api.model.ApiCoreSchema.QuerySpecSchema.QUERY_SPEC_EXAMPLE;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
Expand All @@ -54,6 +59,7 @@ void setUp() {
transformer.register(new JsonObjectToQuerySpecTransformer());
transformer.register(new JsonObjectToCriterionTransformer());
transformer.register(new JsonValueToGenericTypeTransformer(objectMapper));
transformer.register(new JsonObjectToDataAddressTransformer());
}

@Test
Expand Down Expand Up @@ -113,4 +119,23 @@ void apiErrorDetailExample() throws JsonProcessingException {
assertThat(apiErrorDetail.getString("path")).isNotBlank();
assertThat(apiErrorDetail.getString("invalidValue")).isNotBlank();
}

@Test
void dataAddressExample() throws JsonProcessingException {
var validator = DataAddressValidator.instance();

var jsonObject = objectMapper.readValue(DATA_ADDRESS_EXAMPLE, JsonObject.class);
assertThat(jsonObject).isNotNull();

var expanded = jsonLd.expand(jsonObject);
assertThat(expanded).isSucceeded()
.satisfies(exp -> assertThat(validator.validate(exp)).isSucceeded())
.extracting(e -> transformer.transform(e, DataAddress.class).getContent())
.isNotNull()
.satisfies(transformed -> {
assertThat(transformed.getType()).isNotBlank();
assertThat(transformed.getProperties()).asInstanceOf(map(String.class, Object.class)).isNotEmpty();
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import io.swagger.v3.oas.annotations.media.Schema;
import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement;
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.spi.types.domain.callback.CallbackAddress;

import java.util.List;
Expand Down Expand Up @@ -79,23 +78,6 @@ record CallbackAddressSchema(

}

@Schema(name = "DataAddress", additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
record DataAddressSchema(
@Schema(name = TYPE, example = DataAddress.EDC_DATA_ADDRESS_TYPE)
String type,
@Schema(name = "type")
String typeProperty
) {
public static final String DATA_ADDRESS_EXAMPLE = """
{
"@context": { "@vocab": "https://w3id.org/edc/v0.0.1/ns/" },
"@type": "https://w3id.org/edc/v0.0.1/ns/DataAddress",
"type": "HttpData",
"baseUrl": "http://example.com"
}
""";
}

@Schema(name = "Properties", additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
record FreeFormPropertiesSchema() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonObject;
import org.eclipse.edc.api.validation.DataAddressValidator;
import org.eclipse.edc.jsonld.JsonLdExtension;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.jsonld.util.JacksonJsonLd;
import org.eclipse.edc.spi.types.domain.DataAddress;
import org.eclipse.edc.transform.TypeTransformerRegistryImpl;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.transform.transformer.edc.to.JsonObjectToDataAddressTransformer;
Expand All @@ -30,10 +28,8 @@
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.map;
import static org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema.ContractAgreementSchema.CONTRACT_AGREEMENT_EXAMPLE;
import static org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema.ContractNegotiationSchema.CONTRACT_NEGOTIATION_EXAMPLE;
import static org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema.DataAddressSchema.DATA_ADDRESS_EXAMPLE;
import static org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema.PolicySchema.POLICY_EXAMPLE;
import static org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement.CONTRACT_AGREEMENT_ASSET_ID;
import static org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement.CONTRACT_AGREEMENT_CONSUMER_ID;
Expand Down Expand Up @@ -106,24 +102,6 @@ void contractNegotiationExample() throws JsonProcessingException {
});
}

@Test
void dataAddressExample() throws JsonProcessingException {
var validator = DataAddressValidator.instance();

var jsonObject = objectMapper.readValue(DATA_ADDRESS_EXAMPLE, JsonObject.class);
assertThat(jsonObject).isNotNull();

var expanded = jsonLd.expand(jsonObject);
assertThat(expanded).isSucceeded()
.satisfies(exp -> assertThat(validator.validate(exp)).isSucceeded())
.extracting(e -> transformer.transform(e, DataAddress.class).getContent())
.isNotNull()
.satisfies(transformed -> {
assertThat(transformed.getType()).isNotBlank();
assertThat(transformed.getProperties()).asInstanceOf(map(String.class, Object.class)).isNotEmpty();
});
}

@Test
void policyExample() throws JsonProcessingException {
var jsonObject = objectMapper.readValue(POLICY_EXAMPLE, JsonObject.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ record AssetInputSchema(
ManagementApiSchema.FreeFormPropertiesSchema properties,
ManagementApiSchema.FreeFormPropertiesSchema privateProperties,
@Schema(requiredMode = REQUIRED)
ManagementApiSchema.DataAddressSchema dataAddress
ApiCoreSchema.DataAddressSchema dataAddress
) {
public static final String ASSET_INPUT_EXAMPLE = """
{
Expand Down Expand Up @@ -142,7 +142,7 @@ record AssetOutputSchema(
String type,
ManagementApiSchema.FreeFormPropertiesSchema properties,
ManagementApiSchema.FreeFormPropertiesSchema privateProperties,
ManagementApiSchema.DataAddressSchema dataAddress,
ApiCoreSchema.DataAddressSchema dataAddress,
long createdAt
) {
public static final String ASSET_OUTPUT_EXAMPLE = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import org.eclipse.edc.api.model.ApiCoreSchema;
import org.eclipse.edc.connector.api.management.configuration.ManagementApiSchema;
import org.eclipse.edc.edr.spi.types.EndpointDataReferenceEntry;

import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID;
Expand All @@ -50,7 +49,7 @@ public interface EdrCacheApi {
@Operation(description = "Gets the EDR data address with the given transfer process ID",
responses = {
@ApiResponse(responseCode = "200", description = "The data address",
content = @Content(schema = @Schema(implementation = ManagementApiSchema.DataAddressSchema.class))),
content = @Content(schema = @Schema(implementation = ApiCoreSchema.DataAddressSchema.class))),
@ApiResponse(responseCode = "400", description = "Request was malformed, e.g. id was null",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiCoreSchema.ApiErrorDetailSchema.class)))),
@ApiResponse(responseCode = "404", description = "An EDR data address with the given transfer process ID does not exist",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ record TransferRequestSchema(
String assetId,
@Schema(requiredMode = REQUIRED)
String transferType,
ManagementApiSchema.DataAddressSchema dataDestination,
ApiCoreSchema.DataAddressSchema dataDestination,
@Schema(additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
ManagementApiSchema.FreeFormPropertiesSchema privateProperties,
List<ManagementApiSchema.CallbackAddressSchema> callbackAddresses) {
Expand Down Expand Up @@ -215,7 +215,7 @@ record TransferProcessSchema(
String state,
String contractAgreementId,
String errorDetail,
ManagementApiSchema.DataAddressSchema dataDestination,
ApiCoreSchema.DataAddressSchema dataDestination,
ManagementApiSchema.FreeFormPropertiesSchema privateProperties,
List<ManagementApiSchema.CallbackAddressSchema> callbackAddresses
) {
Expand Down
Loading

0 comments on commit 0ca80ac

Please sign in to comment.