diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java index 5a50fd588..55f5fc413 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java @@ -35,6 +35,7 @@ import org.eclipse.tractusx.irs.common.ExceptionUtils; 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.Shell; import org.eclipse.tractusx.irs.component.Tombstone; import org.eclipse.tractusx.irs.component.enums.ProcessStep; @@ -64,23 +65,19 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai final PartChainIdentificationKey itemId) { if (StringUtils.isBlank(itemId.getBpn())) { - log.warn("Could not process item with id {} because no BPN was provided. Creating Tombstone.", - itemId.getGlobalAssetId()); - return itemContainerBuilder.tombstone( - Tombstone.from(itemId.getGlobalAssetId(), null, "Can't get relationship without a BPN", 0, - ProcessStep.DIGITAL_TWIN_REQUEST)).build(); + return itemContainerBuilder.tombstone(createNoBpnProvidedTombstone(jobData, itemId)).build(); } try { final var dtrKeys = List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn())); - final var eithers = digitalTwinRegistryService.fetchShells(dtrKeys); - final var shell = eithers.stream() + 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(eithers)); + .orElseThrow(() -> shellNotFound(shells)); itemContainerBuilder.shell( jobData.isAuditContractNegotiation() ? shell : shell.withoutContractAgreementId()); @@ -101,6 +98,23 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai return itemContainerBuilder.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()); + + final ProcessingError error = ProcessingError.builder() + .withProcessStep(ProcessStep.DIGITAL_TWIN_REQUEST) + .withRetryCounterAndLastAttemptNow(0) + .withErrorDetail("Can't get relationship without a BPN") + .build(); + return Tombstone.builder() + .endpointURL(null) + .catenaXId(itemId.getGlobalAssetId()) + .processingError(error) + .businessPartnerNumber(jobData.getBpn()) + .build(); + } + private static RegistryServiceException shellNotFound(final Collection> eithers) { final RegistryServiceException shellNotFound = new RegistryServiceException("Shell not found"); ExceptionUtils.addSuppressedExceptions(eithers, shellNotFound); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java index 0d9b0ef72..c62e5d8b5 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java @@ -128,18 +128,8 @@ void shouldUseExceptionMessageWhenSuppressedExceptionNotPresent() { } private String zonedDateTimeExcerpt(ZonedDateTime dateTime) { - return new StringBuilder().append(dateTime.getYear()) - .append("-") - .append(dateTime.getMonth()) - .append("-") - .append(dateTime.getDayOfMonth()) - .append("T") - .append(dateTime.getHour()) - .append(":") - .append(dateTime.getMinute()) - .append(":") - .append(dateTime.getSecond()) - .toString(); + return "%d-%s-%dT%d:%d:%d".formatted(dateTime.getYear(), dateTime.getMonth(), dateTime.getDayOfMonth(), + dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond()); } } diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java index 4a6927181..fef65ed8c 100644 --- a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java +++ b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java @@ -79,7 +79,6 @@ public CompletableFuture getFastestResult(final List if (ex != null) { log.warn("All failed: " + System.lineSeparator() - // TODO (#538) can we remove logging here and log only up in call hierarchy + exceptions.stream() .map(ExceptionUtils::getStackTrace) .collect(Collectors.joining(System.lineSeparator())), ex); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java index 4ec279974..e977a4bea 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java @@ -19,19 +19,21 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.edc.client.exceptions; +import lombok.Getter; import org.eclipse.edc.policy.model.Policy; /** - * This interface provides get-methods for fine-grained policy exceptions + * Policy exception with detail information */ -public interface PolicyException { - /** - * @return the corresponding bpn of the policy - */ - String getBusinessPartnerNumber(); +@Getter +public class PolicyException extends EdcClientException { - /** - * @return the policy that caused the exception - */ - Policy getPolicy(); + private final transient Policy policy; + private final String businessPartnerNumber; + + public PolicyException(final String message, final Policy policy, final String businessPartnerNumber) { + super(message); + this.policy = policy; + this.businessPartnerNumber = businessPartnerNumber; + } } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java index 64549c554..8ef7273a5 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java @@ -29,17 +29,12 @@ * Usage Policy Expired Exception errors in the contract negotiation. */ @Getter -public class UsagePolicyExpiredException extends EdcClientException implements PolicyException { - - private final transient Policy policy; - private final String businessPartnerNumber; +public class UsagePolicyExpiredException extends PolicyException { public UsagePolicyExpiredException(final List acceptedPolicies, final Policy providedCatalogItemPolicy, final String businessPartnerNumber) { super("Policy " + acceptedPolicies.stream().map(policy -> policy.policy().getPolicyId()).toList() - + " has expired."); - this.policy = providedCatalogItemPolicy; - this.businessPartnerNumber = businessPartnerNumber; + + " has expired.", providedCatalogItemPolicy, businessPartnerNumber); } } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java index 8cac63106..c100c1a76 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java @@ -33,18 +33,13 @@ * Usage Policy Permission Exception errors in the contract negotiation. */ @Getter -public class UsagePolicyPermissionException extends EdcClientException implements PolicyException { - - private final transient Policy policy; - private final String businessPartnerNumber; +public class UsagePolicyPermissionException extends PolicyException { public UsagePolicyPermissionException(final List acceptedPolicies, final Policy providedCatalogItemPolicy, final String businessPartnerNumber) { super("Policies " + acceptedPolicies.stream().map(policy -> policy.policy().getPolicyId()).toList() - + " did not match with policy from " + businessPartnerNumber + "."); - - this.policy = providedCatalogItemPolicy; - this.businessPartnerNumber = businessPartnerNumber; + + " did not match with policy from " + businessPartnerNumber + ".", providedCatalogItemPolicy, + businessPartnerNumber); } diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java index 74878c299..40be07ae7 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java @@ -23,6 +23,7 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.component; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.List; @@ -42,6 +43,7 @@ @Builder(toBuilder = true, setterPrefix = "with") @JsonDeserialize(builder = ProcessingError.ProcessingErrorBuilder.class) public class ProcessingError { + private ProcessStep processStep; private String errorDetail; private ZonedDateTime lastAttempt; @@ -58,5 +60,14 @@ public class ProcessingError { @JsonPOJOBuilder() public static class ProcessingErrorBuilder { + public ProcessingErrorBuilder withLastAttemptNow() { + return this.withLastAttempt(ZonedDateTime.now(ZoneOffset.UTC)); + } + + public ProcessingErrorBuilder withRetryCounterAndLastAttemptNow(final int retryCount) { + return this.withLastAttemptNow().withRetryCounter(retryCount); + } + } + } diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java index be9451229..01a464eab 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java @@ -41,13 +41,15 @@ * Tombstone with information about request failure */ @Getter -@Builder +@Builder(toBuilder = true) @Jacksonized @Schema(description = "Tombstone with information about request failure") public class Tombstone { - private static final NodeType NODE_TYPE = NodeType.TOMBSTONE; + public static final int CATENA_X_ID_LENGTH = 45; + private static final NodeType NODE_TYPE = NodeType.TOMBSTONE; + @Schema(description = "CATENA-X global asset id in the format urn:uuid:uuid4.", example = "urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0", minLength = CATENA_X_ID_LENGTH, maxLength = CATENA_X_ID_LENGTH, @@ -88,26 +90,20 @@ public static Tombstone from(final String catenaXId, final String endpointURL, f public static Tombstone from(final String globalAssetId, final String endpointURL, final Throwable exception, final Throwable[] suppressed, final int retryCount, final ProcessStep processStep) { - final ProcessingError processingError = withProcessingError(processStep, retryCount, exception.getMessage(), - suppressed); return Tombstone.builder() .endpointURL(endpointURL) .catenaXId(globalAssetId) - .processingError(processingError) + .processingError(ProcessingError.builder() + .withProcessStep(processStep) + .withRetryCounterAndLastAttemptNow(retryCount) + .withErrorDetail(exception.getMessage()) + .withRootCauses(getRootErrorMessages(suppressed)) + .build()) .build(); } - private static ProcessingError withProcessingError(final ProcessStep processStep, final int retryCount, - final String message, final Throwable... suppressed) { - final List rootCauses = Arrays.stream(suppressed).map(Tombstone::getRootErrorMessages).toList(); - - return ProcessingError.builder() - .withProcessStep(processStep) - .withRetryCounter(retryCount) - .withLastAttempt(ZonedDateTime.now(ZoneOffset.UTC)) - .withErrorDetail(message) - .withRootCauses(rootCauses) - .build(); + private static List getRootErrorMessages(final Throwable... throwables) { + return Arrays.stream(throwables).map(Tombstone::getRootErrorMessages).toList(); } /** diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index 870688418..bb32be953 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -332,7 +332,7 @@ private Collection lookupShellIds(final String bpn, "%s occurred while looking up shell ids for bpn '%s'".formatted(e.getClass().getSimpleName(), bpn), e); } catch (TimeoutException e) { - throw new RegistryServiceException("Timeout during shell ID lookup", e); + throw new RegistryServiceException("Timeout during shell ID lookup for bpn '%s'".formatted(bpn), e); } }