From 65b81af1eb8825b2f00e91c57c165b6e085aed98 Mon Sep 17 00:00:00 2001 From: anhefti Date: Mon, 5 Sep 2022 16:01:30 +0200 Subject: [PATCH] SEBSERV-163 back-end and fixed tests --- .../model/session/ClientConnectionData.java | 18 +++++++ .../servicelayer/dao/ClientGroupDAO.java | 17 ++++++ .../session/impl/ExamSessionCacheService.java | 6 +++ .../InternalClientConnectionDataFactory.java | 52 ++++++++++++++++--- src/main/resources/config/ehcache.xml | 11 ++++ 5 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java index 1e4756de..1724f1bb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java @@ -9,8 +9,10 @@ package ch.ethz.seb.sebserver.gbl.model.session; import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -20,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.GrantEntity; +import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.monitoring.IndicatorValue; import ch.ethz.seb.sebserver.gbl.monitoring.SimpleIndicatorValue; @@ -41,6 +44,8 @@ public class ClientConnectionData implements GrantEntity { public final Boolean missingPing; public final Boolean pendingNotification; + private Set groups = null; + @JsonCreator public ClientConnectionData( @JsonProperty(ATTR_MISSING_PING) final Boolean missingPing, @@ -64,6 +69,19 @@ public class ClientConnectionData implements GrantEntity { this.indicatorValues = Utils.immutableListOf(indicatorValues); } + @JsonIgnore + public void addToClientGroup(final ClientGroup group) { + if (this.groups == null) { + this.groups = new HashSet<>(1); + } + this.groups.add(group.id); + } + + @JsonIgnore + public boolean isInClientGroup(final Long clientGroupId) { + return this.groups != null && this.groups.contains(clientGroupId); + } + @Override public EntityType entityType() { return this.clientConnection.entityType(); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientGroupDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientGroupDAO.java index 19ec33a2..5f63f1da 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientGroupDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ClientGroupDAO.java @@ -10,6 +10,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; import java.util.Collection; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; + import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO; @@ -17,10 +20,24 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSuppor /** Concrete EntityDAO interface of ClientGroup entities */ public interface ClientGroupDAO extends EntityDAO, BulkActionSupportDAO { + public static final String CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE = "RUNNING_EXAM_CLIENT_GROUP_CACHE"; + /** Get a collection of all ClientGroup entities for a specified exam. * * @param examId the Exam identifier to get the ClientGroups for * @return Result referring to the collection of ClientGroups of an Exam or to an error if happened */ + @Cacheable( + cacheNames = CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE, + key = "#examId", + condition = "#examId!=null", + unless = "#result.hasError()") Result> allForExam(Long examId); + @CacheEvict( + cacheNames = CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE, + key = "#examId") + default void evictCacheForExam(final Long examId) { + // just evict the cache + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionCacheService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionCacheService.java index c6a3ddcd..a81f8304 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionCacheService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionCacheService.java @@ -23,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; 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.ClientGroupDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigService; @@ -45,6 +46,7 @@ public class ExamSessionCacheService { private static final Logger log = LoggerFactory.getLogger(ExamSessionCacheService.class); private final ExamDAO examDAO; + private final ClientGroupDAO clientGroupDAO; private final ClientConnectionDAO clientConnectionDAO; private final InternalClientConnectionDataFactory internalClientConnectionDataFactory; private final ExamConfigService sebExamConfigService; @@ -52,6 +54,7 @@ public class ExamSessionCacheService { protected ExamSessionCacheService( final ExamDAO examDAO, + final ClientGroupDAO clientGroupDAO, final ClientConnectionDAO clientConnectionDAO, final InternalClientConnectionDataFactory internalClientConnectionDataFactory, final ExamConfigService sebExamConfigService, @@ -59,6 +62,7 @@ public class ExamSessionCacheService { final RemoteProctoringRoomDAO remoteProctoringRoomDAO) { this.examDAO = examDAO; + this.clientGroupDAO = clientGroupDAO; this.clientConnectionDAO = clientConnectionDAO; this.internalClientConnectionDataFactory = internalClientConnectionDataFactory; this.sebExamConfigService = sebExamConfigService; @@ -98,6 +102,7 @@ public class ExamSessionCacheService { log.trace("Conditional eviction of running Exam from cache: {}", isRunning(exam)); } + this.clientGroupDAO.evictCacheForExam(exam.id); return exam; } @@ -110,6 +115,7 @@ public class ExamSessionCacheService { log.trace("Conditional eviction of running Exam from cache: {}", examId); } + this.clientGroupDAO.evictCacheForExam(examId); return examId; } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/InternalClientConnectionDataFactory.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/InternalClientConnectionDataFactory.java index 54b23f19..80afbc6a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/InternalClientConnectionDataFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/InternalClientConnectionDataFactory.java @@ -8,12 +8,20 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; +import java.util.Collection; +import java.util.Collections; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; 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.monitoring.ClientGroupMatcherService; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientGroupDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService; @Lazy @@ -21,34 +29,64 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificati @WebServiceProfile public class InternalClientConnectionDataFactory { + private static final Logger log = LoggerFactory.getLogger(InternalClientConnectionDataFactory.class); + private final ClientIndicatorFactory clientIndicatorFactory; private final SEBClientNotificationService sebClientNotificationService; + private final ClientGroupDAO clientGroupDAO; + private final ClientGroupMatcherService clientGroupMatcherService; public InternalClientConnectionDataFactory( final ClientIndicatorFactory clientIndicatorFactory, - final SEBClientNotificationService sebClientNotificationService) { + final SEBClientNotificationService sebClientNotificationService, + final ClientGroupDAO clientGroupDAO, + final ClientGroupMatcherService clientGroupMatcherService) { this.clientIndicatorFactory = clientIndicatorFactory; this.sebClientNotificationService = sebClientNotificationService; + this.clientGroupDAO = clientGroupDAO; + this.clientGroupMatcherService = clientGroupMatcherService; } public ClientConnectionDataInternal createClientConnectionData(final ClientConnection clientConnection) { + ClientConnectionDataInternal result; if (clientConnection.status == ConnectionStatus.CLOSED || clientConnection.status == ConnectionStatus.DISABLED) { // dispose notification indication for closed or disabled connection - return new ClientConnectionDataInternal( + result = new ClientConnectionDataInternal( clientConnection, () -> false, this.clientIndicatorFactory.createFor(clientConnection)); + } else { + + result = new ClientConnectionDataInternal( + clientConnection, + () -> this.sebClientNotificationService + .hasAnyPendingNotification(clientConnection), + this.clientIndicatorFactory.createFor(clientConnection)); } - return new ClientConnectionDataInternal( - clientConnection, - () -> this.sebClientNotificationService - .hasAnyPendingNotification(clientConnection), - this.clientIndicatorFactory.createFor(clientConnection)); + // set client groups for connection + if (clientConnection.examId != null) { + final Collection clientGroups = this.clientGroupDAO + .allForExam(clientConnection.examId) + .onError( + error -> log.error("Failed to get client groups for clientConnection: {}", clientConnection, + error)) + .getOr(Collections.emptyList()); + + if (!clientGroups.isEmpty()) { + clientGroups.forEach(clientGroup -> { + if (this.clientGroupMatcherService.isInGroup(clientConnection, clientGroup)) { + result.addToClientGroup(clientGroup); + } + }); + } + } + + return result; } } diff --git a/src/main/resources/config/ehcache.xml b/src/main/resources/config/ehcache.xml index 8a12f3f4..74e0a0fa 100644 --- a/src/main/resources/config/ehcache.xml +++ b/src/main/resources/config/ehcache.xml @@ -15,6 +15,17 @@ 100 + + + java.lang.Long + ch.ethz.seb.sebserver.gbl.util.Result + + 24 + + + 10 + + java.lang.String