SEBSERV-163 back-end and fixed tests

This commit is contained in:
anhefti 2022-09-05 16:01:30 +02:00
parent cea166f065
commit 65b81af1eb
5 changed files with 97 additions and 7 deletions

View file

@ -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<Long> 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();

View file

@ -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<ClientGroup, ClientGroup>, BulkActionSupportDAO<ClientGroup> {
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<Collection<ClientGroup>> allForExam(Long examId);
@CacheEvict(
cacheNames = CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE,
key = "#examId")
default void evictCacheForExam(final Long examId) {
// just evict the cache
}
}

View file

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

View file

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

View file

@ -15,6 +15,17 @@
<heap unit="entries">100</heap>
</resources>
</cache>
<cache alias="RUNNING_EXAM_CLIENT_GROUP_CACHE">
<key-type>java.lang.Long</key-type>
<value-type>ch.ethz.seb.sebserver.gbl.util.Result</value-type>
<expiry>
<ttl unit="hours">24</ttl>
</expiry>
<resources>
<heap unit="entries">10</heap>
</resources>
</cache>
<cache alias="ACTIVE_CLIENT_CONNECTION">
<key-type>java.lang.String</key-type>