fixed concurrent user login within ServerPushService
This commit is contained in:
parent
1b9b201da9
commit
1d7bd02382
6 changed files with 104 additions and 41 deletions
|
@ -163,7 +163,10 @@ public class MonitoringClientConnection implements TemplateComposer {
|
|||
indicators);
|
||||
|
||||
this.serverPushService.runServerPush(
|
||||
new ServerPushContext(content, Utils.truePredicate()),
|
||||
new ServerPushContext(
|
||||
content,
|
||||
Utils.truePredicate(),
|
||||
MonitoringRunningExam.createServerPushUpdateErrorHandler(this.pageService, pageContext)),
|
||||
this.pollInterval,
|
||||
context1 -> clientConnectionDetails.updateData(),
|
||||
context -> clientConnectionDetails.updateGUI());
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.eclipse.swt.SWT;
|
|||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -57,6 +58,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClient
|
|||
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.InstructionProcessor;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
|
@ -149,7 +151,9 @@ public class MonitoringRunningExam implements TemplateComposer {
|
|||
ActionDefinition.MONITOR_EXAM_DISABLE_SELECTED_CONNECTION));
|
||||
|
||||
this.serverPushService.runServerPush(
|
||||
new ServerPushContext(content, Utils.truePredicate()),
|
||||
new ServerPushContext(
|
||||
content, Utils.truePredicate(),
|
||||
createServerPushUpdateErrorHandler(this.pageService, pageContext)),
|
||||
this.pollInterval,
|
||||
context -> clientTable.updateValues(),
|
||||
updateTableGUI(clientTable));
|
||||
|
@ -360,4 +364,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;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.push;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
|
@ -18,23 +19,25 @@ import org.eclipse.swt.widgets.Display;
|
|||
* @author anhefti */
|
||||
public final class ServerPushContext {
|
||||
|
||||
private final Composite anchor;
|
||||
private final Predicate<ServerPushContext> runAgain;
|
||||
|
||||
public ServerPushContext(final Composite anchor) {
|
||||
this(anchor, context -> false);
|
||||
}
|
||||
public final Composite anchor;
|
||||
public final Predicate<ServerPushContext> runAgain;
|
||||
public final Function<Exception, Boolean> errorHandler;
|
||||
boolean internalStop = false;
|
||||
|
||||
public ServerPushContext(
|
||||
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.runAgain = runAgain;
|
||||
}
|
||||
|
||||
public boolean runAgain() {
|
||||
return this.runAgain.test(this);
|
||||
return !this.internalStop && this.runAgain.test(this);
|
||||
}
|
||||
|
||||
public boolean isDisposed() {
|
||||
|
|
|
@ -54,43 +54,43 @@ public class ServerPushService {
|
|||
}
|
||||
}
|
||||
|
||||
if (business != null) {
|
||||
try {
|
||||
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()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!context.isDisposed()) {
|
||||
|
||||
log.trace("Call update on Server Push Session on: {}", Thread.currentThread().getName());
|
||||
|
||||
context.getDisplay().asyncExec(() -> {
|
||||
context.getDisplay().asyncExec(() -> {
|
||||
if (business != null) {
|
||||
try {
|
||||
update.accept(context);
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Call business on Server Push Session on: {}",
|
||||
Thread.currentThread().getName());
|
||||
}
|
||||
|
||||
business.accept(context);
|
||||
updateGUI(context, update);
|
||||
|
||||
} 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());
|
||||
log.error("Unexpected error while do business for server push service", e);
|
||||
context.internalStop = context.errorHandler.apply(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
updateGUI(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 {
|
||||
pushSession.stop();
|
||||
} catch (final Exception e) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -101,4 +101,28 @@ public class ServerPushService {
|
|||
bgThread.setDaemon(true);
|
||||
bgThread.start();
|
||||
}
|
||||
|
||||
private void updateGUI(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -303,10 +303,7 @@ public final class ClientConnectionTable {
|
|||
this.restCallBuilder
|
||||
.withHeader(API.EXAM_MONITORING_STATE_FILTER, this.statusFilterParam)
|
||||
.call()
|
||||
.get(error -> {
|
||||
log.error("Error poll connection data: ", error);
|
||||
return Collections.emptyList();
|
||||
})
|
||||
.getOrThrow()
|
||||
.forEach(data -> {
|
||||
final UpdatableTableItem tableItem = this.tableMapping.computeIfAbsent(
|
||||
data.getConnectionId(),
|
||||
|
|
|
@ -113,7 +113,13 @@ public final class ImageUploadSelection extends Composite {
|
|||
ImageUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl());
|
||||
|
||||
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,
|
||||
ImageUploadSelection::update);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue