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

feat(impl):[#244] Show infected supply chain on first tier level + feat(impl):[#246] Show hops number for impacted supply chain #618

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
62ecb05
feat(impl):[TRI-1641] hops implementation
ds-ext-kmassalski Oct 27, 2023
77fa64c
feat(impl):[TRI-1641] fixes and improvements
ds-ext-kmassalski Oct 27, 2023
0999bf6
feat(impl):[TRI-1641] tool fixes
ds-ext-kmassalski Oct 27, 2023
470030d
feat(impl):[TRI-1641] fixes&adjustments
ds-ext-kmassalski Oct 27, 2023
6345adb
feat(impl):[TRI-1641] fixes&adjustments
ds-ext-kmassalski Oct 27, 2023
29b4a3b
feat(impl):[TRI-1641] fixes&adjustments
ds-ext-kmassalski Oct 27, 2023
207fd84
feat(impl):[TRI-1641] fixes&adjustments
ds-ext-kmassalski Oct 27, 2023
7bb3036
feat(impl):[TRI-1641] fix spotbugs
ds-ext-kmassalski Oct 30, 2023
9844ea9
feat(impl):[TRI-1641] merge main
ds-ext-kmassalski Oct 30, 2023
94f232b
feat(impl):[TRI-1641] add changelog
ds-ext-kmassalski Oct 30, 2023
3dd9ac3
feat(impl):[TRI-1641] fix pmds
ds-ext-kmassalski Oct 30, 2023
2e1d69f
feat(impl):[TRI-1641] refactoring
ds-ext-kmassalski Oct 30, 2023
a941604
feat(impl):[TRI-1641] adjustments and test
ds-ext-kmassalski Oct 30, 2023
16c0519
feat(impl):[TRI-1641] adjustments review comments
ds-ext-kmassalski Oct 31, 2023
6b2cebe
feat(impl):[TRI-1641] send hop in notification
ds-ext-kmassalski Nov 2, 2023
6524a74
Merge branch 'main' into feature/TRI-1641-implementation-of-hops
ds-ext-kmassalski Nov 2, 2023
4e71336
feat(impl):[TRI-1641] fix DEP file
ds-ext-kmassalski Nov 2, 2023
a48f914
feat(impl):[TRI-1658] added bpn number of the first level chain
ds-psosnowski Nov 3, 2023
e4d7ac5
feat(impl):[TRI-1658] changed bpn in notification callback to sender bpn
ds-psosnowski Nov 6, 2023
2523f1e
feat(impl):[TRI-1658] extended unanswered notification to contain bpn…
ds-psosnowski Nov 6, 2023
9db1421
feat(impl):[TRI-1658] added checkstyle fixes
ds-psosnowski Nov 6, 2023
d439917
feat(impl):[TRI-1658] added checkstyle fixes for tabs
ds-psosnowski Nov 6, 2023
a0fe225
feat(impl):[TRI-1658] fixed problem with missing notification bpn
ds-psosnowski Nov 6, 2023
8cfe9de
TRI-1658: Corrected Vehicle D assets in ESS_Testdata_v2.0.0-AsPlanned…
ds-alexander-bulgakov Nov 7, 2023
e2c8d08
feat(impl):[TRI-1658] added tests, code clean up
ds-psosnowski Nov 7, 2023
41a00a1
feat(impl):[TRI-1658] added tests and code clean up
ds-psosnowski Nov 7, 2023
78f79fa
TRI-1658 (#246 and #244): Added tavern tests and according helpers fo…
ds-alexander-bulgakov Nov 8, 2023
d6da7f8
refacroting: refactored tavern-helpers for supplyChainImpacted checks
ds-alexander-bulgakov Nov 8, 2023
72314b0
feat(impl):[244] changed tavern method name
ds-alexander-bulgakov Nov 9, 2023
979ae74
feat(impl):[244] changed approach for first level supplier incident f…
ds-psosnowski Nov 9, 2023
809b21d
feat(impl):[244] adjusted check methods for expectedBpnl and hops rem…
ds-alexander-bulgakov Nov 9, 2023
254d382
feat(impl):[244] added more tests for ESS hops and firstLevelBpn and …
ds-alexander-bulgakov Nov 10, 2023
b1f3530
feat(irs-api):[#244] Verification of the 1st level supplier bpn in re…
ds-psosnowski Nov 13, 2023
ae3b1fd
feat(irs-api):[#244] Verification of the 1st level supplier bpn in re…
ds-psosnowski Nov 13, 2023
de621fe
feat(irs-api):[#244] Verification of the 1st level supplier bpn in re…
ds-psosnowski Nov 13, 2023
34370b2
feat(irs-api):[#246] Changed hops incrementation pattern
ds-psosnowski Nov 15, 2023
43680fe
chore(docs):[253] added known knows to CHANGELOG.md
ds-alexander-bulgakov Nov 15, 2023
214f291
feat(irs-api):[#246] First level supply chain changed to show only lo…
ds-psosnowski Nov 16, 2023
00e0f02
Merge remote-tracking branch 'origin/feature/TRI-1658-infected-supply…
ds-psosnowski Nov 16, 2023
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- ESS
- Added 'hops' parameter to SupplyChainImpacted Aspect model - contains relative distance in the supply chain
- Added `impactedSuppliersOnFirstTier` parameter to Supply SupplyChainImpacted Aspect model - contains information of first level supply chain impacted

### Known knowns
- [#253] Cancelation of order jobs is not working stable

## [4.0.0] - 2023-10-27
### Added
Expand Down
2 changes: 1 addition & 1 deletion DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ maven/mavencentral/io.rest-assured/xml-path/5.3.0, Apache-2.0, approved, #9267
maven/mavencentral/io.rest-assured/xml-path/5.3.2, Apache-2.0, approved, #9267
maven/mavencentral/io.suzaku/boopickle_2.13/1.3.3, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-annotations-jakarta/2.2.15, Apache-2.0, approved, #5947
maven/mavencentral/io.swagger.core.v3/swagger-annotations/2.2.16, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-annotations/2.2.16, Apache-2.0, approved, #11362
maven/mavencentral/io.swagger.core.v3/swagger-core-jakarta/2.2.15, Apache-2.0, approved, #5929
maven/mavencentral/io.swagger.core.v3/swagger-models-jakarta/2.2.15, Apache-2.0, approved, #5919
maven/mavencentral/jakarta.activation/jakarta.activation-api/2.1.2, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf
Expand Down
9 changes: 7 additions & 2 deletions docs/src/api/irs-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2521,6 +2521,11 @@ components:
type: object
additionalProperties: false
properties:
hops:
type: integer
format: int32
bpn:
type: string
result:
type: string
SemanticId:
Expand Down Expand Up @@ -2563,10 +2568,10 @@ components:
items:
$ref: '#/components/schemas/Endpoint'
maxItems: 2147483647
idShort:
type: string
id:
type: string
idShort:
type: string
semanticId:
$ref: '#/components/schemas/Reference'
Summary:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,57 +27,44 @@
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.tractusx.irs.component.Job;
import org.eclipse.tractusx.irs.component.Jobs;
import org.eclipse.tractusx.irs.component.Notification;
import org.eclipse.tractusx.irs.component.Submodel;
import org.eclipse.tractusx.irs.component.Summary;
import org.eclipse.tractusx.irs.component.enums.JobState;
import org.eclipse.tractusx.irs.edc.client.model.notification.EdcNotification;
import org.eclipse.tractusx.irs.edc.client.model.notification.ResponseNotificationContent;
import org.eclipse.tractusx.irs.util.JsonUtil;

/**
* Object to store in cache
*/
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public class BpnInvestigationJob {

private static final String SUPPLY_CHAIN_ASPECT_TYPE = "supply_chain_impacted";

private Jobs jobSnapshot;
private List<String> incidentBpns;
private List<String> unansweredNotifications;
private List<String> answeredNotifications;
private List<Notification> unansweredNotifications;
private List<EdcNotification<ResponseNotificationContent>> answeredNotifications;
private JobState state;

public BpnInvestigationJob(final Jobs jobSnapshot, final List<String> incidentBpns) {
this(jobSnapshot, incidentBpns, new ArrayList<>(), new ArrayList<>(), JobState.RUNNING);
}

private static Jobs extendJobWithSupplyChainSubmodel(final Jobs irsJob,
final SupplyChainImpacted supplyChainImpacted) {
final Submodel supplyChainImpactedSubmodel = Submodel.builder()
.aspectType(SUPPLY_CHAIN_ASPECT_TYPE)
.payload(Map.of("supplyChainImpacted",
supplyChainImpacted.getDescription()))
.build();

return irsJob.toBuilder()
.clearSubmodels()
.submodels(Collections.singletonList(supplyChainImpactedSubmodel))
.build();
}

private static Jobs updateLastModified(final Jobs irsJob, final ZonedDateTime lastModifiedOn) {
final Job job = irsJob.getJob().toBuilder().completedOn(lastModifiedOn).lastModifiedOn(lastModifiedOn).build();
return irsJob.toBuilder().job(job).build();
}

public BpnInvestigationJob update(final Jobs jobSnapshot, final SupplyChainImpacted newSupplyChain) {
final Optional<SupplyChainImpacted> previousSupplyChain = getSupplyChainImpacted();

Expand All @@ -90,6 +77,42 @@ public BpnInvestigationJob update(final Jobs jobSnapshot, final SupplyChainImpac
return this;
}

public BpnInvestigationJob withUnansweredNotifications(final List<Notification> notifications) {
this.unansweredNotifications.addAll(notifications);
return this;
}

public BpnInvestigationJob withAnsweredNotification(
final EdcNotification<ResponseNotificationContent> notification) {
final Optional<String> bpn = getChildBpn(notification);
removeFromUnansweredNotification(notification);
notification.getContent().setBpn(bpn.orElse(null));
notification.getContent().incrementHops();
this.answeredNotifications.add(notification);

return this;
}

private Optional<String> getChildBpn(final EdcNotification<ResponseNotificationContent> notification) {
return this.unansweredNotifications.stream()
.filter(unansweredNotification -> unansweredNotification.notificationId()
.equals(notification.getHeader()
.getOriginalNotificationId()))
.map(Notification::childBpn)
.findAny();
}

private void removeFromUnansweredNotification(final EdcNotification<ResponseNotificationContent> notification) {
this.unansweredNotifications.removeIf(unansweredNotification -> unansweredNotification.notificationId()
.equals(notification.getHeader()
.getOriginalNotificationId()));
}

public BpnInvestigationJob complete() {
this.state = JobState.COMPLETED;
return this;
}

/* package */ Optional<SupplyChainImpacted> getSupplyChainImpacted() {
return this.getJobSnapshot()
.getSubmodels()
Expand All @@ -101,6 +124,46 @@ public BpnInvestigationJob update(final Jobs jobSnapshot, final SupplyChainImpac
.findFirst();
}

private Jobs extendJobWithSupplyChainSubmodel(final Jobs irsJob, final SupplyChainImpacted supplyChainImpacted) {
final SupplyChainImpactedAspect.SupplyChainImpactedAspectBuilder supplyChainImpactedAspectBuilder = SupplyChainImpactedAspect.builder()
.supplyChainImpacted(
supplyChainImpacted);

if (getUnansweredNotifications().isEmpty()) {
final Optional<SupplyChainImpactedAspect.ImpactedSupplierFirstLevel> impactedSupplierWithLowestHopsNumber = getImpactedSupplierWithLowestHopsNumber();
supplyChainImpactedAspectBuilder.impactedSuppliersOnFirstTier(
impactedSupplierWithLowestHopsNumber.orElse(null));
}

return irsJob.toBuilder()
.clearSubmodels()
.submodels(Collections.singletonList(
createSupplyChainImpactedSubmodel(supplyChainImpactedAspectBuilder)))
.build();
}

private Optional<SupplyChainImpactedAspect.ImpactedSupplierFirstLevel> getImpactedSupplierWithLowestHopsNumber() {
return getAnsweredNotifications().stream()
.map(EdcNotification::getContent)
.filter(ResponseNotificationContent::thereIsIncident)
.min(Comparator.comparing(ResponseNotificationContent::getHops))
.map(impacted -> new SupplyChainImpactedAspect.ImpactedSupplierFirstLevel(
impacted.getBpn(), impacted.getHops()));
}

private static Submodel createSupplyChainImpactedSubmodel(
final SupplyChainImpactedAspect.SupplyChainImpactedAspectBuilder supplyChainImpactedAspectBuilder) {
return Submodel.builder()
.aspectType(SUPPLY_CHAIN_ASPECT_TYPE)
.payload(new JsonUtil().asMap(supplyChainImpactedAspectBuilder.build()))
.build();
}

private Jobs updateLastModified(final Jobs irsJob, final ZonedDateTime lastModifiedOn) {
final Job job = irsJob.getJob().toBuilder().completedOn(lastModifiedOn).lastModifiedOn(lastModifiedOn).build();
return irsJob.toBuilder().job(job).build();
}

private Jobs extendSummary(final Jobs irsJob) {
final Summary oldSummary = Optional.ofNullable(irsJob.getJob().getSummary()).orElse(Summary.builder().build());
final NotificationSummary newSummary = new NotificationSummary(oldSummary.getAsyncFetchedItems(),
Expand All @@ -111,19 +174,4 @@ private Jobs extendSummary(final Jobs irsJob) {
return irsJob.toBuilder().job(job).build();
}

public BpnInvestigationJob withNotifications(final List<String> notifications) {
this.unansweredNotifications.addAll(notifications);
return this;
}

public BpnInvestigationJob withAnsweredNotification(final String notificationId) {
this.unansweredNotifications.remove(notificationId);
this.answeredNotifications.add(notificationId);
return this;
}

public BpnInvestigationJob complete() {
this.state = JobState.COMPLETED;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public EdcNotificationSender(final EdcSubmodelFacade edcSubmodelFacade,
}

public void sendEdcNotification(final EdcNotification<InvestigationNotificationContent> originalEdcNotification,
final SupplyChainImpacted supplyChainImpacted) {
final SupplyChainImpacted supplyChainImpacted, final Integer hops, final String bpn) {
final String notificationId = UUID.randomUUID().toString();
final String originalNotificationId = originalEdcNotification.getHeader().getNotificationId();
final String recipientBpn = originalEdcNotification.getHeader().getSenderBpn();
Expand All @@ -69,6 +69,8 @@ public void sendEdcNotification(final EdcNotification<InvestigationNotificationC
log.info("Edc Notification will be send to connector endpoint: {}", connectorEndpoint);
final NotificationContent notificationContent = ResponseNotificationContent.builder()
.result(supplyChainImpacted.getDescription())
.hops(hops)
.bpn(bpn)
.build();
final EdcNotification<NotificationContent> responseNotification = edcRequest(notificationId,
originalNotificationId, essLocalEdcEndpoint, localBpn, recipientBpn, notificationContent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,41 +43,46 @@ public class EssRecursiveNotificationHandler {
private final BpnInvestigationJobCache bpnInvestigationJobCache;
private final EdcNotificationSender edcNotificationSender;

/* package */ void handleNotification(final UUID finishedJobId, final SupplyChainImpacted supplyChainImpacted) {
/* package */ void handleNotification(final UUID finishedJobId, final SupplyChainImpacted supplyChainImpacted,
final String bpn, final Integer hops) {

final Optional<RelatedInvestigationJobs> relatedJobsId = relatedInvestigationJobsCache.findByRecursiveRelatedJobId(
finishedJobId);

relatedJobsId.ifPresentOrElse(relatedJobs -> {
if (SupplyChainImpacted.YES.equals(supplyChainImpacted)) {
log.debug("SupplyChain is impacted. Sending notification back to requestor.");
edcNotificationSender.sendEdcNotification(relatedJobs.originalNotification(), supplyChainImpacted);
edcNotificationSender.sendEdcNotification(relatedJobs.originalNotification(), supplyChainImpacted, hops,
bpn);
relatedInvestigationJobsCache.remove(
relatedJobs.originalNotification().getHeader().getNotificationId());
} else {
log.debug(
"SupplyChainImpacted in state '{}'. Waiting for Jobs to complete to send notification back to requestor.",
supplyChainImpacted);
sendNotificationAfterAllCompleted(relatedJobs);
sendNotificationAfterAllCompleted(relatedJobs, bpn, hops);
}
}, () -> log.debug("No RelatedInvestigationJob found for id '{}'.", finishedJobId));
}

private void sendNotificationAfterAllCompleted(final RelatedInvestigationJobs relatedInvestigationJobs) {
private void sendNotificationAfterAllCompleted(final RelatedInvestigationJobs relatedInvestigationJobs,
final String bpn, final Integer hops) {
final List<BpnInvestigationJob> allInvestigationJobs = relatedInvestigationJobs.recursiveRelatedJobIds()
.stream()
.map(bpnInvestigationJobCache::findByJobId)
.flatMap(Optional::stream)
.toList();

if (checkAllFinished(allInvestigationJobs)) {
final SupplyChainImpacted finalResult = allInvestigationJobs.stream()
.map(BpnInvestigationJob::getSupplyChainImpacted)
.flatMap(Optional::stream)
.reduce(SupplyChainImpacted.NO,
SupplyChainImpacted::or);
edcNotificationSender.sendEdcNotification(relatedInvestigationJobs.originalNotification(), finalResult);
}

edcNotificationSender.sendEdcNotification(relatedInvestigationJobs.originalNotification(), finalResult,
hops, bpn);
}
}

private boolean checkAllFinished(final List<BpnInvestigationJob> allInvestigationJobs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
@Slf4j
public class EssRecursiveService {

private static final Integer FIRST_HOP = 0;

private final EssService essService;
private final RelatedInvestigationJobsCache relatedInvestigationJobsCache;
private final String localBpn;
Expand All @@ -65,7 +67,7 @@ public void handleNotification(final EdcNotification<InvestigationNotificationCo
notification.getContent().getConcernedCatenaXIds());

if (incidentBPNSs.isPresent() && incidentBPNSs.get().contains(localBpn)) {
edcNotificationSender.sendEdcNotification(notification, SupplyChainImpacted.YES);
edcNotificationSender.sendEdcNotification(notification, SupplyChainImpacted.YES, FIRST_HOP, localBpn);
} else if (concernedCatenaXIdsNotification.isPresent() && incidentBPNSs.isPresent()) {
final List<String> bpns = incidentBPNSs.get();
final List<String> concernedCatenaXIds = concernedCatenaXIdsNotification.get();
Expand Down
Loading