Skip to content

Commit

Permalink
Merge branch 'feature/440246-440246-referring-connector-nuevo-endpoin…
Browse files Browse the repository at this point in the history
…t' into 'develop'

Feature/440246 440246 referring connector nuevo endpoint

See merge request upm-inesdata/inesdata-connector!33
  • Loading branch information
ralconada-gmv committed Aug 12, 2024
2 parents 5403d0a + 795bd69 commit e88a279
Show file tree
Hide file tree
Showing 44 changed files with 1,551 additions and 58 deletions.
4 changes: 4 additions & 0 deletions extensions/complex-policy-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Complex policy definition API

Provides a management API for work with complex policy definitions. This API expands the functionality of the control-plane management API to be able to handle Complex policy definition entities.

30 changes: 30 additions & 0 deletions extensions/complex-policy-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
plugins {
`java-library`
id("com.gmv.inesdata.edc-application")
}

dependencies {
api(libs.edc.spi.core)
implementation(libs.edc.spi.transform)
implementation(libs.edc.web.spi)
implementation(libs.edc.control.plane.aggregate.services)
implementation(libs.edc.policy.definition.api)

implementation(libs.edc.connector.core)
implementation(libs.edc.api.core)
implementation(libs.edc.lib.util)
implementation(libs.edc.lib.transform)
implementation(libs.edc.dsp.api.configuration)
implementation(libs.edc.api.management.config)
implementation(libs.swagger.annotations.jakarta)
implementation(libs.edc.transaction.spi)
implementation(libs.edc.lib.validator)
implementation(libs.edc.validator.spi)
implementation(libs.swagger.annotations.jakarta)
annotationProcessor(libs.lombok)
compileOnly(libs.lombok)
runtimeOnly(libs.edc.spi.jsonld)
runtimeOnly(libs.edc.json.ld.lib)
testAnnotationProcessor(libs.lombok)
testCompileOnly(libs.lombok)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.upm.inesdata.complexpolicy;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.Json;
import org.eclipse.edc.connector.controlplane.api.management.policy.transform.JsonObjectFromPolicyDefinitionTransformer;
import org.eclipse.edc.connector.controlplane.api.management.policy.transform.JsonObjectToPolicyDefinitionTransformer;
import org.eclipse.edc.connector.controlplane.api.management.policy.validation.PolicyDefinitionValidator;
import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
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.validator.spi.JsonObjectValidatorRegistry;
import org.eclipse.edc.web.spi.WebService;
import org.eclipse.edc.web.spi.configuration.ApiContext;
import org.upm.inesdata.complexpolicy.controller.ComplexPolicyDefinitionApiController;
import org.upm.inesdata.complexpolicy.mapper.AtomicConstraintMapper;
import org.upm.inesdata.complexpolicy.mapper.ExpressionExtractor;
import org.upm.inesdata.complexpolicy.mapper.ExpressionMapper;
import org.upm.inesdata.complexpolicy.mapper.LiteralMapper;
import org.upm.inesdata.complexpolicy.mapper.OperatorMapper;
import org.upm.inesdata.complexpolicy.mapper.PolicyMapper;
import org.upm.inesdata.complexpolicy.mapper.PolicyValidator;

import java.util.Map;

import static org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition.EDC_POLICY_DEFINITION_TYPE;
import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD;

/**
* Extension that provides an API for managing complex policy definition
*/
@Extension(value = ComplexPolicyDefinitionApiExtension.NAME)
public class ComplexPolicyDefinitionApiExtension implements ServiceExtension {

public static final String NAME = "Complex policy definition API Extension";

@Inject
private TypeTransformerRegistry transformerRegistry;

@Inject
private WebService webService;

@Inject
private PolicyDefinitionService service;

@Inject
private JsonObjectValidatorRegistry validatorRegistry;

@Inject
private TypeManager typeManager;

@Override
public String name() {
return NAME;
}

@Override
public void initialize(ServiceExtensionContext context) {
var jsonBuilderFactory = Json.createBuilderFactory(Map.of());
var managementApiTransformerRegistry = transformerRegistry.forContext("management-api");
var mapper = typeManager.getMapper(JSON_LD);
managementApiTransformerRegistry.register(new JsonObjectToPolicyDefinitionTransformer());
managementApiTransformerRegistry.register(
new JsonObjectFromPolicyDefinitionTransformer(jsonBuilderFactory, mapper));

validatorRegistry.register(EDC_POLICY_DEFINITION_TYPE, PolicyDefinitionValidator.instance());

var monitor = context.getMonitor();
ExpressionMapper expressionMapper = new ExpressionMapper(
new AtomicConstraintMapper(new LiteralMapper(new ObjectMapper()), new OperatorMapper()));
ExpressionExtractor expressionExtractor = new ExpressionExtractor(new PolicyValidator(), expressionMapper);
PolicyMapper policyMapper = new PolicyMapper(expressionExtractor, expressionMapper, transformerRegistry);

webService.registerResource(ApiContext.MANAGEMENT,
new ComplexPolicyDefinitionApiController(transformerRegistry, service, monitor, validatorRegistry,policyMapper));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.upm.inesdata.complexpolicy.controller;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import org.eclipse.edc.api.model.ApiCoreSchema;
import org.upm.inesdata.complexpolicy.model.PolicyDefinitionCreateDto;

@OpenAPIDefinition(
info = @Info(
version = "v3"
)
)
@Tag(
name = "Complex Policy Definition"
)
public interface ComplexPolicyDefinitionApi {
@Operation(
description = "Creates a new policy definition",
requestBody = @RequestBody(
content = {@Content(
schema = @Schema(
)
)}
),
responses = {@ApiResponse(
responseCode = "200",
description = "policy definition was created successfully. Returns the Policy Definition Id and created timestamp",
content = {@Content(
schema = @Schema(
implementation = ApiCoreSchema.IdResponseSchema.class
)
)}
), @ApiResponse(
responseCode = "400",
description = "Request body was malformed",
content = {@Content(
array = @ArraySchema(
schema = @Schema(
implementation = ApiCoreSchema.ApiErrorDetailSchema.class
)
)
)}
), @ApiResponse(
responseCode = "409",
description = "Could not create policy definition, because a contract definition with that ID already exists",
content = {@Content(
array = @ArraySchema(
schema = @Schema(
implementation = ApiCoreSchema.ApiErrorDetailSchema.class
)
)
)}
)}
)
JsonObject createPolicyDefinitionV3(PolicyDefinitionCreateDto var1);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.upm.inesdata.complexpolicy.controller;

import jakarta.json.JsonObject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.eclipse.edc.api.model.IdResponse;
import org.eclipse.edc.connector.controlplane.policy.spi.PolicyDefinition;
import org.eclipse.edc.connector.controlplane.services.spi.policydefinition.PolicyDefinitionService;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry;
import org.eclipse.edc.web.spi.exception.InvalidRequestException;
import org.upm.inesdata.complexpolicy.mapper.PolicyMapper;
import org.upm.inesdata.complexpolicy.model.PolicyDefinitionCreateDto;
import org.upm.inesdata.complexpolicy.model.UiPolicyExpression;

import static java.lang.String.format;
import static org.eclipse.edc.web.spi.exception.ServiceResultHandler.exceptionMapper;

@Consumes({"application/json"})
@Produces({"application/json"})
@Path("/v3/complexpolicydefinitions")
public class ComplexPolicyDefinitionApiController implements ComplexPolicyDefinitionApi {
private final TypeTransformerRegistry transformerRegistry;
private final PolicyDefinitionService service;
private final Monitor monitor;
private final JsonObjectValidatorRegistry validator;
private final PolicyMapper policyMapper;

public ComplexPolicyDefinitionApiController(TypeTransformerRegistry transformerRegistry,
PolicyDefinitionService service, Monitor monitor, JsonObjectValidatorRegistry validator,
PolicyMapper policyMapper) {
this.transformerRegistry = transformerRegistry;
this.service = service;
this.monitor = monitor;
this.validator = validator;
this.policyMapper = policyMapper;
}

@POST
public JsonObject createPolicyDefinitionV3(PolicyDefinitionCreateDto request) {
/*var expressions = transformerRegistry.transform(request, PolicyDefinitionCreateDto.class)
.orElseThrow(InvalidRequestException::new);*/

var policyDefinition = buildPolicyDefinition(request.getPolicyDefinitionId(), request.getExpression());
var createdDefinition = service.create(policyDefinition)
.onSuccess(d -> monitor.debug(format("Policy Definition created %s", d.getId())))
.orElseThrow(exceptionMapper(PolicyDefinitionCreateDto.class, request.getPolicyDefinitionId()));

var responseDto = IdResponse.Builder.newInstance()
.id(createdDefinition.getId())
.createdAt(createdDefinition.getCreatedAt())
.build();

return transformerRegistry.transform(responseDto, JsonObject.class)
.orElseThrow(f -> new EdcException("Error creating response body: " + f.getFailureDetail()));
}

public PolicyDefinition buildPolicyDefinition(String id, UiPolicyExpression uiPolicyExpression) {
var policy = policyMapper.buildPolicy(uiPolicyExpression);
return PolicyDefinition.Builder.newInstance()
.id(id)
.policy(policy)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.upm.inesdata.complexpolicy.exception;

import org.eclipse.edc.spi.result.Failure;

public class FailedMappingException extends RuntimeException {
public FailedMappingException(String message) {
super(message);
}

public static FailedMappingException ofFailure(Failure failure) {
return new FailedMappingException(failure.getFailureDetail());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.upm.inesdata.complexpolicy.mapper;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.eclipse.edc.policy.model.AtomicConstraint;
import org.eclipse.edc.policy.model.LiteralExpression;
import org.upm.inesdata.complexpolicy.model.OperatorDto;
import org.upm.inesdata.complexpolicy.model.UiPolicyConstraint;

import java.util.Optional;

@RequiredArgsConstructor
public class AtomicConstraintMapper {
private final LiteralMapper literalMapper;
private final OperatorMapper operatorMapper;

/**
* Create ODRL {@link AtomicConstraint} from {@link UiPolicyConstraint}
* <p>
* This operation is lossless.
*
* @param constraint ui constraint
* @return ODRL constraint
*/
public AtomicConstraint buildAtomicConstraint(UiPolicyConstraint constraint) {
var left = constraint.getLeft();
var operator = operatorMapper.getOperator(constraint.getOperator());
var right = literalMapper.getUiLiteralValue(constraint.getRight());

return AtomicConstraint.Builder.newInstance()
.leftExpression(new LiteralExpression(left))
.operator(operator)
.rightExpression(new LiteralExpression(right))
.build();
}


/**
* Create {@link UiPolicyConstraint} from ODRL {@link AtomicConstraint}
* <p>
* This operation is lossy.
*
* @param atomicConstraint atomic contraints
* @param errors errors
* @return ui policy constraint
*/
public Optional<UiPolicyConstraint> buildUiConstraint(
@NonNull AtomicConstraint atomicConstraint,
MappingErrors errors
) {
var leftValue = literalMapper.getExpressionString(atomicConstraint.getLeftExpression(),
errors.forChildObject("leftExpression"));

var operator = getOperator(atomicConstraint, errors);

var rightValue = literalMapper.getExpressionValue(atomicConstraint.getRightExpression(),
errors.forChildObject("rightExpression"));

if (leftValue.isEmpty() || rightValue.isEmpty() || operator.isEmpty()) {
return Optional.empty();
}

UiPolicyConstraint result = UiPolicyConstraint.builder()
.left(leftValue.get())
.operator(operator.get())
.right(rightValue.get())
.build();

return Optional.of(result);
}

private Optional<OperatorDto> getOperator(AtomicConstraint atomicConstraint, MappingErrors errors) {
var operator = atomicConstraint.getOperator();

if (operator == null) {
errors.forChildObject("operator").add("Operator is null.");
return Optional.empty();
}

return Optional.of(operatorMapper.getOperatorDto(operator));
}
}
Loading

0 comments on commit e88a279

Please sign in to comment.