Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/334-backend-ui-api-wrapp…
Browse files Browse the repository at this point in the history
…er-negotiate-contract-endpoint-with-02x' into 2023-09-11-dcat-catalog-service

# Conflicts:
#	extensions/wrapper/client/build.gradle.kts
#	extensions/wrapper/wrapper-common-mappers/build.gradle.kts
#	extensions/wrapper/wrapper-common-mappers/src/main/java/de/sovity/edc/ext/wrapper/api/common/mappers/PolicyMapper.java
#	extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtension.java
#	extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/WrapperExtensionContextBuilder.java
#	extensions/wrapper/wrapper/src/main/java/de/sovity/edc/ext/wrapper/api/ui/UiResource.java
#	utils/test-connector-remote/build.gradle.kts
  • Loading branch information
richardtreier committed Sep 13, 2023
2 parents 83fcdb8 + 0f4b723 commit 0cc386a
Show file tree
Hide file tree
Showing 18 changed files with 573 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* Copyright (c) 2023 sovity GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* sovity GmbH - initial API and implementation
*
*/

package de.sovity.edc.client;

import de.sovity.edc.client.gen.model.ContractNegotiationRequest;
import de.sovity.edc.ext.wrapper.api.common.mappers.PolicyJsonMapper;
import de.sovity.edc.extension.e2e.connector.ConnectorRemote;
import de.sovity.edc.extension.e2e.connector.MockDataAddressRemote;
import jakarta.json.JsonObject;
import org.awaitility.Awaitility;
import org.eclipse.edc.connector.api.management.configuration.transform.ManagementApiTypeTransformerRegistry;
import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl;
import org.eclipse.edc.junit.annotations.ApiTest;
import org.eclipse.edc.junit.extensions.EdcExtension;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.policy.model.PolicyType;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.net.URI;
import java.time.Duration;
import java.util.UUID;

import static de.sovity.edc.extension.e2e.connector.DataTransferTestUtil.validateDataTransferred;
import static de.sovity.edc.extension.e2e.connector.config.ConnectorConfigFactory.basicEdcConfig;
import static de.sovity.edc.extension.e2e.connector.config.ConnectorRemoteConfigFactory.fromConnectorConfig;
import static io.restassured.http.ContentType.JSON;
import static jakarta.json.Json.createObjectBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import static org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates.FINALIZED;
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;
import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE;
import static org.eclipse.edc.spi.CoreConstants.EDC_PREFIX;

@ApiTest
@ExtendWith(EdcExtension.class)
class ContractNegotiationApiServiceTest {


private static final String PROVIDER_PARTICIPANT_ID = "provider";
private static final String CONSUMER_PARTICIPANT_ID = "consumer";
private static final String TEST_BACKEND_TEST_DATA = UUID.randomUUID().toString();

@RegisterExtension
static EdcExtension providerEdcContext = new EdcExtension();
@RegisterExtension
static EdcExtension consumerEdcContext = new EdcExtension();

private ConnectorRemote providerConnector;
private ConnectorRemote consumerConnector;
private MockDataAddressRemote dataAddress;

private EdcClient consumerClient;

@BeforeEach
void setup() {
var providerConfig = basicEdcConfig(PROVIDER_PARTICIPANT_ID, 24000);
providerEdcContext.setConfiguration(providerConfig.getProperties());
providerConnector = new ConnectorRemote(fromConnectorConfig(providerConfig));

var consumerConfig = basicEdcConfig(CONSUMER_PARTICIPANT_ID, 25000);
consumerEdcContext.setConfiguration(consumerConfig.getProperties());
consumerConnector = new ConnectorRemote(fromConnectorConfig(consumerConfig));

consumerClient = EdcClient.builder()
.managementApiUrl(consumerConnector.getConfig().getManagementEndpoint().getUri().toString())
.managementApiKey(consumerConfig.getProperties().get("edc.api.auth.key"))
.build();

// We use the provider EDC as data sink / data source (it has the test-backend-controller extension)
dataAddress = new MockDataAddressRemote(providerConnector.getConfig().getDefaultEndpoint());
}

@Test
void testContractNegotiation__usingManagementApiOnly__todo_remove() {
// arrange
var assetId = UUID.randomUUID().toString();
providerConnector.createDataOffer(assetId, dataAddress.getDataSourceUrl(TEST_BACKEND_TEST_DATA));
String providerId = providerConnector.getParticipantId();
URI providerProtocolApi = providerConnector.getConfig().getProtocolEndpoint().getUri();
JsonObject destination = dataAddress.getDataSinkJsonLd();
var dataset = consumerConnector.getDatasetForAsset(assetId, providerProtocolApi);
var contractId = consumerConnector.getDatasetContractId(dataset);

var policyJsonLd = createObjectBuilder()
.add(CONTEXT, "https://www.w3.org/ns/odrl.jsonld")
.add(TYPE, "use")
.build()
.toString();

// act
var negotiationId = consumerConnector.prepareManagementApiCall()
.contentType(JSON)
.body(createObjectBuilder()
.add(CONTEXT, createObjectBuilder().add(EDC_PREFIX, EDC_NAMESPACE))
.add(TYPE, "NegotiationInitiateRequestDto")
.add("connectorId", providerId)
.add("consumerId", consumerConnector.getParticipantId())
.add("providerId", providerId)
.add("connectorAddress", providerProtocolApi.toString())
.add("protocol", "dataspace-protocol-http")
.add("offer", createObjectBuilder()
.add("offerId", contractId.toString())
.add("assetId", contractId.assetIdPart())
.add("policy", policyJsonLd.toString())
)
.build())
.when()
.post("/v2/contractnegotiations")
.then()
.statusCode(200)
.extract().body().jsonPath().getString(ID);

Awaitility.await().atMost(Duration.ofSeconds(60)).untilAsserted(() -> {
var state = consumerConnector.prepareManagementApiCall()
.contentType(JSON)
.when()
.get("/v2/contractnegotiations/{id}/state", negotiationId)
.then()
.statusCode(200)
.extract().body().jsonPath().getString("'edc:state'");
assertThat(state).isEqualTo(FINALIZED.name());
});

var contractAgreementId = consumerConnector.getContractAgreementId(negotiationId);

// assert
var transferProcessId = consumerConnector.initiateTransfer(
contractAgreementId,
assetId,
providerProtocolApi,
destination);

assertThat(transferProcessId).isNotNull();
validateDataTransferred(dataAddress.getDataSinkSpyUrl(), TEST_BACKEND_TEST_DATA);
}

@Test
void testContractNegotiation() {
// arrange
TypeTransformerRegistry typeTransformerRegistry = providerEdcContext.getContext().getService(ManagementApiTypeTransformerRegistry.class, false);
Policy policy = Policy.Builder.newInstance()
.assigner("sampleAssigner")
.assignee("sampleAssignee")
.target("sampleTarget")
.inheritsFrom("sampleInheritsFrom")
.type(PolicyType.OFFER)
.extensibleProperty("sampleKey", "sampleValue")
.build();
var policyJson = typeTransformerRegistry.transform(policy, JsonObject.class).getContent();
var assetId = UUID.randomUUID().toString();
providerConnector.createDataOffer(assetId, dataAddress.getDataSourceUrl(TEST_BACKEND_TEST_DATA));
String providerId = providerConnector.getParticipantId();
URI providerProtocolApi = providerConnector.getConfig().getProtocolEndpoint().getUri();
JsonObject destination = dataAddress.getDataSinkJsonLd();
var dataset = consumerConnector.getDatasetForAsset(assetId, providerProtocolApi);
var contractId = consumerConnector.getDatasetContractId(dataset);

var contractNegotiationRequest = ContractNegotiationRequest.builder()
.protocol("dataspace-protocol-http")
.counterPartyAddress(providerProtocolApi.toString())
.contractOfferId(contractId.toString())
.assetId(contractId.assetIdPart())
.policyJsonLd(String.valueOf(policyJson))
.build();

// act

var contractNegotiationDto = consumerClient.uiApi().initiateContractNegotiation(contractNegotiationRequest);

Awaitility.await().atMost(Duration.ofSeconds(60)).untilAsserted(() -> {
var state = consumerConnector.prepareManagementApiCall()
.contentType(JSON)
.when()
.get("/v2/contractnegotiations/{id}/state", contractNegotiationDto.getContractNegotiationId())
.then()
.statusCode(200)
.extract().body().jsonPath().getString("'edc:state'");
assertThat(state).isEqualTo(FINALIZED.name());
});


var existingContractNegotiationDto = consumerClient.uiApi().getContractNegotiation(contractNegotiationDto.getContractNegotiationId());
var state = existingContractNegotiationDto.getStatus();


// assert
assertThat(state).isEqualTo(FINALIZED.name());
var transferProcessId = consumerConnector.initiateTransfer(
contractNegotiationDto.getContractAgreementId(),
assetId,
providerProtocolApi,
destination);

assertThat(transferProcessId).isNotNull();
validateDataTransferred(dataAddress.getDataSinkSpyUrl(), TEST_BACKEND_TEST_DATA);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
package de.sovity.edc.client;


import de.sovity.edc.client.gen.model.ContractNegotiationRequest;
import de.sovity.edc.client.gen.model.PolicyDefinitionCreateRequest;
import de.sovity.edc.client.gen.model.PolicyDefinitionDto;
import de.sovity.edc.client.gen.model.UiPolicyConstraint;
import de.sovity.edc.client.gen.model.UiPolicyCreateRequest;
import de.sovity.edc.client.gen.model.UiPolicyLiteral;
import jakarta.json.Json;
import lombok.SneakyThrows;
import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService;
import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService;
import org.eclipse.edc.junit.annotations.ApiTest;
import org.eclipse.edc.junit.extensions.EdcExtension;
Expand All @@ -32,7 +35,10 @@

import java.util.List;

import static jakarta.json.Json.createObjectBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;

@ApiTest
@ExtendWith(EdcExtension.class)
Expand Down
1 change: 1 addition & 0 deletions extensions/wrapper/wrapper-common-mappers/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {
compileOnly("org.projectlombok:lombok:${lombokVersion}")

api("${edcGroup}:policy-model:${edcVersion}")
api("${edcGroup}:transform-core:${edcVersion}")
api("${edcGroup}:core-spi:${edcVersion}")
api("${edcGroup}:transform-spi:${edcVersion}")
api(project(":extensions:wrapper:wrapper-common-api"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package de.sovity.edc.ext.wrapper.api.common.mappers;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.sovity.edc.ext.wrapper.api.common.mappers.utils.AtomicConstraintMapper;
import de.sovity.edc.ext.wrapper.api.common.mappers.utils.ConstraintExtractor;
import de.sovity.edc.ext.wrapper.api.common.mappers.utils.MappingErrors;
import de.sovity.edc.ext.wrapper.api.common.mappers.utils.PolicyValidator;
import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyCreateRequest;
import de.sovity.edc.ext.wrapper.api.common.model.UiPolicyDto;
import jakarta.json.JsonObject;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.eclipse.edc.policy.model.Action;
import org.eclipse.edc.policy.model.Constraint;
import org.eclipse.edc.policy.model.Permission;
import org.eclipse.edc.policy.model.Policy;
import org.eclipse.edc.policy.model.PolicyType;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;

import java.util.ArrayList;

@RequiredArgsConstructor
public class PolicyJsonMapper {
private final TypeTransformerRegistry transformerRegistry;

@SneakyThrows
public Result<JsonObject> getPolicyJsonLd(Policy policy) {
return transformerRegistry.transform(policy, JsonObject.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ public class PolicyMapper {
* @param policy ODRL policy
* @return ui policy
*/
@SneakyThrows
public UiPolicyDto buildUiPolicy(Policy policy) {
MappingErrors errors = MappingErrors.root();

var constraints = constraintExtractor.getPermissionConstraints(policy, errors);

return UiPolicyDto.builder()
.policyJsonLd(jsonLdObjectMapper.writeValueAsString(policy))
.policyJsonLd(getPolicyJsonLd(policy).toString())
.constraints(constraints)
.errors(errors.getErrors())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,13 @@
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.types.TypeManager;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.web.spi.WebService;

import java.time.OffsetDateTime;

import static org.eclipse.edc.spi.CoreConstants.JSON_LD;

public class WrapperExtension implements ServiceExtension {

public static final String EXTENSION_NAME = "WrapperExtension";
Expand Down Expand Up @@ -67,6 +72,9 @@ public class WrapperExtension implements ServiceExtension {
private TransferProcessService transferProcessService;
@Inject
private TransferProcessStore transferProcessStore;

@Inject
private TypeTransformerRegistry transformerRegistry;
@Inject
private TypeManager typeManager;
@Inject
Expand All @@ -86,10 +94,12 @@ public String name() {
}

@Override
@SneakyThrows
public void initialize(ServiceExtensionContext context) {
var objectMapper = typeManager.getMapper(CoreConstants.JSON_LD);
fixObjectMapperDateSerialization(objectMapper);


var wrapperExtensionContext = WrapperExtensionContextBuilder.buildContext(
assetIndex,
assetService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.ContractAgreementPageApiService;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.ContractAgreementTransferApiService;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.ContractDefinitionApiService;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.ContractNegotiationApiService;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.ContractAgreementDataFetcher;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.ContractAgreementPageCardBuilder;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.ContractDefinitionBuilder;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.ContractNegotiationBuilder;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.TransferProcessStateService;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.TransferRequestBuilder;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractAgreementUtils;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractNegotiationUtils;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.ContractOfferMapper;
import de.sovity.edc.ext.wrapper.api.ui.pages.contracts.services.utils.CriterionMapper;
import de.sovity.edc.ext.wrapper.api.ui.pages.policy.PolicyDefinitionApiService;
import de.sovity.edc.ext.wrapper.api.ui.pages.transferhistory.TransferHistoryPageApiService;
Expand Down Expand Up @@ -165,15 +168,19 @@ public static WrapperExtensionContext buildContext(
var dspCatalogService = new DspCatalogService(catalogService, dataOfferBuilder);
var assetMapper = new AssetMapper(typeTransformerRegistry);
var catalogApiService = new CatalogApiService(assetMapper, policyMapper, dspCatalogService);
var contractOfferMapper = new ContractOfferMapper(policyMapper);
var contractNegotiationBuilder = new ContractNegotiationBuilder(contractOfferMapper);
var contractNegotiationApiService = new ContractNegotiationApiService(contractNegotiationService, contractNegotiationBuilder);
var uiResource = new UiResource(
contractAgreementApiService,
contractAgreementTransferApiService,
transferHistoryPageApiService,
transferHistoryPageAssetFetcherService,
assetApiService,
policyDefinitionApiService,
contractDefinitionApiService,
catalogApiService,
contractDefinitionApiService
contractNegotiationApiService
);

// Use Case API
Expand Down
Loading

0 comments on commit 0cc386a

Please sign in to comment.