SEBSERV-163 back-end and fixed tests
This commit is contained in:
parent
cea166f065
commit
65b81af1eb
5 changed files with 97 additions and 7 deletions
|
@ -9,8 +9,10 @@
|
||||||
package ch.ethz.seb.sebserver.gbl.model.session;
|
package ch.ethz.seb.sebserver.gbl.model.session;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
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.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
|
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.model.exam.Indicator;
|
||||||
import ch.ethz.seb.sebserver.gbl.monitoring.IndicatorValue;
|
import ch.ethz.seb.sebserver.gbl.monitoring.IndicatorValue;
|
||||||
import ch.ethz.seb.sebserver.gbl.monitoring.SimpleIndicatorValue;
|
import ch.ethz.seb.sebserver.gbl.monitoring.SimpleIndicatorValue;
|
||||||
|
@ -41,6 +44,8 @@ public class ClientConnectionData implements GrantEntity {
|
||||||
public final Boolean missingPing;
|
public final Boolean missingPing;
|
||||||
public final Boolean pendingNotification;
|
public final Boolean pendingNotification;
|
||||||
|
|
||||||
|
private Set<Long> groups = null;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public ClientConnectionData(
|
public ClientConnectionData(
|
||||||
@JsonProperty(ATTR_MISSING_PING) final Boolean missingPing,
|
@JsonProperty(ATTR_MISSING_PING) final Boolean missingPing,
|
||||||
|
@ -64,6 +69,19 @@ public class ClientConnectionData implements GrantEntity {
|
||||||
this.indicatorValues = Utils.immutableListOf(indicatorValues);
|
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
|
@Override
|
||||||
public EntityType entityType() {
|
public EntityType entityType() {
|
||||||
return this.clientConnection.entityType();
|
return this.clientConnection.entityType();
|
||||||
|
|
|
@ -10,6 +10,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
||||||
|
|
||||||
import java.util.Collection;
|
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.model.exam.ClientGroup;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
|
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 */
|
/** Concrete EntityDAO interface of ClientGroup entities */
|
||||||
public interface ClientGroupDAO extends EntityDAO<ClientGroup, ClientGroup>, BulkActionSupportDAO<ClientGroup> {
|
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.
|
/** Get a collection of all ClientGroup entities for a specified exam.
|
||||||
*
|
*
|
||||||
* @param examId the Exam identifier to get the ClientGroups for
|
* @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 */
|
* @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);
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
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.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.ExamDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigService;
|
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 static final Logger log = LoggerFactory.getLogger(ExamSessionCacheService.class);
|
||||||
|
|
||||||
private final ExamDAO examDAO;
|
private final ExamDAO examDAO;
|
||||||
|
private final ClientGroupDAO clientGroupDAO;
|
||||||
private final ClientConnectionDAO clientConnectionDAO;
|
private final ClientConnectionDAO clientConnectionDAO;
|
||||||
private final InternalClientConnectionDataFactory internalClientConnectionDataFactory;
|
private final InternalClientConnectionDataFactory internalClientConnectionDataFactory;
|
||||||
private final ExamConfigService sebExamConfigService;
|
private final ExamConfigService sebExamConfigService;
|
||||||
|
@ -52,6 +54,7 @@ public class ExamSessionCacheService {
|
||||||
|
|
||||||
protected ExamSessionCacheService(
|
protected ExamSessionCacheService(
|
||||||
final ExamDAO examDAO,
|
final ExamDAO examDAO,
|
||||||
|
final ClientGroupDAO clientGroupDAO,
|
||||||
final ClientConnectionDAO clientConnectionDAO,
|
final ClientConnectionDAO clientConnectionDAO,
|
||||||
final InternalClientConnectionDataFactory internalClientConnectionDataFactory,
|
final InternalClientConnectionDataFactory internalClientConnectionDataFactory,
|
||||||
final ExamConfigService sebExamConfigService,
|
final ExamConfigService sebExamConfigService,
|
||||||
|
@ -59,6 +62,7 @@ public class ExamSessionCacheService {
|
||||||
final RemoteProctoringRoomDAO remoteProctoringRoomDAO) {
|
final RemoteProctoringRoomDAO remoteProctoringRoomDAO) {
|
||||||
|
|
||||||
this.examDAO = examDAO;
|
this.examDAO = examDAO;
|
||||||
|
this.clientGroupDAO = clientGroupDAO;
|
||||||
this.clientConnectionDAO = clientConnectionDAO;
|
this.clientConnectionDAO = clientConnectionDAO;
|
||||||
this.internalClientConnectionDataFactory = internalClientConnectionDataFactory;
|
this.internalClientConnectionDataFactory = internalClientConnectionDataFactory;
|
||||||
this.sebExamConfigService = sebExamConfigService;
|
this.sebExamConfigService = sebExamConfigService;
|
||||||
|
@ -98,6 +102,7 @@ public class ExamSessionCacheService {
|
||||||
log.trace("Conditional eviction of running Exam from cache: {}", isRunning(exam));
|
log.trace("Conditional eviction of running Exam from cache: {}", isRunning(exam));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clientGroupDAO.evictCacheForExam(exam.id);
|
||||||
return exam;
|
return exam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +115,7 @@ public class ExamSessionCacheService {
|
||||||
log.trace("Conditional eviction of running Exam from cache: {}", examId);
|
log.trace("Conditional eviction of running Exam from cache: {}", examId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clientGroupDAO.evictCacheForExam(examId);
|
||||||
return examId;
|
return examId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,20 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
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.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
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;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
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.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientGroupDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -21,34 +29,64 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificati
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
public class InternalClientConnectionDataFactory {
|
public class InternalClientConnectionDataFactory {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(InternalClientConnectionDataFactory.class);
|
||||||
|
|
||||||
private final ClientIndicatorFactory clientIndicatorFactory;
|
private final ClientIndicatorFactory clientIndicatorFactory;
|
||||||
private final SEBClientNotificationService sebClientNotificationService;
|
private final SEBClientNotificationService sebClientNotificationService;
|
||||||
|
private final ClientGroupDAO clientGroupDAO;
|
||||||
|
private final ClientGroupMatcherService clientGroupMatcherService;
|
||||||
|
|
||||||
public InternalClientConnectionDataFactory(
|
public InternalClientConnectionDataFactory(
|
||||||
final ClientIndicatorFactory clientIndicatorFactory,
|
final ClientIndicatorFactory clientIndicatorFactory,
|
||||||
final SEBClientNotificationService sebClientNotificationService) {
|
final SEBClientNotificationService sebClientNotificationService,
|
||||||
|
final ClientGroupDAO clientGroupDAO,
|
||||||
|
final ClientGroupMatcherService clientGroupMatcherService) {
|
||||||
|
|
||||||
this.clientIndicatorFactory = clientIndicatorFactory;
|
this.clientIndicatorFactory = clientIndicatorFactory;
|
||||||
this.sebClientNotificationService = sebClientNotificationService;
|
this.sebClientNotificationService = sebClientNotificationService;
|
||||||
|
this.clientGroupDAO = clientGroupDAO;
|
||||||
|
this.clientGroupMatcherService = clientGroupMatcherService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientConnectionDataInternal createClientConnectionData(final ClientConnection clientConnection) {
|
public ClientConnectionDataInternal createClientConnectionData(final ClientConnection clientConnection) {
|
||||||
|
|
||||||
|
ClientConnectionDataInternal result;
|
||||||
if (clientConnection.status == ConnectionStatus.CLOSED
|
if (clientConnection.status == ConnectionStatus.CLOSED
|
||||||
|| clientConnection.status == ConnectionStatus.DISABLED) {
|
|| clientConnection.status == ConnectionStatus.DISABLED) {
|
||||||
|
|
||||||
// dispose notification indication for closed or disabled connection
|
// dispose notification indication for closed or disabled connection
|
||||||
return new ClientConnectionDataInternal(
|
result = new ClientConnectionDataInternal(
|
||||||
clientConnection,
|
clientConnection,
|
||||||
() -> false,
|
() -> false,
|
||||||
this.clientIndicatorFactory.createFor(clientConnection));
|
this.clientIndicatorFactory.createFor(clientConnection));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
result = new ClientConnectionDataInternal(
|
||||||
|
clientConnection,
|
||||||
|
() -> this.sebClientNotificationService
|
||||||
|
.hasAnyPendingNotification(clientConnection),
|
||||||
|
this.clientIndicatorFactory.createFor(clientConnection));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ClientConnectionDataInternal(
|
// set client groups for connection
|
||||||
clientConnection,
|
if (clientConnection.examId != null) {
|
||||||
() -> this.sebClientNotificationService
|
final Collection<ClientGroup> clientGroups = this.clientGroupDAO
|
||||||
.hasAnyPendingNotification(clientConnection),
|
.allForExam(clientConnection.examId)
|
||||||
this.clientIndicatorFactory.createFor(clientConnection));
|
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,17 @@
|
||||||
<heap unit="entries">100</heap>
|
<heap unit="entries">100</heap>
|
||||||
</resources>
|
</resources>
|
||||||
</cache>
|
</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">
|
<cache alias="ACTIVE_CLIENT_CONNECTION">
|
||||||
<key-type>java.lang.String</key-type>
|
<key-type>java.lang.String</key-type>
|
||||||
|
|
Loading…
Reference in a new issue