Skip to content

Commit

Permalink
Merge pull request #131 from carlos-schmidt/feat/faaast-registry
Browse files Browse the repository at this point in the history
[Feature] Add support for AAS registry
  • Loading branch information
carlos-schmidt authored Aug 26, 2024
2 parents cc115d0 + bb37b75 commit 10dac2e
Show file tree
Hide file tree
Showing 101 changed files with 5,621 additions and 4,281 deletions.
43 changes: 23 additions & 20 deletions README.md

Large diffs are not rendered by default.

38 changes: 37 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,41 @@

## Current development version

Compatibility: **Eclipse Dataspace Connector v0.8.0**
Compatibility: **Eclipse Dataspace Connector v0.8.1**

**New Features**

* AAS registries (spec, example) can now be registered at the extension.
* Add a FA³ST Registry / AAS registry by URL
* The extension reads the shell-/submodel-descriptors and registers assets for their endpoints
* The information (id, idShort, ...) displayed in the self-description comes only from the registry itself, the
service behind the endpoint is not queried
* When a contract is negotiated for one of those elements, the endpoint provided by the
shell-/submodel-descriptor
is used as data source for the data transfer

**Bugfixes**

**Miscellaneous**

* The synchronization of the EDC AssetIndex/ContractStore to the AAS services/registries is updated to a pipeline
architecture.
* The extension does not use custom AAS models for internal persistence any longer
* Instead, the nested structure of the AAS environment is now stored in an 'environment asset'.
* This asset is kept by the extension for the self-description
* Its elements are added to the assetIndex (and contractStore/policyDefinitionStore)
* On AAS environment updates, this nested asset is updated and these updates are propagated to the EDC components as
described above.
* This makes the extension not rely on custom data classes which can be invalidated through an update of AAS or EDC
* It also makes (de)serialization of AAS environments easier
* Updated FA³ST to version v1.1.0
* Updated EDC to version 0.8.1
* Removed custom dependency injection because of transitive dependency issue from FA³ST service
* This was in `example/build.gradle.kts`

## V2.1.1

This version is compatible to **Eclipse Dataspace Connector v0.8.0**

**New Features**

Expand All @@ -25,6 +59,8 @@ Compatibility: **Eclipse Dataspace Connector v0.8.0**
possible
* Unregistering an external AAS service no longer throws IllegalArgumentException
* DataTransfer with AAS DataSource no longer throws IOException: closed
* Test runs on Microsoft's OS no longer fail
* Update older docker example files to support new version of extension

**Miscellaneous**

Expand Down
99 changes: 11 additions & 88 deletions client/src/main/java/de/fraunhofer/iosb/client/ClientEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@
import de.fraunhofer.iosb.client.negotiation.NegotiationController;
import de.fraunhofer.iosb.client.policy.PolicyController;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
Expand All @@ -35,7 +33,6 @@
import org.eclipse.edc.connector.controlplane.contract.spi.types.agreement.ContractAgreement;
import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractRequest;
import org.eclipse.edc.connector.controlplane.contract.spi.types.offer.ContractOffer;
import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.result.Result;
Expand All @@ -59,14 +56,13 @@ public class ClientEndpoint {
* Root path for the client
*/
public static final String AUTOMATED_PATH = "automated";
private static final String ACCEPTED_POLICIES_PATH = "acceptedPolicies";
private static final String OFFER_PATH = "offer";
private static final String NEGOTIATE_CONTRACT_PATH = "negotiateContract";
private static final String NEGOTIATE_PATH = "negotiate";
private static final String TRANSFER_PATH = "transfer";

private static final String MISSING_QUERY_PARAMETER_MESSAGE = "Missing query parameter. Required parameters: %s";
private static final String MISSING_REQUEST_BODY_MESSAGE = "Missing request body of type %s";
public static final String MISSING_QUERY_PARAMETER_MESSAGE = "Missing query parameter. Required parameters: %s";
public static final String MISSING_REQUEST_BODY_MESSAGE = "Missing request body of type %s";

private final Monitor monitor;

Expand Down Expand Up @@ -102,7 +98,7 @@ private ClientEndpoint(Monitor monitor,
@GET
@Path(OFFER_PATH)
public Response getOffer(@QueryParam("providerUrl") URL providerUrl, @QueryParam("assetId") String assetId, @QueryParam("providerId") String counterPartyId) {
monitor.info("[Client] Received an %s GET request".formatted(OFFER_PATH));
monitor.info("GET /%s".formatted(OFFER_PATH));
if (Objects.isNull(assetId) || Objects.isNull(providerUrl)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(MISSING_QUERY_PARAMETER_MESSAGE.formatted("assetId, providerId")).build();
Expand All @@ -112,7 +108,7 @@ public Response getOffer(@QueryParam("providerUrl") URL providerUrl, @QueryParam
try {
dataset = policyController.getDataset(counterPartyId, providerUrl, assetId);
} catch (InterruptedException interruptedException) {
monitor.severe("[Client] Getting offer failed for provider %s and asset %s"
monitor.severe("Getting offer failed for provider %s and asset %s"
.formatted(providerUrl, assetId), interruptedException);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(interruptedException.getMessage())
Expand Down Expand Up @@ -155,7 +151,7 @@ public Response negotiateContract(@QueryParam("providerUrl") URL counterPartyUrl
@QueryParam("providerId") String counterPartyId,
@QueryParam("assetId") String assetId,
DataAddress dataAddress) {
monitor.info("[Client] Received a %s POST request".formatted(NEGOTIATE_PATH));
monitor.info("POST /%s".formatted(NEGOTIATE_PATH));
if (Objects.isNull(counterPartyUrl) || Objects.isNull(counterPartyId) || Objects.isNull(assetId)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(MISSING_QUERY_PARAMETER_MESSAGE.formatted("providerUrl, counterPartyId, assetId")).build();
Expand All @@ -164,7 +160,7 @@ public Response negotiateContract(@QueryParam("providerUrl") URL counterPartyUrl
Result<ContractOffer> contractOfferResult = policyController.getAcceptableContractOfferForAssetId(counterPartyId, counterPartyUrl, assetId);

if (contractOfferResult.failed()) {
monitor.severe("[Client] Getting policies failed for provider %s and asset %s: %s".formatted(
monitor.severe("Getting policies failed for provider %s and asset %s: %s".formatted(
counterPartyUrl, assetId, contractOfferResult.getFailureDetail()));
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(contractOfferResult.getFailureDetail())
Expand All @@ -180,7 +176,7 @@ public Response negotiateContract(@QueryParam("providerUrl") URL counterPartyUrl
Result<ContractAgreement> agreementResult = negotiationController.negotiateContract(contractRequest);

if (agreementResult.failed()) {
monitor.severe("[Client] Negotiation failed for provider %s and contractOffer %s: %s".formatted(
monitor.severe("Negotiation failed for provider %s and contractOffer %s: %s".formatted(
counterPartyUrl, contractOfferResult.getContent().getId(), agreementResult.getFailureDetail()));
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(agreementResult.getFailureDetail()).build();
Expand All @@ -199,7 +195,7 @@ public Response negotiateContract(@QueryParam("providerUrl") URL counterPartyUrl
@POST
@Path(NEGOTIATE_CONTRACT_PATH)
public Response negotiateContract(ContractRequest contractRequest) {
monitor.info("[Client] Received a %s POST request".formatted(NEGOTIATE_CONTRACT_PATH));
monitor.info("POST /%s".formatted(NEGOTIATE_CONTRACT_PATH));
if (Objects.isNull(contractRequest)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(MISSING_REQUEST_BODY_MESSAGE.formatted("ContractRequest")).build();
Expand All @@ -208,7 +204,7 @@ public Response negotiateContract(ContractRequest contractRequest) {
Result<ContractAgreement> agreementResult = negotiationController.negotiateContract(contractRequest);

if (agreementResult.failed()) {
monitor.severe("[Client] Negotiation failed for provider %s and contractOffer %s: %s".formatted(
monitor.severe("Negotiation failed for provider %s and contractOffer %s: %s".formatted(
contractRequest.getProviderId(), contractRequest.getContractOffer().getId(), agreementResult.getFailureDetail()));
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(agreementResult.getFailureDetail()).build();
Expand All @@ -232,7 +228,7 @@ public Response negotiateContract(ContractRequest contractRequest) {
public Response getData(@QueryParam("providerUrl") URL providerUrl,
@QueryParam("agreementId") String agreementId,
DataAddress dataAddress) {
monitor.info("[Client] Received a %s GET request".formatted(TRANSFER_PATH));
monitor.info("GET /%s".formatted(TRANSFER_PATH));
if (Objects.isNull(providerUrl) || Objects.isNull(agreementId)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(MISSING_QUERY_PARAMETER_MESSAGE.formatted("providerUrl, agreementId")).build();
Expand All @@ -246,87 +242,14 @@ public Response getData(@QueryParam("providerUrl") URL providerUrl,
return Response.ok("Data transfer request sent.").build();
}
} catch (InterruptedException | ExecutionException negotiationException) {
monitor.severe("[Client] Data transfer failed for provider %s and agreementId %s".formatted(providerUrl,
monitor.severe("Data transfer failed for provider %s and agreementId %s".formatted(providerUrl,
agreementId), negotiationException);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(negotiationException.getMessage())
.build();
}
}

/**
* Adds an accepted contractOffer to match when checking a provider
* contractOffer. Only the policies' rules are relevant.
*
* @param policyDefinitions accepted policyDefinitions
* @return "OK"-response if requestBody is not empty
*/
@POST
@Path(ACCEPTED_POLICIES_PATH)
public Response addAcceptedPolicyDefinitions(PolicyDefinition[] policyDefinitions) {
monitor.info("[Client] Received a %s POST request".formatted(ACCEPTED_POLICIES_PATH));
if (Objects.isNull(policyDefinitions)) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(MISSING_REQUEST_BODY_MESSAGE.formatted("PolicyDefinition[]")).build();
}

policyController.addAcceptedPolicyDefinitions(policyDefinitions);
return Response.ok().build();
}

/**
* Returns accepted policyDefinitions as list
*
* @return Accepted policyDefinitions list
*/
@GET
@Path(ACCEPTED_POLICIES_PATH)
public Response getAcceptedPolicyDefinitions() {
monitor.info("[Client] Received a %s GET request".formatted(ACCEPTED_POLICIES_PATH));
return Response.ok(policyController.getAcceptedPolicyDefinitions()).build();
}

/**
* Removes an accepted policyDefinitions.
*
* @param policyDefinitionId ID of policyDefinition to be removed
* @return PolicyDefinitionId of removed policyDefinition or 404
*/
@DELETE
@Path(ACCEPTED_POLICIES_PATH)
public Response deleteAcceptedPolicyDefinition(@QueryParam("policyDefinitionId") String policyDefinitionId) {
monitor.info("[Client] Received a %s DELETE request for %s".formatted(ACCEPTED_POLICIES_PATH, policyDefinitionId));
if (Objects.isNull(policyDefinitionId)) {
return Response.status(Response.Status.BAD_REQUEST).entity(MISSING_QUERY_PARAMETER_MESSAGE.formatted("policyDefinitionId")).build();
}

if (policyController.deleteAcceptedPolicyDefinition(policyDefinitionId).isPresent()) {
return Response.ok(policyDefinitionId).build();
}
return Response.status(Response.Status.NOT_FOUND).entity("Unknown policyDefinitionId.").build();
}

/**
* Updates an accepted policyDefinition.
* The policyDefinitionId must match with a stored policyDefinition.
*
* @param policyDefinition Updated policyDefinition
* @return PolicyDefinitionId of updated policyDefinition or 404
*/
@PUT
@Path(ACCEPTED_POLICIES_PATH)
public Response updateAcceptedPolicyDefinition(PolicyDefinition policyDefinition) {
monitor.info("[Client] Received a %s PUT request".formatted(ACCEPTED_POLICIES_PATH));
if (Objects.isNull(policyDefinition)) {
return Response.status(Response.Status.BAD_REQUEST).entity(MISSING_REQUEST_BODY_MESSAGE.formatted("PolicyDefinition")).build();
}

if (policyController.updateAcceptedPolicyDefinition(policyDefinition).isPresent()) {
return Response.ok(policyDefinition.getId()).build();
}
return Response.status(Response.Status.NOT_FOUND).entity("Unknown policyDefinitionId.").build();
}

public static class Builder {
private Monitor monitor;
private NegotiationController negotiationController;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class ClientExtension implements ServiceExtension {

@Override
public void initialize(ServiceExtensionContext context) {
var monitor = context.getMonitor();
var monitor = context.getMonitor().withPrefix("Client");
var config = context.getConfig("edc.client");
registerTransformers();

Expand All @@ -86,6 +86,7 @@ public void initialize(ServiceExtensionContext context) {
transformer,
config);

webService.registerResource(policyController);
webService.registerResource(
ClientEndpoint.Builder.newInstance()
.monitor(monitor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
*/
class TransferInitiator {

public static final String COULD_NOT_BUILD_URI_MESSAGE = "[Client] Could not build own URI, thus cannot transfer data to this EDC. Only data transfers to external endpoints are supported.";
public static final String COULD_NOT_BUILD_URI_MESSAGE = "[Client] Could not build own URI, cannot transfer data to this EDC directly. Only data transfers to external endpoints are supported.";
public static final String HTTPS_KEYSTORE_PATH = "edc.web.https.keystore.path";
public static final String HTTP_PORT = "web.http.port";
public static final String HTTP_PATH = "web.http.path";
Expand Down
Loading

0 comments on commit 10dac2e

Please sign in to comment.