Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ maven/mavencentral/io.netty/netty-tcnative-classes/2.0.56.Final, Apache-2.0, app
maven/mavencentral/io.netty/netty-transport-native-unix-common/4.1.86.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926
maven/mavencentral/io.netty/netty-transport/4.1.86.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926
maven/mavencentral/io.opentelemetry.instrumentation/opentelemetry-instrumentation-annotations/1.32.0, Apache-2.0, approved, #11684
maven/mavencentral/io.opentelemetry.proto/opentelemetry-proto/1.3.1-alpha, None, restricted, #14688
maven/mavencentral/io.opentelemetry.proto/opentelemetry-proto/1.3.1-alpha, Apache-2.0, approved, #14688
maven/mavencentral/io.opentelemetry/opentelemetry-api/1.32.0, Apache-2.0, approved, #11682
maven/mavencentral/io.opentelemetry/opentelemetry-context/1.32.0, Apache-2.0, approved, #11683
maven/mavencentral/io.prometheus/simpleclient/0.16.0, Apache-2.0, approved, clearlydefined
Expand Down 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
Loading