Skip to content

Commit

Permalink
Merge pull request #863 from dsmf/fix/841-fill-bpn-in-tombstone
Browse files Browse the repository at this point in the history
Fix/841 fill bpn in tombstone
  • Loading branch information
ds-jhartmann authored Aug 5, 2024
2 parents 513bc56 + 5715943 commit 757974a
Show file tree
Hide file tree
Showing 20 changed files with 671 additions and 251 deletions.
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();
}

private static List<Bpn> getBpnsFrom(final List<Relationship> relationships) {
return relationships.stream()
.map(Relationship::getBpn)
Expand Down
Loading

0 comments on commit 757974a

Please sign in to comment.