fixed notification changes in GUI

This commit is contained in:
anhefti 2021-09-20 15:46:20 +02:00
parent dffb0e61f8
commit 7d647cc9c2
8 changed files with 63 additions and 35 deletions

View file

@ -28,6 +28,7 @@ public class GuiServiceInfo {
private final String contextPath;
private final UriComponentsBuilder internalServerURIBuilder;
private final UriComponentsBuilder externalServerURIBuilder;
private final boolean distributedSetup;
public GuiServiceInfo(
@Value("${server.address}") final String internalServer,
@ -36,7 +37,8 @@ public class GuiServiceInfo {
@Value("${sebserver.gui.http.external.servername}") final String externalServer,
@Value("${sebserver.gui.http.external.port}") final String externalPort,
@Value("${sebserver.gui.entrypoint:/gui}") final String entryPoint,
@Value("${server.servlet.context-path:/}") final String contextPath) {
@Value("${server.servlet.context-path:/}") final String contextPath,
@Value("${sebserver.webservice.distributed:false}") final boolean distributedSetup) {
if (StringUtils.isBlank(externalScheme)) {
throw new RuntimeException("Missing mandatory inital parameter sebserver.gui.http.external.servername");
@ -69,6 +71,8 @@ public class GuiServiceInfo {
if (StringUtils.isNotBlank(contextPath) && !contextPath.equals("/")) {
this.externalServerURIBuilder.path(contextPath);
}
this.distributedSetup = distributedSetup;
}
public String getExternalScheme() {
@ -107,4 +111,8 @@ public class GuiServiceInfo {
return this.externalServerURIBuilder.cloneBuilder();
}
public boolean isDistributedSetup() {
return this.distributedSetup;
}
}

View file

@ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.gui.content;
import java.util.Collection;
import java.util.function.Supplier;
import org.apache.commons.lang3.BooleanUtils;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -195,10 +194,9 @@ public class MonitoringClientConnection implements TemplateComposer {
indicators);
// NOTIFICATIONS
final boolean hasNotifications = BooleanUtils.isTrue(connectionData.pendingNotification());
Supplier<EntityTable<ClientNotification>> _notificationTableSupplier = () -> null;
if (hasNotifications) {
final PageService.PageActionBuilder actionBuilder = this.pageService
if (connectionData.clientConnection.status.clientActiveStatus) {
final PageService.PageActionBuilder notificationActionBuilder = this.pageService
.pageActionBuilder(
pageContext
.clearAttributes()
@ -240,7 +238,7 @@ public class MonitoringClientConnection implements TemplateComposer {
this::getServerTime)
.sortable()
.widthProportion(1))
.withDefaultAction(t -> actionBuilder
.withDefaultAction(t -> notificationActionBuilder
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_CONFIRM_NOTIFICATION)
.withParentEntityKey(parentEntityKey)
.withConfirm(() -> NOTIFICATION_LIST_CONFIRM_TEXT_KEY)
@ -252,7 +250,7 @@ public class MonitoringClientConnection implements TemplateComposer {
ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_CONFIRM_NOTIFICATION))
.compose(pageContext.copyOf(content));
actionBuilder
notificationActionBuilder
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_CONFIRM_NOTIFICATION)
.withParentEntityKey(parentEntityKey)
.withConfirm(() -> NOTIFICATION_LIST_CONFIRM_TEXT_KEY)

View file

@ -41,6 +41,7 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.GuiServiceInfo;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
@ -92,6 +93,7 @@ public class MonitoringRunningExam implements TemplateComposer {
private final InstructionProcessor instructionProcessor;
private final MonitoringExamSearchPopup monitoringExamSearchPopup;
private final MonitoringProctoringService monitoringProctoringService;
private final boolean distributedSetup;
private final long pollInterval;
private final long proctoringRoomUpdateInterval;
@ -102,6 +104,7 @@ public class MonitoringRunningExam implements TemplateComposer {
final InstructionProcessor instructionProcessor,
final MonitoringExamSearchPopup monitoringExamSearchPopup,
final MonitoringProctoringService monitoringProctoringService,
final GuiServiceInfo guiServiceInfo,
@Value("${sebserver.gui.webservice.poll-interval:1000}") final long pollInterval,
@Value("${sebserver.gui.remote.proctoring.rooms.update.poll-interval:5000}") final long proctoringRoomUpdateInterval) {
@ -113,6 +116,7 @@ public class MonitoringRunningExam implements TemplateComposer {
this.instructionProcessor = instructionProcessor;
this.monitoringProctoringService = monitoringProctoringService;
this.pollInterval = pollInterval;
this.distributedSetup = guiServiceInfo.isDistributedSetup();
this.monitoringExamSearchPopup = monitoringExamSearchPopup;
this.proctoringRoomUpdateInterval = proctoringRoomUpdateInterval;
}
@ -164,7 +168,8 @@ public class MonitoringRunningExam implements TemplateComposer {
exam,
indicators,
restCall,
pushContext);
pushContext,
this.distributedSetup);
clientTable
.withDefaultAction(

View file

@ -83,8 +83,8 @@ public class ServerPushService {
});
}
if (log.isInfoEnabled()) {
log.info("Stop Server Push Session on: {}", Thread.currentThread().getName());
if (log.isDebugEnabled()) {
log.debug("Stop Server Push Session on: {}", Thread.currentThread().getName());
}
try {
@ -100,7 +100,9 @@ public class ServerPushService {
});
log.info("Start new Server Push Session on: {}", bgThread.getName());
if (log.isDebugEnabled()) {
log.debug("Start new Server Push Session on: {}", bgThread.getName());
}
bgThread.setDaemon(true);
bgThread.start();

View file

@ -25,7 +25,6 @@ import ch.ethz.seb.sebserver.gbl.model.Domain;
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.QuizData;
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.session.ClientNotification;
import ch.ethz.seb.sebserver.gbl.model.session.IndicatorValue;
@ -69,6 +68,7 @@ public class ClientConnectionDetails {
private ClientConnectionData connectionData = null;
private boolean statusChanged = true;
private long startTime = -1;
private Consumer<ClientConnectionData> statusChangeListener = null;
public ClientConnectionDetails(
@ -147,13 +147,22 @@ public class ClientConnectionDetails {
.toBoolean(connectionData.missingPing);
}
this.connectionData = connectionData;
if (this.startTime < 0) {
this.startTime = System.currentTimeMillis();
}
}
public void updateGUI(
final Supplier<EntityTable<ClientNotification>> notificationTableSupplier,
final PageContext pageContext) {
// Note: This is to update the whole page (by reload) only when the status has changed
// while this page was open. This prevent constant page reloads.
if (this.statusChanged && System.currentTimeMillis() - this.startTime > Constants.SECOND_IN_MILLIS) {
reloadPage(pageContext);
return;
}
if (this.connectionData == null) {
return;
}
@ -214,16 +223,8 @@ public class ClientConnectionDetails {
// update notifications
final EntityTable<ClientNotification> notificationTable = notificationTableSupplier.get();
if (notificationTable != null && this.connectionData.clientConnection.status == ConnectionStatus.CLOSED) {
reloadPage(pageContext);
} else {
if (BooleanUtils.isTrue(this.connectionData.pendingNotification())) {
if (notificationTable == null) {
reloadPage(pageContext);
} else {
notificationTable.refreshPageSize();
}
}
if (notificationTable != null) {
notificationTable.refreshPageSize();
}
}

View file

@ -97,6 +97,7 @@ public final class ClientConnectionTable {
private final Exam exam;
private final RestCall<Collection<ClientConnectionData>>.RestCallBuilder restCallBuilder;
private final ServerPushContext pushConext;
private final boolean distributedSetup;
private final Map<Long, IndicatorData> indicatorMapping;
private final Table table;
@ -119,8 +120,6 @@ public final class ClientConnectionTable {
private boolean forceUpdateAll = false;
private boolean updateInProgress = false;
//private int updateErrors = 0;
public ClientConnectionTable(
final PageService pageService,
final Composite tableRoot,
@ -128,13 +127,15 @@ public final class ClientConnectionTable {
final Exam exam,
final Collection<Indicator> indicators,
final RestCall<Collection<ClientConnectionData>>.RestCallBuilder restCallBuilder,
final ServerPushContext pushConext) {
final ServerPushContext pushConext,
final boolean distributedSetup) {
this.pageService = pageService;
this.asyncRunner = asyncRunner;
this.exam = exam;
this.restCallBuilder = restCallBuilder;
this.pushConext = pushConext;
this.distributedSetup = distributedSetup;
final WidgetFactory widgetFactory = pageService.getWidgetFactory();
final ResourceService resourceService = pageService.getResourceService();
@ -332,9 +333,8 @@ public final class ClientConnectionTable {
private void updateValuesAsync(final boolean needsSync) {
try {
// TODO forceUpdateAll doeasn't work on distributed
if (this.statusFilterChanged || this.forceUpdateAll || needsSync) {
final boolean sync = this.statusFilterChanged || this.forceUpdateAll || needsSync || this.distributedSetup;
if (sync) {
this.toDelete.clear();
this.toDelete.addAll(this.tableMapping.keySet());
}
@ -351,7 +351,7 @@ public final class ClientConnectionTable {
data.getConnectionId(),
UpdatableTableItem::new);
tableItem.push(data);
if (this.statusFilterChanged || this.forceUpdateAll || needsSync) {
if (sync) {
this.toDelete.remove(data.getConnectionId());
}
});
@ -680,8 +680,11 @@ public final class ClientConnectionTable {
!this.connectionData.dataEquals(connectionData);
final boolean statusChanged = this.connectionData == null ||
this.connectionData.clientConnection.status != connectionData.clientConnection.status;
final boolean notificationChanged = this.connectionData == null ||
BooleanUtils.toBoolean(this.connectionData.pendingNotification) != BooleanUtils
.toBoolean(connectionData.pendingNotification);
if (statusChanged) {
if (statusChanged || notificationChanged) {
ClientConnectionTable.this.needsSort = true;
}

View file

@ -22,13 +22,13 @@ import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants;
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.ClientEvent;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
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.WebserviceInfo;
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;
@ -51,20 +51,25 @@ public class SEBClientNotificationServiceImpl implements SEBClientNotificationSe
private final Set<Long> examUpdate = new HashSet<>();
private long lastUpdate = 0;
private long updateInterval = 5 * Constants.SECOND_IN_MILLIS;
public SEBClientNotificationServiceImpl(
final ClientEventDAO clientEventDAO,
final ClientConnectionDAO clientConnectionDAO,
final SEBClientInstructionService sebClientInstructionService) {
final SEBClientInstructionService sebClientInstructionService,
final WebserviceInfo webserviceInfo) {
this.clientEventDAO = clientEventDAO;
this.clientConnectionDAO = clientConnectionDAO;
this.sebClientInstructionService = sebClientInstructionService;
if (webserviceInfo.isDistributed()) {
this.updateInterval = Constants.SECOND_IN_MILLIS;
}
}
@Override
public Boolean hasAnyPendingNotification(final ClientConnection clientConnection) {
if (clientConnection.status != ConnectionStatus.ACTIVE) {
if (!clientConnection.status.clientActiveStatus) {
return false;
}
updateCache(clientConnection.examId);
@ -141,7 +146,7 @@ public class SEBClientNotificationServiceImpl implements SEBClientNotificationSe
}
private final void updateCache(final Long examId) {
if (System.currentTimeMillis() - this.lastUpdate > 5 * Constants.SECOND_IN_MILLIS) {
if (System.currentTimeMillis() - this.lastUpdate > this.updateInterval) {
this.examUpdate.clear();
this.pendingNotifications.clear();
this.lastUpdate = System.currentTimeMillis();

View file

@ -42,4 +42,10 @@ public class ReplTest {
// assertEquals(Constants.DAY_IN_MIN, interv.toDurationMillis() / Constants.MINUTE_IN_MILLIS);
// }
// @Test
// public void testBooleanMatch() {
// assertTrue(Boolean.valueOf(false) == Boolean.valueOf(false));
// assertTrue(new Boolean(false) == new Boolean(false));
// }
}