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

Feature/962 notification model update #1090

Merged
merged 6 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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 @@ -10,6 +10,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha
### Changed
- #965 Implement proxy functionality of the IRS policy store
- #962 Changed notification model to new one in frontend/backend
- #962 Removed initial notification message for notification flow
- #753 Refactored message history in notification detail view

### Added
Expand Down
8,118 changes: 8,117 additions & 1 deletion docs/api/traceability-foss-backend.json

Large diffs are not rendered by default.

8,118 changes: 8,117 additions & 1 deletion tx-backend/openapi/traceability-foss-backend.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class NotificationMapper {
* @param notification the notification associated with the alert or investigation
* @return an Notification object representing the notification received by the receiver
*/
public Notification toNotification(BPN bpn, EDCNotification edcNotification, NotificationMessage notification, NotificationType notificationType) {
public Notification toNotification(BPN bpn, EDCNotification edcNotification, NotificationMessage notification, NotificationType notificationType, BPN applicationBPN) {

List<String> assetIds = new ArrayList<>();
emptyIfNull(notification.getAffectedParts()).stream()
Expand All @@ -64,10 +64,12 @@ public Notification toNotification(BPN bpn, EDCNotification edcNotification, Not
.notificationType(notificationType)
.description(edcNotification.getInformation())
.createdAt(Instant.now())
.sendTo(applicationBPN.value())
.severity(NotificationSeverity.fromString(edcNotification.getSeverity()))
.targetDate(convertInstantToString(edcNotification.getTargetDate()))
.affectedPartIds(assetIds)
.notifications(List.of(notification))
.initialReceiverBpns(List.of(applicationBPN.value()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ public static NotificationResponse from(Notification notification) {
.type(NotificationMessageMapper.from(notification.getNotificationType()))
.title(notification.getTitle())
.updatedDate(OffsetDateTime.now().toString())
.sendTo(getReceiverBPN(notification.getNotifications()))
.sendTo(notification.getSendTo())
.sendToName(getReceiverName(notification.getNotifications()))
.severity(notification.getSeverity() != null ?
NotificationSeverityResponse.fromString(notification.getSeverity().getRealName()) :
null)
.targetDate(notification.getTargetDate())
.messages(fromNotifications(notification.getNotifications()))
.build();
.messages(fromNotifications(notification.getNotifications())).build();
}

public static PageResult<NotificationResponse> fromAsPageResult(PageResult<Notification> notificationPageResult) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
public class Notification {
private String title;
private BPN bpn;
private String sendTo;
private NotificationId notificationId;
private NotificationStatus notificationStatus;
private String description;
Expand All @@ -60,13 +61,17 @@ public class Notification {
private List<String> affectedPartIds = new ArrayList<>();
private NotificationSeverity severity;
private String targetDate;
@Builder.Default
private List<String> initialReceiverBpns = new ArrayList<>();

@Getter
@Builder.Default
private List<NotificationMessage> notifications = List.of();


public static Notification startNotification(String title, Instant createDate, BPN bpn, String description, NotificationType notificationType, NotificationSeverity severity, Instant targetDate) {
public static Notification startNotification(String title, Instant createDate, BPN bpn, String description, NotificationType notificationType, NotificationSeverity severity, Instant targetDate, List<String> affectedPartIds, List<String> initialReceiverBpns, String receiverBpn) {



return Notification.builder()
.title(title)
Expand All @@ -78,55 +83,17 @@ public static Notification startNotification(String title, Instant createDate, B
.severity(severity)
.description(description)
.updatedDate(Instant.now())
.sendTo(receiverBpn)
.createdAt(createDate)
.affectedPartIds(Collections.emptyList())
.affectedPartIds(affectedPartIds)
.initialReceiverBpns(initialReceiverBpns)
.build();
}

public void clearNotifications() {
notifications = new ArrayList<>();
}

public void createInitialNotifications(List<AssetBase> affectedParts, BPN applicationBPN, EditNotification editNotification, List<BpnEdcMapping> bpnEdcMappings) {

if (editNotification.getReceiverBpn() != null) {
Map.Entry<String, List<AssetBase>> receiverAssetsMap = new AbstractMap.SimpleEntry<>(editNotification.getReceiverBpn(), affectedParts);
Optional<String> sentToName = bpnEdcMappings.stream().filter(bpnEdcMapping -> bpnEdcMapping.bpn().equals(editNotification.getReceiverBpn())).findFirst().map(BpnEdcMapping::manufacturerName);
NotificationMessage notificationMessage = NotificationMessage.create(
applicationBPN,
editNotification.getReceiverBpn(),
editNotification.getDescription(),
this.notificationType,
receiverAssetsMap,
applicationBPN.value(),
sentToName.orElse(null));

this.addNotificationMessage(notificationMessage);


} else {
Map<String, List<AssetBase>> assetsAsBuiltBPNMap = affectedParts.stream().collect(groupingBy(AssetBase::getManufacturerId));
assetsAsBuiltBPNMap
.entrySet()
.stream()
.map(receiverAssetsMapEntry -> {
String sentToBPN = receiverAssetsMapEntry.getKey();
Optional<String> sentToName = bpnEdcMappings.stream().filter(bpnEdcMapping -> bpnEdcMapping.bpn().equals(sentToBPN)).findFirst().map(BpnEdcMapping::manufacturerName);
return NotificationMessage.create(
applicationBPN,
sentToBPN,
editNotification.getDescription(),
this.notificationType,
receiverAssetsMapEntry,
applicationBPN.value(),
sentToName.orElse(null));
})
.forEach(this::addNotificationMessage);
}


}

public List<String> getAffectedPartIds() {
return Collections.unmodifiableList(affectedPartIds);
}
Expand Down Expand Up @@ -194,7 +161,7 @@ private void changeStatusTo(NotificationStatus to) {
this.notificationStatus = to;
}

public void addNotificationMessage(NotificationMessage notification) {
public synchronized void addNotificationMessage(NotificationMessage notification) {

List<NotificationMessage> updatedNotifications = new ArrayList<>(notifications);
updatedNotifications.add(notification);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.eclipse.tractusx.traceability.common.model.BPN;
import org.eclipse.tractusx.traceability.notification.domain.notification.exception.NotificationStatusTransitionNotAllowed;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -77,7 +76,7 @@ public static NotificationMessage create(BPN applicationBpn, String receiverBpn,
.sentTo(StringUtils.isBlank(receiverBpn) ? asset.getKey() : receiverBpn)
.sendToName(sendToName)
.message(description)
.notificationStatus(NotificationStatus.CREATED)
.notificationStatus(NotificationStatus.SENT)
.affectedParts(asset.getValue().stream().map(AssetBase::getId).map(NotificationAffectedPart::new).toList())
.edcNotificationId(notificationId)
.type(notificationType)
Expand All @@ -86,7 +85,6 @@ public static NotificationMessage create(BPN applicationBpn, String receiverBpn,
}



// Important - receiver and sender will be saved in switched order
public NotificationMessage copyAndSwitchSenderAndReceiver(BPN applicationBpn) {
final String notificationId = UUID.randomUUID().toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,8 @@ public static NotificationStatus fromStringValue(String value) {
public static NotificationStatus getPreviousStatus(NotificationStatus status, List<NotificationMessage> messages) {
return switch (status) {
case CREATED, SENT, CANCELED -> NotificationStatus.CREATED;
case ACKNOWLEDGED, RECEIVED -> NotificationStatus.SENT;
case ACKNOWLEDGED, RECEIVED, CLOSED -> NotificationStatus.SENT;
case ACCEPTED, DECLINED -> NotificationStatus.ACKNOWLEDGED;
case CLOSED -> messages.size() > 1 ? NotificationStatus.SENT : NotificationStatus.CREATED;
};
}
public boolean transitionAllowed(NotificationStatus to) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ public abstract class AbstractNotificationReceiverService implements Notificatio

protected abstract RuntimeException getIllegalUpdateException(String message);

protected abstract BPN getApplicationBpn();

@Override
public void handleReceive(EDCNotification edcNotification, NotificationType notificationType) {
BPN investigationCreatorBPN = BPN.of(edcNotification.getSenderBPN());
NotificationMessage notification = getNotificationMessageMapper().toNotificationMessage(edcNotification, notificationType);
Notification investigation = getNotificationMapper().toNotification(investigationCreatorBPN, edcNotification, notification, notificationType);
Notification investigation = getNotificationMapper().toNotification(investigationCreatorBPN, edcNotification, notification, notificationType, getApplicationBpn());
NotificationId investigationId = getRepository().saveNotification(investigation);
log.info("Stored received edcNotification in investigation with id {}", investigationId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
********************************************************************************/
package org.eclipse.tractusx.traceability.notification.domain.base.service;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.tractusx.traceability.assets.domain.asbuilt.repository.AssetAsBuiltRepository;
Expand Down Expand Up @@ -51,6 +52,7 @@

@RequiredArgsConstructor
@Slf4j
@Transactional
public abstract class AbstractNotificationService implements NotificationService {

private final TraceabilityProperties traceabilityProperties;
Expand Down Expand Up @@ -114,15 +116,13 @@ public void updateStatusTransition(Long notificationId, NotificationStatus notif
public void editNotification(EditNotification editNotification) {
validateReceiverIsNotOwnBpn(editNotification.getReceiverBpn(), editNotification.getId());
Notification notification = loadOrNotFoundException(new NotificationId(editNotification.getId()));
List<AssetBase> affectedParts = assetAsBuiltRepository.getAssetsById(editNotification.getAffectedPartIds());
List<BpnEdcMapping> bpnMappings = bpnRepository.findAllByIdIn(affectedParts.stream().map(AssetBase::getManufacturerId).toList());

List<String> oldMessageIds =
notification.getNotifications().stream().map(NotificationMessage::getId).toList();

getNotificationRepository().deleteByIdIn(oldMessageIds);
notification.clearNotifications();
notification.createInitialNotifications(affectedParts, traceabilityProperties.getBpn(), editNotification, bpnMappings);

if (editNotification.getReceiverBpn() != null) {
notification.setBpn(BPN.of(editNotification.getReceiverBpn()));
}
Expand Down Expand Up @@ -154,24 +154,6 @@ public Notification find(Long id) {
@Override
public void approve(Long notificationId) {
Notification notification = loadOrNotFoundException(new NotificationId(notificationId));
List<NotificationMessage> createdNotifications = notification
.getNotifications()
.stream()
.filter(notificationMessage -> notificationMessage.getNotificationStatus().equals(NotificationStatus.CREATED))
.map(notificationMessage -> notificationMessage.toBuilder().build())
.toList();

log.info("Found {} notification messages in status CREATED", createdNotifications.size());
List<NotificationMessage> approvedNotifications = new ArrayList<>(createdNotifications);
approvedNotifications.forEach(notificationMessage -> {
notificationMessage.setId(UUID.randomUUID().toString());
notificationMessage.changeStatusTo(NotificationStatus.SENT);
});
log.info("Found {} notification messages in status SENT", approvedNotifications.size());

notification.addNotificationMessages(approvedNotifications);
log.info("Found {} notification messages at all", notification.getNotifications().size());
notification.getNotifications().stream().map(notificationMessage -> notificationMessage.getNotificationStatus().name()).forEach(s -> log.info("Notification Status {} ", s));

final Notification approvedInvestigation;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@

package org.eclipse.tractusx.traceability.notification.domain.base.service;

import org.eclipse.tractusx.traceability.notification.domain.base.model.Notification;
import org.eclipse.tractusx.traceability.notification.domain.base.model.NotificationMessage;

import java.util.concurrent.CompletableFuture;

public interface EdcNotificationService {
CompletableFuture<NotificationMessage> asyncNotificationMessageExecutor(NotificationMessage notification);
CompletableFuture<NotificationMessage> asyncNotificationMessageExecutor(NotificationMessage message, Notification notification);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import static org.apache.commons.collections4.ListUtils.emptyIfNull;
Expand All @@ -57,7 +56,7 @@ public class EdcNotificationServiceImpl implements EdcNotificationService {

@Override
@Async(value = AssetsAsyncConfig.UPDATE_NOTIFICATION_EXECUTOR)
public CompletableFuture<NotificationMessage> asyncNotificationMessageExecutor(NotificationMessage message) {
public CompletableFuture<NotificationMessage> asyncNotificationMessageExecutor(NotificationMessage message, Notification notification) {
log.info("::asyncNotificationExecutor::message {}", message);
try {
Discovery discovery = discoveryService.getDiscoveryByBPN(message.getSentTo());
Expand All @@ -69,13 +68,13 @@ public CompletableFuture<NotificationMessage> asyncNotificationMessageExecutor(N
if (message.getType().equals(NotificationType.ALERT)) {
log.info("::asyncNotificationExecutor::isQualityAlert");
sendResults = receiverUrls
.stream().map(receiverUrl -> handleSendingNotification(message, senderEdcUrl, receiverUrl)).toList();
.stream().map(receiverUrl -> handleSendingNotification(message, senderEdcUrl, receiverUrl, notification)).toList();
}

if (message.getType().equals(NotificationType.INVESTIGATION)) {
log.info("::asyncNotificationExecutor::isQualityInvestigation");
sendResults = receiverUrls
.stream().map(receiverUrl -> handleSendingNotification(message, senderEdcUrl, receiverUrl)).toList();
.stream().map(receiverUrl -> handleSendingNotification(message, senderEdcUrl, receiverUrl, notification)).toList();
}

Boolean wasSent = sendResults.stream().anyMatch(Boolean.TRUE::equals);
Expand All @@ -87,49 +86,42 @@ public CompletableFuture<NotificationMessage> asyncNotificationMessageExecutor(N
return CompletableFuture.completedFuture(null);

} catch (DiscoveryFinderException discoveryFinderException) {
enrichNotificationByError(discoveryFinderException, message);
enrichNotificationByError(discoveryFinderException, notification);
return CompletableFuture.completedFuture(null);
}
}

private boolean handleSendingNotification(NotificationMessage message, String senderEdcUrl, String receiverUrl) {
private boolean handleSendingNotification(NotificationMessage message, String senderEdcUrl, String receiverUrl, Notification notification) {
try {
edcFacade.startEdcTransfer(message, receiverUrl, senderEdcUrl);
edcFacade.startEdcTransfer(message, receiverUrl, senderEdcUrl, notification);
return true;
} catch (NoCatalogItemException e) {
log.warn("Could not send message to {} no catalog item found. ", receiverUrl, e);
enrichNotificationByError(e, message);
enrichNotificationByError(e, notification);
} catch (SendNotificationException e) {
log.warn("Could not send message to {} ", receiverUrl, e);
enrichNotificationByError(e, message);
enrichNotificationByError(e, notification);
} catch (NoEndpointDataReferenceException e) {
log.warn("Could not send message to {} no endpoint data reference found", receiverUrl, e);
enrichNotificationByError(e, message);
enrichNotificationByError(e, notification);
} catch (ContractNegotiationException e) {
log.warn("Could not send message to {} could not negotiate contract agreement", receiverUrl, e);
enrichNotificationByError(e, message);
enrichNotificationByError(e, notification);
}
return false;
}

private void enrichNotificationByError(Exception e, NotificationMessage notificationMessage) {
log.info("Retrieving notification by message id {}", notificationMessage.getEdcNotificationId());
private void enrichNotificationByError(Exception e, Notification notification) {

Optional<Notification> optionalNotificationByEdcId = notificationRepository.findByEdcNotificationId(notificationMessage.getEdcNotificationId());
log.info("Notification for error message enrichment {}", notification);
notification.getNotifications().forEach(message1 -> log.info("Message found {}", message1));
notification.secondLatestNotifications().forEach(qmMessage -> {
log.info("Message from second latest notification {}", qmMessage);
qmMessage.setErrorMessage(e.getMessage());
});

log.info("Successfully executed retrieving quality notification by message id");
if (optionalNotificationByEdcId.isPresent()) {
log.info("Notification for error message enrichment {}", optionalNotificationByEdcId.get());
optionalNotificationByEdcId.get().getNotifications().forEach(message1 -> log.info("Message found {}", message1));
optionalNotificationByEdcId.get().secondLatestNotifications().forEach(qmMessage -> {
log.info("Message from second latest notification {}", qmMessage);
qmMessage.setErrorMessage(e.getMessage());
});
notificationRepository.updateErrorMessage(notification);

notificationRepository.updateErrorMessage(optionalNotificationByEdcId.get());
} else {
log.warn("Notification NOT FOUND for error message enrichment notification id {}", notificationMessage.getId());
}
}
}

Loading
Loading