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: clean up ids-api-multipart-endpoint-v1 #1715

Merged
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0ef385c
chore: remove IdsResponseMessageFactory
ronjaquensel Jul 8, 2022
d815e25
chore: remove unused exceptions
ronjaquensel Jul 8, 2022
1ab2fc5
chore: merge response and rejection util classes
ronjaquensel Jul 8, 2022
034dc73
chore: remove class IdsClientCredentialsScope
ronjaquensel Jul 11, 2022
42b1156
chore: do not use description sub-handlers
ronjaquensel Jul 11, 2022
6cfd5d7
chore: remove sub-handler classes
ronjaquensel Jul 12, 2022
5f32658
chore: remove DescriptionRequestHandler interface
ronjaquensel Jul 12, 2022
be3c483
chore: remove DescriptionResponseMessageUtil
ronjaquensel Jul 12, 2022
d90f447
chore: move util classes to util package
ronjaquensel Jul 12, 2022
7582399
chore: add token to all response headers
ronjaquensel Jul 12, 2022
fc11082
chore: add Javadoc to MultipartController
ronjaquensel Jul 12, 2022
1896f7b
chore: move method for building description response to util
ronjaquensel Jul 12, 2022
84f70e5
chore: return RequestInProcessMessage for artifact requests
ronjaquensel Jul 12, 2022
20df603
chore: make response depend on status result from state machine
ronjaquensel Jul 12, 2022
eb07868
chore: do not build message in ArtifactRequestHandler
ronjaquensel Jul 12, 2022
7a05a51
chore: rename DescriptionRequestHandler
ronjaquensel Jul 13, 2022
761f359
chore: align parameter order in ResponseMessageUtil
ronjaquensel Jul 13, 2022
4786e6b
docs: add Javadoc for ResponseMessageUtil
ronjaquensel Jul 13, 2022
5d6651c
chore: remove unused method
ronjaquensel Jul 13, 2022
1344b2d
docs: add Javadoc for MultipartResponseUtil
ronjaquensel Jul 13, 2022
4db8bf7
refactor: remove duplicated methods from handlers
ronjaquensel Jul 18, 2022
83f5e59
refactor: remove MultipartResponseUtil
ronjaquensel Jul 18, 2022
0dad8e2
refactor: process status result in contract handlers
ronjaquensel Jul 18, 2022
62b30c8
refactor: remove notification sub-handlers
ronjaquensel Jul 18, 2022
39fb36c
chore: remove check for connector payload in MultipartController
ronjaquensel Jul 18, 2022
755e5d7
refactor: remove superfluous claim token parameter
ronjaquensel Jul 18, 2022
a61cdf9
refactor: remove internal handle method from DescriptionRequestHandler
ronjaquensel Jul 18, 2022
dea5fcf
docs: add comments and Javadoc
ronjaquensel Jul 19, 2022
199ff97
refactor: make handleRequest in Handler @NotNull
ronjaquensel Jul 19, 2022
0a0b08f
chore: change rejection reason in EDR handler
ronjaquensel Jul 19, 2022
39a9d1d
chore: add required fields to test messages
ronjaquensel Jul 19, 2022
24b2045
test: update handler tests
ronjaquensel Jul 19, 2022
96697d2
test: replace tests for DescriptionRequestHandler
ronjaquensel Jul 19, 2022
2dbcbea
refactor: rename RequestUtil
ronjaquensel Jul 20, 2022
fd28727
chore: only store secret if TP initialized successfully
ronjaquensel Jul 20, 2022
118d3f0
docs: update CHANGELOG.md
ronjaquensel Jul 20, 2022
833f521
test: update ResponseUtilTest
ronjaquensel Jul 20, 2022
189ede4
chore: fix import order
ronjaquensel Jul 20, 2022
ec60ced
chore: fix import order
ronjaquensel Jul 20, 2022
818269e
refactor: return FormDataMultiPart from MultipartController
ronjaquensel Jul 20, 2022
cb3fe43
refactor: return token from method in MultipartController
ronjaquensel Jul 20, 2022
48103c3
chore: remove unused contract offer handler
ronjaquensel Jul 20, 2022
95f3634
chore: remove superfluous requireNonNull checks
ronjaquensel Jul 20, 2022
7f4dfa7
refactor: inject monitor into IdsMultipartApiServiceExtension
ronjaquensel Jul 22, 2022
d7cbdd5
chore: add TODOs for after project structure review
ronjaquensel Jul 22, 2022
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
Prev Previous commit
Next Next commit
docs: add comments and Javadoc
ronjaquensel committed Jul 20, 2022
commit dea5fcf493f3d5e163bdc4dac1c707c4066947e3
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@ public Response request(@FormDataParam(HEADER) InputStream headerInputStream,
return Response.ok(createResponse(malformedMessage(null, connectorId))).build();
}

// Check if any required field missing
// Check if any required header field missing
if (header.getId() == null || header.getIssuerConnector() == null || header.getSenderAgent() == null) {
return Response.ok(createResponse(malformedMessage(header, connectorId))).build();
}
@@ -138,13 +138,15 @@ public Response request(@FormDataParam(HEADER) InputStream headerInputStream,
return Response.ok(createResponse(notAuthenticated(header, connectorId))).build();
}

// Build the multipart request
var claimToken = verificationResult.getContent();
var multipartRequest = MultipartRequest.Builder.newInstance()
.header(header)
.payload(payload)
.claimToken(claimToken)
.build();

// Find handler for the multipart request
var handler = multipartHandlers.stream()
.filter(h -> h.canHandle(multipartRequest))
.findFirst()
Original file line number Diff line number Diff line change
@@ -85,52 +85,59 @@ public boolean canHandle(@NotNull MultipartRequest multipartRequest) {
var claimToken = multipartRequest.getClaimToken();
var message = (ArtifactRequestMessage) multipartRequest.getHeader();

// Validate request artifact ID
var artifactUri = message.getRequestedArtifact();
var artifactIdsId = IdsIdParser.parse(artifactUri.toString());
if (artifactIdsId.getType() != IdsType.ARTIFACT) {
monitor.debug("ArtifactRequestHandler: Requested artifact URI not of type artifact.");
return createMultipartResponse(badParameters(multipartRequest.getHeader(), connectorId));
}

// Validate contract ID
var contractUri = message.getTransferContract();
var contractIdsId = IdsIdParser.parse(contractUri.toString());
if (contractIdsId.getType() != IdsType.CONTRACT) {
monitor.debug("ArtifactRequestHandler: Transfer contract URI not of type contract.");
return createMultipartResponse(badParameters(multipartRequest.getHeader(), connectorId));
}

// Get contract agreement for received contract ID
var contractAgreement = contractNegotiationStore.findContractAgreement(contractIdsId.getValue());
if (contractAgreement == null) {
monitor.debug(String.format("ArtifactRequestHandler: No contract agreement with id %s found.", contractIdsId.getValue()));
return createMultipartResponse(badParameters(multipartRequest.getHeader(), connectorId));
}

// Validate contract agreement
var isContractValid = contractValidationService.validate(claimToken, contractAgreement);
if (!isContractValid) {
monitor.debug("ArtifactRequestHandler: Contract is invalid");
return createMultipartResponse(badParameters(multipartRequest.getHeader(), connectorId));
}

// Verify that contract agreement is valid for requested artifact
if (!artifactIdsId.getValue().equals(contractAgreement.getAssetId())) {
monitor.debug(String.format("ArtifactRequestHandler: invalid artifact id specified %s for contract: %s", artifactIdsId.getValue(), contractIdsId.getValue()));
return createMultipartResponse(badParameters(multipartRequest.getHeader(), connectorId));
}

// Read request payload, which contains the data destination and an optional secret
ArtifactRequestMessagePayload artifactRequestMessagePayload;
try {
artifactRequestMessagePayload =
objectMapper.readValue(multipartRequest.getPayload(), ArtifactRequestMessagePayload.class);
artifactRequestMessagePayload = objectMapper.readValue(multipartRequest.getPayload(), ArtifactRequestMessagePayload.class);
} catch (IOException e) {
return createMultipartResponse(badParameters(multipartRequest.getHeader(), connectorId));
}

var dataAddress = artifactRequestMessagePayload.getDataDestination();
var dataDestination = artifactRequestMessagePayload.getDataDestination();

// Read request message properties
Map<String, String> props = new HashMap<>();
if (message.getProperties() != null) {
message.getProperties().forEach((k, v) -> props.put(k, v.toString()));
}

// Get webhook address of requesting connector from message properties
var idsWebhookAddress = Optional.ofNullable(props.remove(IDS_WEBHOOK_ADDRESS_PROPERTY))
.map(Object::toString)
.orElse(null);
@@ -146,18 +153,19 @@ public boolean canHandle(@NotNull MultipartRequest multipartRequest) {
var dataRequest = DataRequest.Builder.newInstance()
.id(message.getId().toString())
.protocol(Protocols.IDS_MULTIPART)
.dataDestination(dataAddress)
.dataDestination(dataDestination)
.connectorId(connectorId)
.assetId(contractAgreement.getAssetId())
.contractId(contractAgreement.getId())
.properties(props)
.connectorAddress(idsWebhookAddress)
.build();

// Initiate a transfer process for the request
var transferInitiateResult = transferProcessManager.initiateProviderRequest(dataRequest);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for the future (after project structure review), here the TransferProcessService should be used instead of the manager

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, @ronjaquensel, this aligns with our discussion to encapsulate some of the policy evaluation as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ronjaquensel Can we either create an issue or add a TODO for this comment and the one regarding the ContractNegotiationService?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, I added TODOs.


if (artifactRequestMessagePayload.getSecret() != null) {
vault.storeSecret(dataAddress.getKeyName(), artifactRequestMessagePayload.getSecret());
vault.storeSecret(dataDestination.getKeyName(), artifactRequestMessagePayload.getSecret());
}

return createMultipartResponse(inProcessFromStatusResult(transferInitiateResult, multipartRequest.getHeader(), connectorId));
Original file line number Diff line number Diff line change
@@ -89,7 +89,8 @@ public boolean canHandle(@NotNull MultipartRequest multipartRequest) {
monitor.severe("ContractRequestHandler: Contract Request is invalid", e);
return createMultipartResponse(badParameters(message, connectorId));
}


// Get webhook address of requesting connector from message properties
var idsWebhookAddress = message.getProperties().get(IDS_WEBHOOK_ADDRESS_PROPERTY);
if (idsWebhookAddress == null || idsWebhookAddress.toString().isBlank()) {
var msg = "Ids webhook address is invalid";
Original file line number Diff line number Diff line change
@@ -49,7 +49,6 @@
import static org.eclipse.dataspaceconnector.ids.api.multipart.util.ResponseUtil.badParameters;
import static org.eclipse.dataspaceconnector.ids.api.multipart.util.ResponseUtil.descriptionResponse;
import static org.eclipse.dataspaceconnector.ids.api.multipart.util.ResponseUtil.createMultipartResponse;
import static org.eclipse.dataspaceconnector.ids.api.multipart.util.ResponseUtil.messageTypeNotSupported;
import static org.eclipse.dataspaceconnector.ids.api.multipart.util.ResponseUtil.notFound;

public class DescriptionRequestHandler implements Handler {
@@ -92,6 +91,7 @@ public MultipartResponse handleRequest(@NotNull MultipartRequest multipartReques
var claimToken = multipartRequest.getClaimToken();
var message = (DescriptionRequestMessage) multipartRequest.getHeader();

// Get ID of requested element
var requestedElement = message.getRequestedElement();
IdsId idsId = null;
if (requestedElement != null) {
@@ -111,6 +111,7 @@ public MultipartResponse handleRequest(@NotNull MultipartRequest multipartReques
var to = getInt(message, Range.TO, Integer.MAX_VALUE);
var range = new Range(from, to);

// Retrieve and transform requested element
Result<? extends ModelClass> result;
if (idsId == null || (idsId.getType() == IdsType.CONNECTOR)) {
result = getConnector(claimToken, range);
@@ -141,6 +142,15 @@ private Result<Connector> getConnector(ClaimToken claimToken, Range range) {
return transformerRegistry.transform(connectorService.getConnector(claimToken, range), de.fraunhofer.iais.eis.Connector.class);
}

/**
* Retrieves the requested element specified by the IdsId. If the requested element is a
* catalog or resource, the given range is used.
*
* @param idsId the ID.
* @param claimToken the claim token of the requesting connector.
* @param range the range.
* @return the requested element.
*/
private Object retrieveRequestedElement(IdsId idsId, ClaimToken claimToken, Range range) {
var type = idsId.getType();
switch (type) {
@@ -168,6 +178,13 @@ private Object retrieveRequestedElement(IdsId idsId, ClaimToken claimToken, Rang
}
}

/**
* Transforms the requested element as defined by the IdsType.
*
* @param object the object to transform.
* @param type the IDS target type.
* @return the transformation result,
*/
private Result<? extends ModelClass> transformRequestedElement(Object object, IdsType type) {
switch (type) {
case ARTIFACT:
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@ public boolean canHandle(@NotNull MultipartRequest multipartRequest) {
public @Nullable MultipartResponse handleRequest(@NotNull MultipartRequest multipartRequest) {
Objects.requireNonNull(multipartRequest);

// Read and transform the endpoint data reference from the request payload
var edr = typeManager.readValue(multipartRequest.getPayload(), EndpointDataReference.class);
var transformationResult = transformerRegistry.transform(edr);
if (transformationResult.failed()) {
@@ -85,6 +86,7 @@ public boolean canHandle(@NotNull MultipartRequest multipartRequest) {

var transformedEdr = transformationResult.getContent();

// Apply all endpoint data reference receivers to the endpoint data reference
var receiveResult = receiverRegistry.receiveAll(transformedEdr).join();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not for this PR, but joins should be avoided, we should think about making the handlers async to avoid blocking code

if (receiveResult.failed()) {
monitor.severe("EDR dispatch failed: " + String.join(", ", receiveResult.getFailureMessages()));
Original file line number Diff line number Diff line change
@@ -21,6 +21,10 @@

import java.util.Objects;

/**
* Represents an IDS multipart request. Contains the IDS message header, an optional payload and
* the claim token for the requesting connector.
*/
public class MultipartRequest {

private final Message header;
Original file line number Diff line number Diff line change
@@ -20,6 +20,9 @@

import java.util.Objects;

/**
* Represents an IDS multipart response. Contains the IDS message header and an optional payload.
*/
public class MultipartResponse {

private final Message header;