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

Fix/841 fill bpn in tombstone #863

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b8a3255
chore(quality): [#841] remove obsolete method
dsmf Jul 30, 2024
39780ce
chore(quality): [#841] increase visibility of getRootErrorMessages
dsmf Jul 30, 2024
3cef700
chore(quality): [#841] mark unhandy construction methods as deprecated
dsmf Jul 30, 2024
a95e960
chore(quality): [#841] add bpn and edcUrl attributes to EdcRetrieverE…
dsmf Jul 30, 2024
f2d88aa
chore(quality): [#841] simplify builder for EdcReceiverException
dsmf Jul 31, 2024
543daf6
fix(exception-handling): [#841] Fixes, improvements, test
dsmf Jul 31, 2024
b4def46
Merge branch 'main' into fix/841-fill-bpn-in-tombstone
dsmf Aug 1, 2024
dd74856
chore(quality): [#841] formatting
dsmf Aug 1, 2024
9ea3551
fix(exception-handling): [#841] make constructor private (builder)
dsmf Aug 1, 2024
2fe49e9
fix(exception-handling): [#841] add bpn to validation tombstone
dsmf Aug 1, 2024
7778cc4
fix(exception-handling): [#841] add assertions, improve test readability
dsmf Aug 1, 2024
5290a25
fix(exception-handling): [#841] fix PMD warning
dsmf Aug 1, 2024
7c80642
Merge branch 'main' into fix/841-fill-bpn-in-tombstone
dsmf Aug 1, 2024
1c4ab9e
fix(exception-handling): [#841] remove obsolete todos
dsmf Aug 1, 2024
b6fd328
fix(exception-handling): [#841] fix test
dsmf Aug 1, 2024
6e309ad
fix(exception-handling): [#841] add prepareEmptyCatalog
dsmf Aug 2, 2024
fef51fc
fix(exception-handling): [#841] add successfulDiscovery
dsmf Aug 2, 2024
147f701
fix(exception-handling): [#841] add methods for multiple edc urls
dsmf Aug 2, 2024
d3c8af7
fix(exception-handling): [#841] remove todo
dsmf Aug 2, 2024
d89603b
fix(exception-handling): [#841] add test
dsmf Aug 2, 2024
76d22fa
fix(exception-handling): [#841] add todo
dsmf Aug 2, 2024
d6f6920
fix(exception-handling): [#841] PMD
dsmf Aug 2, 2024
1a6a677
fix(exception-handling): [#841] fix checkstyle warning
dsmf Aug 2, 2024
03a20d2
Merge branch 'main' into fix/841-fill-bpn-in-tombstone
dsmf Aug 2, 2024
3d43c2c
Update irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wir…
dsmf Aug 2, 2024
5ed2f89
fix(exception-handling): [#841] improve test
dsmf Aug 2, 2024
a5453f9
Merge remote-tracking branch 'origin/fix/841-fill-bpn-in-tombstone' i…
dsmf Aug 2, 2024
13a23e6
fix(exception-handling): [#841] fix compile error
dsmf Aug 2, 2024
e947268
fix(exception-handling): [#841] add changelog entry
dsmf Aug 2, 2024
bbe6fef
fix(exception-handling): [#841] use unused method
dsmf Aug 2, 2024
5715943
fix(exception-handling): [#841] resolve todo
dsmf Aug 2, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha
in some remaining code places (in context of #794).
- Fixed flaky test `InMemoryJobStoreTest.checkLastModifiedOnAfterCreation()` (PR#857).
- Fixed occasion where completed Job callbacks are called multiple times. #755
- BPN and endpointURL(s) are set in the tombstone now. #841

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ protected SubmodelDescriptor requestSubmodel(final EdcSubmodelFacade submodelFac
private SubmodelDescriptor getSubmodel(final EdcSubmodelFacade submodelFacade,
final Endpoint digitalTwinRegistryEndpoint, final List<String> connectorEndpoints, final String bpn)
throws EdcClientException {

for (final String connectorEndpoint : connectorEndpoints) {
try {
return submodelFacade.getSubmodelPayload(connectorEndpoint,
Expand All @@ -118,6 +119,7 @@ private SubmodelDescriptor getSubmodel(final EdcSubmodelFacade submodelFacade,
log.info("EdcClientException while accessing digitalTwinRegistryEndpoint '{}'", connectorEndpoint, e);
}
}

throw new EdcClientException(
String.format("Called %s connectorEndpoints but did not get any submodels. Connectors: '%s'",
connectorEndpoints.size(), String.join(", ", connectorEndpoints)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.eclipse.tractusx.irs.registryclient.DigitalTwinRegistryKey;
import org.eclipse.tractusx.irs.registryclient.DigitalTwinRegistryService;
import org.eclipse.tractusx.irs.registryclient.exceptions.RegistryServiceException;
import org.eclipse.tractusx.irs.registryclient.exceptions.ShellNotFoundException;

/**
* Retrieves AAShell from Digital Twin Registry service and storing it inside {@link ItemContainer}.
Expand Down Expand Up @@ -72,22 +73,24 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai
final var dtrKeys = List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn()));
final var shells = digitalTwinRegistryService.fetchShells(dtrKeys);
final var shell = shells.stream()
// we use findFirst here, because we query only for one
// DigitalTwinRegistryKey here
.map(Either::getOrNull)
.filter(Objects::nonNull)
.findFirst()
.orElseThrow(() -> shellNotFound(shells));
// we use findFirst here, because we query only for one
// DigitalTwinRegistryKey here
.map(Either::getOrNull)
.filter(Objects::nonNull)
.findFirst()
.orElseThrow(() -> shellNotFound(shells));

itemContainerBuilder.shell(
jobData.isAuditContractNegotiation() ? shell : shell.withoutContractAgreementId());

} catch (final ShellNotFoundException e) {
log.info("Shell not found for item: {}. Creating Tombstone.", itemId);
createShellNotFoundTombstone(itemContainerBuilder, itemId, e);
} catch (final RegistryServiceException | RuntimeException e) {
// catching generic exception is intended here,
// otherwise Jobs stay in state RUNNING forever
log.info("Shell Endpoint could not be retrieved for Item: {}. Creating Tombstone.", itemId);
itemContainerBuilder.tombstone(
Tombstone.from(itemId.getGlobalAssetId(), null, e, e.getSuppressed(), retryCount,
ProcessStep.DIGITAL_TWIN_REQUEST));
log.info("Shell could not be retrieved for item: {}. Creating Tombstone.", itemId);
createShellEndpointCouldNotBeRetrievedTombstone(itemContainerBuilder, itemId, e);
}

if (expectedDepthOfTreeIsNotReached(jobData.getDepth(), aasTransferProcess.getDepth())) {
Expand All @@ -98,7 +101,41 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai
return itemContainerBuilder.build();
}

private Tombstone createNoBpnProvidedTombstone(final JobParameter jobData, final PartChainIdentificationKey itemId) {
private void createShellNotFoundTombstone(final ItemContainer.ItemContainerBuilder itemContainerBuilder,
final PartChainIdentificationKey itemId, final ShellNotFoundException exception) {
final String endpointURL = String.join("; ", exception.getCalledEndpoints());
final Tombstone tombstone = createTombstone(itemId, exception, endpointURL);
itemContainerBuilder.tombstone(tombstone);
}

private void createShellEndpointCouldNotBeRetrievedTombstone(
final ItemContainer.ItemContainerBuilder itemContainerBuilder, final PartChainIdentificationKey itemId,
final Exception exception) {
final Tombstone tombstone = createTombstone(itemId, exception, /* endpoint URL is unknown here */ null);
itemContainerBuilder.tombstone(tombstone);
}

private Tombstone createTombstone(final PartChainIdentificationKey itemId, final Exception exception,
final String endpointURL) {

final List<String> rootErrorMessages = Tombstone.getRootErrorMessages(exception.getSuppressed());
final ProcessingError error = ProcessingError.builder()
.withProcessStep(ProcessStep.DIGITAL_TWIN_REQUEST)
.withRetryCounterAndLastAttemptNow(retryCount)
.withErrorDetail(exception.getMessage())
.withRootCauses(rootErrorMessages)
.build();

return Tombstone.builder()
.endpointURL(endpointURL)
.catenaXId(itemId.getGlobalAssetId())
.processingError(error)
.businessPartnerNumber(itemId.getBpn())
.build();
}

private Tombstone createNoBpnProvidedTombstone(final JobParameter jobData,
final PartChainIdentificationKey itemId) {
log.warn("Could not process item with id {} because no BPN was provided. Creating Tombstone.",
itemId.getGlobalAssetId());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package org.eclipse.tractusx.irs.aaswrapper.job.delegate;

import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -32,6 +33,7 @@
import org.eclipse.tractusx.irs.component.Bpn;
import org.eclipse.tractusx.irs.component.JobParameter;
import org.eclipse.tractusx.irs.component.PartChainIdentificationKey;
import org.eclipse.tractusx.irs.component.ProcessingError;
import org.eclipse.tractusx.irs.component.Relationship;
import org.eclipse.tractusx.irs.component.Tombstone;
import org.eclipse.tractusx.irs.component.assetadministrationshell.Endpoint;
Expand All @@ -41,6 +43,7 @@
import org.eclipse.tractusx.irs.data.JsonParseException;
import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade;
import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException;
import org.eclipse.tractusx.irs.edc.client.exceptions.PolicyException;
import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyExpiredException;
import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyPermissionException;
import org.eclipse.tractusx.irs.edc.client.relationships.RelationshipAspect;
Expand Down Expand Up @@ -94,9 +97,7 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r
if (StringUtils.isBlank(itemId.getBpn())) {
log.warn("Could not process item with id {} because no BPN was provided. Creating Tombstone.",
itemId.getGlobalAssetId());
itemContainerBuilder.tombstone(
Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(),
"Can't get relationship without a BPN", retryCount, ProcessStep.SUBMODEL_REQUEST));
itemContainerBuilder.tombstone(createNoBpnProvidedTombstone(endpoint, itemId));
return;
}

Expand All @@ -111,30 +112,77 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r
relationshipAspect.getDirection());

log.info("Processing Relationships with {} items", idsToProcess.size());

aasTransferProcess.addIdsToProcess(idsToProcess);
itemContainerBuilder.relationships(relationships);
itemContainerBuilder.bpns(getBpnsFrom(relationships));

} catch (final UsagePolicyPermissionException | UsagePolicyExpiredException e) {
log.info("Encountered usage policy exception: {}. Creating Tombstone.", e.getMessage());
itemContainerBuilder.tombstone(
Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0,
ProcessStep.USAGE_POLICY_VALIDATION, e.getBusinessPartnerNumber(),
jsonUtil.asMap(e.getPolicy())));
final Tombstone tombstone = createPolicyTombstone(endpoint, itemId, e);
itemContainerBuilder.tombstone(tombstone);

} catch (final EdcClientException e) {
log.info("Submodel Endpoint could not be retrieved for Endpoint: {}. Creating Tombstone.",
endpoint.getProtocolInformation().getHref());
itemContainerBuilder.tombstone(
Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0,
ProcessStep.SUBMODEL_REQUEST));
final Tombstone tombstone = createEdcClientExceptionTombstone(endpoint, itemId, e);
itemContainerBuilder.tombstone(tombstone);

} catch (final JsonParseException e) {
log.info("Submodel payload did not match the expected AspectType. Creating Tombstone.");
itemContainerBuilder.tombstone(
Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0,
ProcessStep.SUBMODEL_REQUEST));
final Tombstone tombstone = createJsonParseSubmodelPayloadTombstone(endpoint, itemId, e);
itemContainerBuilder.tombstone(tombstone);
}
}

private Tombstone createNoBpnProvidedTombstone(final Endpoint endpoint, final PartChainIdentificationKey itemId) {
final ProcessingError error = createProcessingError(ProcessStep.SUBMODEL_REQUEST, retryCount,
"Can't get relationship without a BPN");
return createTombstone(endpoint.getProtocolInformation().getHref(), itemId.getGlobalAssetId(), error,
itemId.getBpn());
}

private Tombstone createPolicyTombstone(final Endpoint endpoint, final PartChainIdentificationKey itemId,
final PolicyException exception) {
final Map<String, Object> policy = jsonUtil.asMap(exception.getPolicy());
final ProcessingError error = createProcessingError(ProcessStep.USAGE_POLICY_VALIDATION, 0,
exception.getMessage());
return createTombstone(endpoint.getProtocolInformation().getHref(), itemId.getGlobalAssetId(), error,
exception.getBusinessPartnerNumber()).toBuilder().policy(policy).build();
}

private Tombstone createEdcClientExceptionTombstone(final Endpoint endpoint,
final PartChainIdentificationKey itemId, final EdcClientException exception) {
final ProcessingError error = createProcessingError(ProcessStep.SUBMODEL_REQUEST, 0, exception.getMessage());
return createTombstone(endpoint.getProtocolInformation().getHref(), itemId.getGlobalAssetId(), error,
itemId.getBpn());
}

private Tombstone createJsonParseSubmodelPayloadTombstone(final Endpoint endpoint,
final PartChainIdentificationKey itemId, final JsonParseException exception) {
final ProcessingError error = createProcessingError(ProcessStep.SUBMODEL_REQUEST, 0, exception.getMessage());
return createTombstone(endpoint.getProtocolInformation().getHref(), itemId.getGlobalAssetId(), error,
itemId.getBpn());
}

private ProcessingError createProcessingError(final ProcessStep processStep, final int retryCount,
final String exception) {
return ProcessingError.builder()
.withProcessStep(processStep)
.withRetryCounterAndLastAttemptNow(retryCount)
.withErrorDetail(exception)
.build();
}

private Tombstone createTombstone(final String endpointURL, final String globalAssetId, final ProcessingError error,
final String bpn) {
return Tombstone.builder()
.endpointURL(endpointURL)
.catenaXId(globalAssetId)
.processingError(error)
.businessPartnerNumber(bpn)
.build();
}

ds-jhartmann marked this conversation as resolved.
Show resolved Hide resolved
private static List<Bpn> getBpnsFrom(final List<Relationship> relationships) {
return relationships.stream()
.map(Relationship::getBpn)
Expand Down
Loading
Loading