Merge remote-tracking branch 'origin/dev-1.2' into development

This commit is contained in:
anhefti 2021-09-16 12:58:49 +02:00
commit e3ac612fb3
5 changed files with 77 additions and 18 deletions

View file

@ -36,6 +36,14 @@ public interface ClientEventDAO extends EntityDAO<ClientEvent, ClientEvent> {
* @return Result refer to the specified ClientNotification or to an error when happened */
Result<ClientNotification> 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<ClientNotification> 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<ClientEvent, ClientEvent> {
/** 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<ClientNotification> confirmPendingNotification(Long notificationId, Long clientConnectionId);
Result<ClientNotification> confirmPendingNotification(Long notificationId);
Result<ClientEventRecord> initPingEvent(Long connectionId);

View file

@ -198,6 +198,43 @@ public class ClientEventDAOImpl implements ClientEventDAO {
.flatMap(ClientEventDAOImpl::toClientNotificationModel);
}
@Override
@Transactional(readOnly = true)
public Result<ClientNotification> getPendingNotificationByValue(
final Long clientConnectionId,
final Long notificationValueId) {
return Result.tryCatch(() -> {
final List<ClientEventRecord> 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<List<ClientNotification>> getPendingNotifications(final Long clientConnectionId) {
@ -240,8 +277,8 @@ public class ClientEventDAOImpl implements ClientEventDAO {
@Override
@Transactional
public Result<ClientNotification> confirmPendingNotification(final Long notificationId,
final Long clientConnectionId) {
public Result<ClientNotification> confirmPendingNotification(final Long notificationId) {
return Result.tryCatch(() -> {
final Long pk = this.clientEventRecordMapper
.selectIdsByExample()

View file

@ -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<String, String> attrs = this.jsonMapper.readValue(
attributes,
new TypeReference<Map<String, String>>() {
});
final Map<String, String> attrs = (StringUtils.isNotBlank(attributes))
? this.jsonMapper.readValue(
attributes,
new TypeReference<Map<String, String>>() {
})
: new HashMap<>();
attrs.put(API.EXAM_API_PING_INSTRUCTION_CONFIRM, String.valueOf(clientInstructionRecord.getId()));
this.clientInstructionRecordMapper.updateByPrimaryKeySelective(

View file

@ -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);
}

View file

@ -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<Long> pendingNotifications = new HashSet<>();
private final Set<Long> 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