diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientEventDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientEventDAO.java index d3ca8f56..87a6f41b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientEventDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientEventDAO.java @@ -36,6 +36,14 @@ public interface ClientEventDAO extends EntityDAO { * @return Result refer to the specified ClientNotification or to an error when happened */ Result getPendingNotification(Long notificationId); + /** Get a pending notification by the notification value identifier (sent by SEB) + * + * @param notificationValueId notification value identifier (sent by SEB) + * @return Result refer to the specified ClientNotification or to an error when happened */ + Result getPendingNotificationByValue( + Long clientConnectionId, + Long notificationValueId); + /** Get all pending notifications for a given client connection. * * @param clientConnectionId The client connection identifier @@ -51,9 +59,8 @@ public interface ClientEventDAO extends EntityDAO { /** Used to confirm a pending notification so that the notification is not pending anymore * * @param notificationId the notification identifier - * @param clientConnectionId the client connection identifier * @return Result refer to the confirmed notification or to en error when happened */ - Result confirmPendingNotification(Long notificationId, Long clientConnectionId); + Result confirmPendingNotification(Long notificationId); Result initPingEvent(Long connectionId); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java index 7c4b583a..48b52537 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java @@ -198,6 +198,43 @@ public class ClientEventDAOImpl implements ClientEventDAO { .flatMap(ClientEventDAOImpl::toClientNotificationModel); } + @Override + @Transactional(readOnly = true) + public Result getPendingNotificationByValue( + final Long clientConnectionId, + final Long notificationValueId) { + + return Result.tryCatch(() -> { + + final List records = this.clientEventRecordMapper + .selectByExample() + .where(ClientEventRecordDynamicSqlSupport.clientConnectionId, isEqualTo(clientConnectionId)) + .and(ClientEventRecordDynamicSqlSupport.type, isEqualTo(EventType.NOTIFICATION.id)) + .build() + .execute(); + + if (log.isDebugEnabled()) { + log.debug("Found notification for clientConnectionId: {} notification: {}", + clientConnectionId, + records); + } + + return records.stream() + .filter(rec -> { + final BigDecimal numericValue = rec.getNumericValue(); + if (numericValue == null) { + return false; + } + return numericValue.longValue() == notificationValueId; + }) + .findFirst() + .orElseThrow(() -> new IllegalStateException( + "Failed to find pending notification event for confirm:" + notificationValueId)); + + }) + .flatMap(ClientEventDAOImpl::toClientNotificationModel); + } + @Override @Transactional(readOnly = true) public Result> getPendingNotifications(final Long clientConnectionId) { @@ -240,8 +277,8 @@ public class ClientEventDAOImpl implements ClientEventDAO { @Override @Transactional - public Result confirmPendingNotification(final Long notificationId, - final Long clientConnectionId) { + public Result confirmPendingNotification(final Long notificationId) { + return Result.tryCatch(() -> { final Long pk = this.clientEventRecordMapper .selectIdsByExample() diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java index c3a16593..639a5e03 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java @@ -10,10 +10,12 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao.impl; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.mybatis.dynamic.sql.SqlBuilder; @@ -153,10 +155,12 @@ public class ClientInstructionDAOImpl implements ClientInstructionDAO { if (needsConfirmation) { - final Map attrs = this.jsonMapper.readValue( - attributes, - new TypeReference>() { - }); + final Map attrs = (StringUtils.isNotBlank(attributes)) + ? this.jsonMapper.readValue( + attributes, + new TypeReference>() { + }) + : new HashMap<>(); attrs.put(API.EXAM_API_PING_INSTRUCTION_CONFIRM, String.valueOf(clientInstructionRecord.getId())); this.clientInstructionRecordMapper.updateByPrimaryKeySelective( diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientInstructionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientInstructionServiceImpl.java index 90e6d941..f2b9cb7a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientInstructionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientInstructionServiceImpl.java @@ -115,12 +115,17 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ if (isActive) { try { - final String attributesString = this.jsonMapper.writeValueAsString(attributes); + + final String attributesString = (attributes != null && !attributes.isEmpty()) + ? this.jsonMapper.writeValueAsString(attributes) + : null; + this.clientInstructionDAO .insert(examId, type, attributesString, connectionToken, needsConfirm) .map(this::putToCache) .onError(error -> log.error("Failed to register instruction: {}", error.getMessage())) .getOrThrow(); + } catch (final Exception e) { throw new RuntimeException("Unexpected: ", e); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientNotificationServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientNotificationServiceImpl.java index 912e831d..b69146fe 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientNotificationServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientNotificationServiceImpl.java @@ -29,6 +29,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType import ch.ethz.seb.sebserver.gbl.model.session.ClientNotification; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService; import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService; @@ -44,6 +45,7 @@ public class SEBClientNotificationServiceImpl implements SEBClientNotificationSe private static final String CONFIRM_INSTRUCTION_ATTR_TYPE = "type"; private final ClientEventDAO clientEventDAO; + private final ClientConnectionDAO clientConnectionDAO; private final SEBClientInstructionService sebClientInstructionService; private final Set pendingNotifications = new HashSet<>(); private final Set examUpdate = new HashSet<>(); @@ -52,9 +54,11 @@ public class SEBClientNotificationServiceImpl implements SEBClientNotificationSe public SEBClientNotificationServiceImpl( final ClientEventDAO clientEventDAO, + final ClientConnectionDAO clientConnectionDAO, final SEBClientInstructionService sebClientInstructionService) { this.clientEventDAO = clientEventDAO; + this.clientConnectionDAO = clientConnectionDAO; this.sebClientInstructionService = sebClientInstructionService; } @@ -75,13 +79,16 @@ public class SEBClientNotificationServiceImpl implements SEBClientNotificationSe @Override public void confirmPendingNotification(final ClientEvent event, final String connectionToken) { try { + + final ClientConnection clientConnection = this.clientConnectionDAO + .byConnectionToken(connectionToken) + .getOrThrow(); final Long notificationId = (long) event.getValue(); - this.clientEventDAO.getPendingNotification(notificationId) - .flatMap(notification -> this.clientEventDAO.confirmPendingNotification( - notificationId, - notification.connectionId)) - .map(this::removeFromCache); + this.clientEventDAO.getPendingNotificationByValue(clientConnection.id, notificationId) + .flatMap(notification -> this.clientEventDAO.confirmPendingNotification(notification.id)) + .map(this::removeFromCache) + .onError(error -> log.error("Failed to confirm pending notification: {}", event, error)); } catch (final Exception e) { log.error( @@ -98,10 +105,9 @@ public class SEBClientNotificationServiceImpl implements SEBClientNotificationSe return this.clientEventDAO.getPendingNotification(notificationId) .map(notification -> this.confirmClientSide(notification, examId, connectionToken)) - .flatMap(notification -> this.clientEventDAO.confirmPendingNotification( - notificationId, - notification.connectionId)) - .map(this::removeFromCache); + .flatMap(notification -> this.clientEventDAO.confirmPendingNotification(notificationId)) + .map(this::removeFromCache) + .onError(error -> log.error("Failed to confirm pending notification: {}", notificationId, error)); } @Override