Merge remote-tracking branch 'origin/patch-1.0.2' into development

Conflicts:
	src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExam.java
This commit is contained in:
anhefti 2020-11-17 17:29:06 +01:00
commit 3b1641994a
6 changed files with 108 additions and 42 deletions

View file

@ -196,7 +196,10 @@ public class MonitoringClientConnection implements TemplateComposer {
indicators); indicators);
this.serverPushService.runServerPush( this.serverPushService.runServerPush(
new ServerPushContext(content, Utils.truePredicate()), new ServerPushContext(
content,
Utils.truePredicate(),
MonitoringRunningExam.createServerPushUpdateErrorHandler(this.pageService, pageContext)),
this.pollInterval, this.pollInterval,
context1 -> clientConnectionDetails.updateData(), context1 -> clientConnectionDetails.updateData(),
context -> clientConnectionDetails.updateGUI()); context -> clientConnectionDetails.updateGUI());

View file

@ -26,6 +26,7 @@ import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.TreeItem;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -80,6 +81,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.session.ClientConnectionTable; import ch.ethz.seb.sebserver.gui.service.session.ClientConnectionTable;
import ch.ethz.seb.sebserver.gui.service.session.InstructionProcessor; import ch.ethz.seb.sebserver.gui.service.session.InstructionProcessor;
import ch.ethz.seb.sebserver.gui.service.session.ProctoringGUIService; import ch.ethz.seb.sebserver.gui.service.session.ProctoringGUIService;
import ch.ethz.seb.sebserver.gui.widget.Message;
@Lazy @Lazy
@Component @Component
@ -198,7 +200,9 @@ public class MonitoringRunningExam implements TemplateComposer {
ActionDefinition.MONITOR_EXAM_NEW_PROCTOR_ROOM)); ActionDefinition.MONITOR_EXAM_NEW_PROCTOR_ROOM));
this.serverPushService.runServerPush( this.serverPushService.runServerPush(
new ServerPushContext(content, Utils.truePredicate()), new ServerPushContext(
content, Utils.truePredicate(),
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
this.pollInterval, this.pollInterval,
context -> clientTable.updateValues(), context -> clientTable.updateValues(),
updateTableGUI(clientTable)); updateTableGUI(clientTable));
@ -358,7 +362,10 @@ public class MonitoringRunningExam implements TemplateComposer {
actionBuilder, actionBuilder,
proctoringSettings); proctoringSettings);
this.serverPushService.runServerPush( this.serverPushService.runServerPush(
new ServerPushContext(content, Utils.truePredicate()), new ServerPushContext(
content,
Utils.truePredicate(),
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
this.proctoringRoomUpdateInterval, this.proctoringRoomUpdateInterval,
context -> updateRoomActions( context -> updateRoomActions(
entityKey, entityKey,
@ -707,4 +714,30 @@ public class MonitoringRunningExam implements TemplateComposer {
}; };
} }
static final Function<Exception, Boolean> createServerPushUpdateErrorHandler(
final PageService pageService,
final PageContext pageContext) {
return error -> {
log.error("Fialed to update server push: {}", error.getMessage());
try {
pageService.getCurrentUser().get();
} catch (final Exception e) {
log.error("Failed to verify current user after server push error: {}", e.getMessage());
log.info("Force logout and session cleanup...");
pageContext.forwardToLoginPage();
final MessageBox logoutSuccess = new Message(
pageContext.getShell(),
pageService.getI18nSupport().getText("sebserver.logout"),
Utils.formatLineBreaks(
pageService.getI18nSupport().getText("sebserver.logout.invalid-session.message")),
SWT.ICON_INFORMATION,
pageService.getI18nSupport());
logoutSuccess.open(null);
return true;
}
return false;
};
}
} }

View file

@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.gui.service.push; package ch.ethz.seb.sebserver.gui.service.push;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
@ -18,23 +19,25 @@ import org.eclipse.swt.widgets.Display;
* @author anhefti */ * @author anhefti */
public final class ServerPushContext { public final class ServerPushContext {
private final Composite anchor; public final Composite anchor;
private final Predicate<ServerPushContext> runAgain; public final Predicate<ServerPushContext> runAgain;
public final Function<Exception, Boolean> errorHandler;
public ServerPushContext(final Composite anchor) { boolean internalStop = false;
this(anchor, context -> false);
}
public ServerPushContext( public ServerPushContext(
final Composite anchor, final Composite anchor,
final Predicate<ServerPushContext> runAgain) { final Predicate<ServerPushContext> runAgain,
final Function<Exception, Boolean> errorHandler) {
this.errorHandler = errorHandler != null
? errorHandler
: error -> true;
this.anchor = anchor; this.anchor = anchor;
this.runAgain = runAgain; this.runAgain = runAgain;
} }
public boolean runAgain() { public boolean runAgain() {
return this.runAgain.test(this); return !this.internalStop && this.runAgain.test(this);
} }
public boolean isDisposed() { public boolean isDisposed() {

View file

@ -54,43 +54,43 @@ public class ServerPushService {
} }
} }
if (business != null) { if (context.isDisposed()) {
try { continue;
log.trace("Call business on Server Push Session on: {}", Thread.currentThread().getName());
business.accept(context);
} catch (final Exception e) {
log.error("Unexpected error while do business for server push service", e);
if (context.runAgain()) {
continue;
} else {
return;
}
}
} }
if (!context.isDisposed()) { context.getDisplay().asyncExec(() -> {
if (business != null) {
log.trace("Call update on Server Push Session on: {}", Thread.currentThread().getName());
context.getDisplay().asyncExec(() -> {
try { try {
update.accept(context);
if (log.isTraceEnabled()) {
log.trace("Call business on Server Push Session on: {}",
Thread.currentThread().getName());
}
business.accept(context);
doUpdate(context, update);
} catch (final Exception e) { } catch (final Exception e) {
log.warn( log.error("Unexpected error while do business for server push service", e);
"Failed to update on Server Push Session {}. It seems that the UISession is not available anymore. " context.internalStop = context.errorHandler.apply(e);
+ "This may source from a connection interruption. cause: {}",
Thread.currentThread().getName(), e.getMessage());
} }
}); } else {
} doUpdate(context, update);
}
});
}
if (log.isInfoEnabled()) {
log.info("Stop Server Push Session on: {}", Thread.currentThread().getName());
} }
log.info("Stop Server Push Session on: {}", Thread.currentThread().getName());
try { try {
pushSession.stop(); pushSession.stop();
} catch (final Exception e) { } catch (final Exception e) {
log.warn( log.warn(
"Failed to stop Server Push Session on: {}. It seems that the UISession is not available anymore. This may source from a connection interruption", "Failed to stop Server Push Session on: {}. "
+ "It seems that the UISession is not available anymore. "
+ "This may source from a connection interruption",
Thread.currentThread().getName(), e); Thread.currentThread().getName(), e);
} }
@ -101,4 +101,28 @@ public class ServerPushService {
bgThread.setDaemon(true); bgThread.setDaemon(true);
bgThread.start(); bgThread.start();
} }
private void doUpdate(
final ServerPushContext context,
final Consumer<ServerPushContext> update) {
if (!context.isDisposed()) {
if (log.isTraceEnabled()) {
log.trace("Call update on Server Push Session on: {}",
Thread.currentThread().getName());
}
try {
update.accept(context);
} catch (final Exception e) {
log.warn(
"Failed to update on Server Push Session {}. "
+ "It seems that the UISession is not available anymore. "
+ "This may source from a connection interruption. cause: {}",
Thread.currentThread().getName(), e.getMessage());
context.internalStop = context.errorHandler.apply(e);
}
}
}
} }

View file

@ -303,10 +303,7 @@ public final class ClientConnectionTable {
this.restCallBuilder this.restCallBuilder
.withHeader(API.EXAM_MONITORING_STATE_FILTER, this.statusFilterParam) .withHeader(API.EXAM_MONITORING_STATE_FILTER, this.statusFilterParam)
.call() .call()
.get(error -> { .getOrThrow()
log.error("Error poll connection data: ", error);
return Collections.emptyList();
})
.forEach(data -> { .forEach(data -> {
final UpdatableTableItem tableItem = this.tableMapping.computeIfAbsent( final UpdatableTableItem tableItem = this.tableMapping.computeIfAbsent(
data.getConnectionId(), data.getConnectionId(),

View file

@ -113,7 +113,13 @@ public final class ImageUploadSelection extends Composite {
ImageUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl()); ImageUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl());
ImageUploadSelection.this.serverPushService.runServerPush( ImageUploadSelection.this.serverPushService.runServerPush(
new ServerPushContext(ImageUploadSelection.this, ImageUploadSelection::uploadInProgress), new ServerPushContext(
ImageUploadSelection.this,
ImageUploadSelection::uploadInProgress,
error -> {
log.error("Failed to upload image: {}", error.getMessage());
return false;
}),
200, 200,
ImageUploadSelection::update); ImageUploadSelection::update);
}); });