diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java index d55f0b1a..dc1584f0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java @@ -25,17 +25,21 @@ import ch.ethz.seb.sebserver.gbl.model.GrantEntity; public final class ClientConnection implements GrantEntity { public enum ConnectionStatus { - UNDEFINED(false), - CONNECTION_REQUESTED(false), - AUTHENTICATED(true), - ACTIVE(true), - CLOSED(false), - DISABLED(false); + UNDEFINED(false, false), + CONNECTION_REQUESTED(true, false), + AUTHENTICATED(true, true), + ACTIVE(false, true), + CLOSED(false, false), + DISABLED(false, false); + public final boolean connectingStatus; public final boolean establishedStatus; + public final boolean indicatorActiveStatus; - ConnectionStatus(final boolean establishedStatus) { + ConnectionStatus(final boolean connectingStatus, final boolean establishedStatus) { + this.connectingStatus = connectingStatus; this.establishedStatus = establishedStatus; + this.indicatorActiveStatus = connectingStatus || establishedStatus; } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java index 5d992f49..3a7f8988 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringClientConnection.java @@ -364,7 +364,7 @@ public class MonitoringClientConnection implements TemplateComposer { }) .noEventPropagation() .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) && - connectionData.clientConnection.status == ConnectionStatus.ACTIVE); + connectionData.clientConnection.status.indicatorActiveStatus); if (connectionData.clientConnection.status == ConnectionStatus.ACTIVE) { final ProctoringServiceSettings procotringSettings = restService diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java index 18404f01..6bc2fde3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java @@ -34,7 +34,6 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.exam.Exam; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings; -import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; @@ -420,7 +419,7 @@ public class MonitoringRunningExam implements TemplateComposer { private Set selectionForQuitInstruction(final ClientConnectionTable clientTable) { final Set connectionTokens = clientTable.getConnectionTokens( - ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE), + cc -> cc.status.indicatorActiveStatus, true); if (connectionTokens == null || connectionTokens.isEmpty()) { return Collections.emptySet(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java index e09d0194..0e83d160 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java @@ -189,7 +189,7 @@ public class ClientConnectionDetails { final double value = indValue.getValue(); final String displayValue = IndicatorValue.getDisplayValue(indValue); - if (!this.connectionData.clientConnection.status.establishedStatus) { + if (!this.connectionData.clientConnection.status.indicatorActiveStatus) { form.setFieldValue( indData.indicator.name, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java index 58a6a1ce..6b06dd6d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java @@ -576,7 +576,7 @@ public final class ClientConnectionTable { continue; } - if (!this.connectionData.clientConnection.status.establishedStatus) { + if (!this.connectionData.clientConnection.status.indicatorActiveStatus) { final String value = (indicatorData.indicator.type.showOnlyInActiveState) ? Constants.EMPTY_NOTE : IndicatorValue.getDisplayValue(indicatorValue); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/InstructionProcessor.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/InstructionProcessor.java index 3103e004..473fdf15 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/InstructionProcessor.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/InstructionProcessor.java @@ -72,7 +72,9 @@ public class InstructionProcessor { final PageContext pageContext) { final Set connectionTokens = selectionFunction - .apply(ClientConnection.getStatusPredicate(ConnectionStatus.ACTIVE)); + .apply(ClientConnection.getStatusPredicate( + ConnectionStatus.CONNECTION_REQUESTED, + ConnectionStatus.ACTIVE)); if (connectionTokens.isEmpty()) { log.warn("Empty selection"); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java index 0f37e322..94d2e7b1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientConnectionDAO.java @@ -145,28 +145,27 @@ public interface ClientConnectionDAO extends * @return Result refer to the ClientConnection for the specified connection token or to an error if happened */ Result byConnectionToken(String connectionToken); - /** Indicates if the client connection for exam and connection token is an active connection. - * - * @param examId the exam identifier - * @param connectionToken the connection token - * @return Result refer to the active connection flag or to an error when happened */ - Result isActiveConnection(Long examId, String connectionToken); - /** Use this to check whether a single ClientConnection is up to date or needs a refresh. * * @param clientConnection the actual ClientConnection (from the internal cache) * @return Result refer to true if the given ClientConnection is up to date */ Result isUpToDate(ClientConnection clientConnection); + /** Indicates if the client connection for given exam and connection token is + * in a ready state to send instructions. + * + * @param examId the exam identifier + * @param connectionToken the connection token + * @return Result refer to the active connection flag or to an error when happened */ + Result isInInstructionStatus(Long examId, String connectionToken); + /** Filters a set of client connection tokens to a set containing only - * connection tokens of active client connections. + * connection tokens of client connections that are in a ready state to send instructions. * - * Use this if you have a bunch of client connections to filter only the active connections - * - * @param examId - * @param connectionToken - * @return */ - Result> filterActive(Long examId, Set connectionToken); + * @param examId the exam identifier + * @param connectionToken a Set of connection tokens to filter + * @return Result refer to filtered Set of connection tokens or to an error when happened */ + Result> filterForInstructionStatus(Long examId, Set connectionToken); /** Used to get the VDI paired connection if it already exsits. * diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java index 404d9f05..cbb9af28 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java @@ -530,8 +530,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { } @Override - @Transactional(readOnly = true) - public Result isActiveConnection(final Long examId, final String connectionToken) { + public Result isInInstructionStatus(final Long examId, final String connectionToken) { return Result.tryCatch(() -> this.clientConnectionRecordMapper .selectByExample() .where( @@ -540,6 +539,12 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { .and( ClientConnectionRecordDynamicSqlSupport.examId, SqlBuilder.isEqualTo(examId)) + .and( + ClientConnectionRecordDynamicSqlSupport.status, + SqlBuilder.isEqualTo(ConnectionStatus.ACTIVE.name())) + .or( + ClientConnectionRecordDynamicSqlSupport.status, + SqlBuilder.isEqualTo(ConnectionStatus.CONNECTION_REQUESTED.name())) .build() .execute() .stream() @@ -566,7 +571,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { @Override @Transactional(readOnly = true) - public Result> filterActive(final Long examId, final Set connectionToken) { + public Result> filterForInstructionStatus(final Long examId, final Set connectionToken) { if (connectionToken == null || connectionToken.isEmpty()) { return Result.ofRuntimeError("Null or empty set reference"); } @@ -578,10 +583,15 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { .and( ClientConnectionRecordDynamicSqlSupport.examId, SqlBuilder.isEqualTo(examId)) + .and( + ClientConnectionRecordDynamicSqlSupport.status, + SqlBuilder.isEqualTo(ConnectionStatus.ACTIVE.name())) + .or( + ClientConnectionRecordDynamicSqlSupport.status, + SqlBuilder.isEqualTo(ConnectionStatus.CONNECTION_REQUESTED.name())) .build() .execute() .stream() - .filter(cc -> ConnectionStatus.ACTIVE.name().equals(cc.getStatus())) .map(ClientConnectionRecord::getConnectionToken) .collect(Collectors.toSet())); } 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 b3044978..b61baded 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 @@ -110,7 +110,7 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ return Result.tryCatch(() -> { final boolean isActive = this.clientConnectionDAO - .isActiveConnection(examId, connectionToken) + .isInInstructionStatus(examId, connectionToken) .getOr(false); if (isActive) { @@ -124,6 +124,10 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ } catch (final Exception e) { throw new RuntimeException("Unexpected: ", e); } + } else { + log.warn( + "The SEB client connection : {} is not in a ready state to process instructions. Instruction registration has been skipped", + connectionToken); } }); } @@ -140,7 +144,7 @@ public class SEBClientInstructionServiceImpl implements SEBClientInstructionServ final String attributesString = Utils.toJsonObject(attributes); final Set activeConnections = this.clientConnectionDAO - .filterActive(examId, connectionTokens) + .filterForInstructionStatus(examId, connectionTokens) .getOrElse(Collections::emptySet); connectionTokens