monitoring improvements

This commit is contained in:
anhefti 2019-12-19 16:44:42 +01:00
parent 25ab3106aa
commit 0e528a3c86
27 changed files with 382 additions and 165 deletions

View file

@ -22,13 +22,19 @@ import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
public final class ClientConnection implements GrantEntity {
public enum ConnectionStatus {
UNDEFINED,
CONNECTION_REQUESTED,
AUTHENTICATED,
ESTABLISHED,
CLOSED,
ABORTED,
DISABLED
UNDEFINED(false),
CONNECTION_REQUESTED(false),
AUTHENTICATED(true),
ACTIVE(true),
CLOSED(false),
DISABLED(false);
public final boolean establishedStatus;
private ConnectionStatus(final boolean establishedStatus) {
this.establishedStatus = establishedStatus;
}
}
public static final ClientConnection EMPTY_CLIENT_CONNECTION = new ClientConnection(

View file

@ -16,6 +16,8 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public class ClientConnectionData {
@ -24,6 +26,8 @@ public class ClientConnectionData {
public final ClientConnection clientConnection;
@JsonProperty("indicatorValues")
public final List<? extends IndicatorValue> indicatorValues;
@JsonIgnore
public final boolean missingPing;
@JsonCreator
protected ClientConnectionData(
@ -32,6 +36,12 @@ public class ClientConnectionData {
this.clientConnection = clientConnection;
this.indicatorValues = Utils.immutableListOf(indicatorValues);
this.missingPing = clientConnection.status == ConnectionStatus.ACTIVE &&
this.indicatorValues.stream()
.filter(ind -> ind.getType() == IndicatorType.LAST_PING)
.findFirst()
.map(ind -> (long) ind.getValue())
.orElse(0L) > 5000;
}
protected ClientConnectionData(
@ -40,6 +50,7 @@ public class ClientConnectionData {
this.clientConnection = clientConnection;
this.indicatorValues = Utils.immutableListOf(indicatorValues);
this.missingPing = false;
}
@JsonIgnore

View file

@ -211,6 +211,10 @@ public class MonitoringClientConnection implements TemplateComposer {
.clearAttributes()
.clearEntityKeys())
.newAction(ActionDefinition.MONITOR_EXAM_FROM_DETAILS)
.withEntityKey(parentEntityKey)
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER))
.newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_QUIT)
.withConfirm(() -> CONFIRM_QUIT)
.withExec(action -> {
@ -221,10 +225,6 @@ public class MonitoringClientConnection implements TemplateComposer {
return action;
})
.noEventPropagation()
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER))
.newAction(ActionDefinition.MONITOR_EXAM_FROM_DETAILS)
.withEntityKey(parentEntityKey)
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER));
}

View file

@ -12,6 +12,7 @@ import java.util.Collection;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import org.eclipse.swt.SWT;
@ -184,39 +185,70 @@ public class MonitoringRunningExam implements TemplateComposer {
.noEventPropagation()
.publishIf(privilege);
clientTable.hideStatus(ConnectionStatus.DISABLED);
if (privilege.getAsBoolean()) {
final PageAction showClosedConnections =
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
.withExec(action -> {
clientTable.showStatus(ConnectionStatus.CLOSED);
return action;
})
.noEventPropagation()
.create();
final PageAction hideClosedConnections =
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
.withExec(action -> {
clientTable.hideStatus(ConnectionStatus.CLOSED);
return action;
})
.noEventPropagation()
.withSwitchAction(showClosedConnections)
.create();
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
.noEventPropagation()
.withSwitchAction(
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
.withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
.noEventPropagation()
.create())
.publish();
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
.noEventPropagation()
.withSwitchAction(
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
.withExec(showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
.noEventPropagation()
.create())
.publish();
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
.noEventPropagation()
.withSwitchAction(
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
.withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
.noEventPropagation()
.create())
.publish();
this.pageService.publishAction(clientTable.isStatusHidden(ConnectionStatus.CLOSED)
? showClosedConnections
: hideClosedConnections);
}
}
private static final Function<PageAction, PageAction> showStateViewAction(
final ClientConnectionTable clientTable,
final ConnectionStatus status) {
return action -> {
clientTable.showStatus(status);
return action;
};
}
private static final Function<PageAction, PageAction> hideStateViewAction(
final ClientConnectionTable clientTable,
final ConnectionStatus status) {
return action -> {
clientTable.hideStatus(status);
return action;
};
}
private PageAction quitSebClients(
final PageAction action,
final ClientConnectionTable clientTable,
final boolean all) {
final Predicate<ClientConnection> activePredicate = ClientConnection
.getStatusPredicate(ConnectionStatus.ESTABLISHED);
.getStatusPredicate(ConnectionStatus.ACTIVE);
final Set<String> connectionTokens = clientTable.getConnectionTokens(
activePredicate,

View file

@ -200,7 +200,7 @@ public class SebClientLogs implements TemplateComposer {
TIME_TEXT_KEY,
this::getEventTime)
.withFilter(new TableFilterAttribute(
CriteriaType.DATE_RANGE,
CriteriaType.DATE_TIME_RANGE,
ClientEvent.FILTER_ATTR_SERVER_TIME_FROM_TO,
Utils.toDateTimeUTC(Utils.getMillisecondsNow())
.minusYears(1)

View file

@ -28,7 +28,7 @@ public enum ActionCategory {
LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
LOGS_SEB_CLIENT_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1),
VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 100),
;
FILTER(new LocTextKey("sebserver.overall.action.category.filter"), 50);
public final LocTextKey title;
public final int slotPosition;

View file

@ -582,16 +582,36 @@ public enum ActionDefinition {
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.CLIENT_EVENT_LIST),
MONITOR_EXAM_HIDE_REQUESTED_CONNECTION(
new LocTextKey("sebserver.monitoring.exam.connection.action.hide.requested"),
ImageIcon.TOGGLE_OFF,
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.FILTER),
MONITOR_EXAM_SHOW_REQUESTED_CONNECTION(
new LocTextKey("sebserver.monitoring.exam.connection.action.show.requested"),
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.FILTER),
MONITOR_EXAM_HIDE_CLOSED_CONNECTION(
new LocTextKey("sebserver.monitoring.exam.connection.action.hide.closed"),
ImageIcon.TOGGLE_OFF,
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.FORM),
ActionCategory.FILTER),
MONITOR_EXAM_SHOW_CLOSED_CONNECTION(
new LocTextKey("sebserver.monitoring.exam.connection.action.show.closed"),
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.FORM),
ActionCategory.FILTER),
MONITOR_EXAM_HIDE_DISABLED_CONNECTION(
new LocTextKey("sebserver.monitoring.exam.connection.action.hide.disabled"),
ImageIcon.TOGGLE_OFF,
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.FILTER),
MONITOR_EXAM_SHOW_DISABLED_CONNECTION(
new LocTextKey("sebserver.monitoring.exam.connection.action.show.disabled"),
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.MONITORING_RUNNING_EXAM,
ActionCategory.FILTER),
LOGS_USER_ACTIVITY_LIST(
new LocTextKey("sebserver.logs.activity.userlogs"),

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.form;
import java.util.function.Consumer;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
@ -27,6 +28,7 @@ public final class TextFieldBuilder extends FieldBuilder<String> {
boolean isNumber = false;
Consumer<String> numberCheck = null;
boolean isArea = false;
boolean isColorbox = false;
TextFieldBuilder(final String name, final LocTextKey label, final String value) {
super(name, label, value);
@ -53,6 +55,11 @@ public final class TextFieldBuilder extends FieldBuilder<String> {
return this;
}
public TextFieldBuilder asColorbox() {
this.isColorbox = true;
return this;
}
@Override
void build(final FormBuilder builder) {
final boolean readonly = builder.readonly || this.readonly;
@ -75,6 +82,9 @@ public final class TextFieldBuilder extends FieldBuilder<String> {
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
if (this.isArea) {
gridData.minimumHeight = WidgetFactory.TEXT_AREA_INPUT_MIN_HEIGHT;
} else if (this.isColorbox) {
gridData.minimumHeight = WidgetFactory.TEXT_INPUT_MIN_HEIGHT;
textInput.setData(RWT.CUSTOM_VARIANT, "colorbox");
}
textInput.setLayoutData(gridData);
if (StringUtils.isNoneBlank(this.value)) {

View file

@ -44,6 +44,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.Configuration
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
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.ClientEvent;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
@ -73,6 +74,8 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
* combo-box content. */
public class ResourceService {
private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING";
public static final Comparator<Tuple<String>> RESOURCE_COMPARATOR = (t1, t2) -> t1._2.compareTo(t2._2);
public static final EnumSet<EntityType> ENTITY_TYPE_EXCLUDE_MAP = EnumSet.of(
@ -436,6 +439,24 @@ public class ResourceService {
.getText(ResourceService.EXAMCONFIG_STATUS_PREFIX + config.configStatus.name());
}
public String localizedClientConnectionStatusName(final ClientConnectionData connectionData) {
if (connectionData == null) {
final String name = ConnectionStatus.UNDEFINED.name();
return this.i18nSupport.getText(
SEB_CONNECTION_STATUS_KEY_PREFIX + name,
name);
}
if (connectionData.missingPing) {
return this.i18nSupport.getText(
SEB_CONNECTION_STATUS_KEY_PREFIX + MISSING_CLIENT_PING_NAME_KEY,
MISSING_CLIENT_PING_NAME_KEY);
} else {
return localizedClientConnectionStatusName((connectionData.clientConnection != null)
? connectionData.clientConnection.status
: ConnectionStatus.UNDEFINED);
}
}
public String localizedClientConnectionStatusName(final ConnectionStatus status) {
String name;
if (status != null) {

View file

@ -323,17 +323,18 @@ public interface PageService {
}
public PageActionBuilder newAction(final ActionDefinition definition) {
pageContext = originalPageContext.copy();
this.definition = definition;
confirm = null;
successMessage = null;
selectionSupplier = null;
noSelectionMessage = null;
exec = null;
fireActionEvent = true;
ignoreMoveAwayFromEdit = false;
switchAction = null;
return this;
final PageActionBuilder newBuilder = new PageActionBuilder(this.pageService, this.originalPageContext);
newBuilder.pageContext = originalPageContext.copy();
newBuilder.definition = definition;
newBuilder.confirm = null;
newBuilder.successMessage = null;
newBuilder.selectionSupplier = null;
newBuilder.noSelectionMessage = null;
newBuilder.exec = null;
newBuilder.fireActionEvent = true;
newBuilder.ignoreMoveAwayFromEdit = false;
newBuilder.switchAction = null;
return newBuilder;
}
public PageAction create() {

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.session;
import java.util.Collection;
import java.util.EnumMap;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,12 +22,12 @@ 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.Indicator.IndicatorType;
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.IndicatorValue;
import ch.ethz.seb.sebserver.gui.form.Form;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
@ -50,13 +51,15 @@ public class ClientConnectionDetails {
private static final int NUMBER_OF_NONE_INDICATOR_ROWS = 3;
private final PageService pageService;
private final ResourceService resourceService;
private final Exam exam;
private final EnumMap<IndicatorType, IndicatorData> indicatorMapping;
private final RestCall<ClientConnectionData>.RestCallBuilder restCallBuilder;
private final FormHandle<?> formhandle;
private final StatusData statusColor;
private final ColorData colorData;
private ClientConnectionData connectionData = null;
private boolean statusChanged = true;
public ClientConnectionDetails(
final PageService pageService,
@ -68,12 +71,14 @@ public class ClientConnectionDetails {
final Display display = pageContext.getRoot().getDisplay();
this.pageService = pageService;
this.resourceService = pageService.getResourceService();
this.exam = exam;
this.restCallBuilder = restCallBuilder;
this.statusColor = new StatusData(display);
this.colorData = new ColorData(display);
this.indicatorMapping = IndicatorData.createFormIndicators(
indicators,
display,
this.colorData,
NUMBER_OF_NONE_INDICATOR_ROWS);
final FormBuilder formBuilder = this.pageService.formBuilder(pageContext, 4)
@ -94,7 +99,8 @@ public class ClientConnectionDetails {
.addField(FormBuilder.text(
Domain.CLIENT_CONNECTION.ATTR_STATUS,
CONNECTION_STATUS_TEXT_KEY,
Constants.EMPTY_NOTE))
Constants.EMPTY_NOTE)
.asColorbox())
.addEmptyCell();
this.indicatorMapping
@ -105,6 +111,7 @@ public class ClientConnectionDetails {
indData.indicator.name,
new LocTextKey(indData.indicator.name),
Constants.EMPTY_NOTE)
.asColorbox()
.withDefaultLabel(indData.indicator.name))
.addEmptyCell();
});
@ -113,12 +120,19 @@ public class ClientConnectionDetails {
}
public void updateData(final ServerPushContext context) {
this.connectionData = this.restCallBuilder
final ClientConnectionData connectionData = this.restCallBuilder
.call()
.get(error -> {
log.error("Unexpected error while trying to get current client connection data: ", error);
return null;
});
if (this.connectionData != null && connectionData != null) {
this.statusChanged =
this.connectionData.clientConnection.status != connectionData.clientConnection.status ||
this.connectionData.missingPing != connectionData.missingPing;
}
this.connectionData = connectionData;
}
public void updateGUI(final ServerPushContext context) {
@ -135,13 +149,16 @@ public class ClientConnectionDetails {
Domain.CLIENT_CONNECTION.ATTR_CLIENT_ADDRESS,
this.connectionData.clientConnection.clientAddress);
// update status
form.setFieldValue(
Domain.CLIENT_CONNECTION.ATTR_STATUS,
getStatusName());
form.setFieldColor(
Domain.CLIENT_CONNECTION.ATTR_STATUS,
this.statusColor.getStatusColor(this.connectionData));
if (this.statusChanged) {
// update status
form.setFieldValue(
Domain.CLIENT_CONNECTION.ATTR_STATUS,
this.resourceService.localizedClientConnectionStatusName(this.connectionData));
final Color statusColor = this.colorData.getStatusColor(this.connectionData);
final Color statusTextColor = this.colorData.getStatusTextColor(statusColor);
form.setFieldColor(Domain.CLIENT_CONNECTION.ATTR_STATUS, statusColor);
form.setFieldTextColor(Domain.CLIENT_CONNECTION.ATTR_STATUS, statusTextColor);
}
// update indicators
this.connectionData.getIndicatorValues()
@ -151,7 +168,7 @@ public class ClientConnectionDetails {
final double value = indValue.getValue();
final String displayValue = IndicatorValue.getDisplayValue(indValue);
if (this.connectionData.clientConnection.status != ConnectionStatus.ESTABLISHED) {
if (!this.connectionData.clientConnection.status.establishedStatus) {
form.setFieldValue(
indData.indicator.name,
@ -175,11 +192,4 @@ public class ClientConnectionDetails {
});
}
String getStatusName() {
return this.pageService.getResourceService().localizedClientConnectionStatusName(
(this.connectionData != null && this.connectionData.clientConnection != null)
? this.connectionData.clientConnection.status
: ConnectionStatus.UNDEFINED);
}
}

View file

@ -51,7 +51,7 @@ 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.IndicatorValue;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
@ -77,13 +77,13 @@ public final class ClientConnectionTable {
private static final int NUMBER_OF_NONE_INDICATOR_COLUMNS = 3;
private final PageService pageService;
private final WidgetFactory widgetFactory;
private final ResourceService resourceService;
private final Exam exam;
private final RestCall<Collection<ClientConnectionData>>.RestCallBuilder restCallBuilder;
private final EnumMap<IndicatorType, IndicatorData> indicatorMapping;
private final Table table;
private final StatusData statusData;
private final ColorData colorData;
private final EnumSet<ConnectionStatus> statusFilter;
private int tableWidth;
@ -101,13 +101,13 @@ public final class ClientConnectionTable {
final Collection<Indicator> indicators,
final RestCall<Collection<ClientConnectionData>>.RestCallBuilder restCallBuilder) {
this.pageService = pageService;
this.widgetFactory = pageService.getWidgetFactory();
this.resourceService = pageService.getResourceService();
this.exam = exam;
this.restCallBuilder = restCallBuilder;
final Display display = tableRoot.getDisplay();
this.statusData = new StatusData(display);
this.colorData = new ColorData(display);
this.darkFontColor = new Color(display, Constants.BLACK_RGB);
this.lightFontColor = new Color(display, Constants.WHITE_RGB);
@ -115,6 +115,7 @@ public final class ClientConnectionTable {
this.indicatorMapping = IndicatorData.createFormIndicators(
indicators,
display,
this.colorData,
NUMBER_OF_NONE_INDICATOR_COLUMNS);
this.statusFilter = EnumSet.noneOf(ConnectionStatus.class);
@ -209,9 +210,8 @@ public final class ClientConnectionTable {
for (int i = 0; i < selectionIndices.length; i++) {
final UpdatableTableItem updatableTableItem =
new ArrayList<>(this.tableMapping.values())
.get(selectionIndices[0]);
.get(selectionIndices[i]);
if (filter.test(updatableTableItem.connectionData.clientConnection)) {
result.add(updatableTableItem.connectionData.clientConnection.connectionToken);
}
}
@ -375,11 +375,10 @@ public final class ClientConnectionTable {
}
void updateConnectionStatusColor(final TableItem tableItem) {
final Color statusColor = ClientConnectionTable.this.statusData.getStatusColor(this.connectionData);
final Color statusColor = ClientConnectionTable.this.colorData.getStatusColor(this.connectionData);
final Color statusTextColor = ClientConnectionTable.this.colorData.getStatusTextColor(statusColor);
tableItem.setBackground(2, statusColor);
tableItem.setForeground(2, Utils.darkColor(statusColor.getRGB())
? ClientConnectionTable.this.darkFontColor
: ClientConnectionTable.this.lightFontColor);
tableItem.setForeground(2, statusTextColor);
}
void updateDuplicateColor(final TableItem tableItem) {
@ -392,7 +391,7 @@ public final class ClientConnectionTable {
final List<Long> list =
ClientConnectionTable.this.sessionIds.get(this.connectionData.clientConnection.userSessionId);
if (list != null && list.size() > 1) {
tableItem.setBackground(0, ClientConnectionTable.this.statusData.color3);
tableItem.setBackground(0, ClientConnectionTable.this.colorData.color3);
tableItem.setForeground(0, ClientConnectionTable.this.lightFontColor);
} else {
tableItem.setBackground(0, null);
@ -409,14 +408,12 @@ public final class ClientConnectionTable {
return;
}
final boolean fillEmpty = this.connectionData.clientConnection.status != ConnectionStatus.ESTABLISHED;
for (int i = 0; i < this.connectionData.indicatorValues.size(); i++) {
final IndicatorValue indicatorValue = this.connectionData.indicatorValues.get(i);
final IndicatorData indicatorData =
ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType());
if (fillEmpty) {
if (!this.connectionData.clientConnection.status.establishedStatus) {
final String value = (indicatorData.indicator.type.showOnlyInActiveState)
? Constants.EMPTY_NOTE
: IndicatorValue.getDisplayValue(indicatorValue);
@ -470,7 +467,7 @@ public final class ClientConnectionTable {
}
int statusWeight() {
return ClientConnectionTable.this.statusData.statusWeight(this.connectionData);
return ClientConnectionTable.this.colorData.statusWeight(this.connectionData);
}
int thresholdsWeight() {
@ -478,10 +475,8 @@ public final class ClientConnectionTable {
}
String getStatusName() {
return ClientConnectionTable.this.pageService.getResourceService().localizedClientConnectionStatusName(
(this.connectionData != null && this.connectionData.clientConnection != null)
? this.connectionData.clientConnection.status
: ConnectionStatus.UNDEFINED);
return ClientConnectionTable.this.resourceService
.localizedClientConnectionStatusName(this.connectionData);
}
String getConnectionAddress() {

View file

@ -12,20 +12,26 @@ import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public class StatusData {
public class ColorData {
final Color darkColor;
final Color lightColor;
final Color defaultColor;
final Color color1;
final Color color2;
final Color color3;
public StatusData(final Display display) {
this.defaultColor = new Color(display, new RGB(255, 255, 255), 255);
public ColorData(final Display display) {
this.defaultColor = new Color(display, new RGB(220, 220, 220), 255);
this.color1 = new Color(display, new RGB(34, 177, 76), 255);
this.color2 = new Color(display, new RGB(255, 194, 14), 255);
this.color3 = new Color(display, new RGB(237, 28, 36), 255);
this.darkColor = new Color(display, Constants.BLACK_RGB);
this.lightColor = new Color(display, Constants.WHITE_RGB);
}
Color getStatusColor(final ClientConnectionData connectionData) {
@ -34,28 +40,30 @@ public class StatusData {
}
switch (connectionData.clientConnection.status) {
case ESTABLISHED:
return this.color1;
case ABORTED:
return this.color3;
default:
case ACTIVE:
return (connectionData.missingPing) ? this.color2 : this.color1;
case DISABLED:
return this.color2;
default:
return this.defaultColor;
}
}
Color getStatusTextColor(final Color statusColor) {
return Utils.darkColor(statusColor.getRGB()) ? this.darkColor : this.lightColor;
}
int statusWeight(final ClientConnectionData connectionData) {
if (connectionData == null) {
return 100;
}
switch (connectionData.clientConnection.status) {
case ABORTED:
return 0;
case CONNECTION_REQUESTED:
case AUTHENTICATED:
return 1;
case ESTABLISHED:
return 2;
case ACTIVE:
return (connectionData.missingPing) ? 0 : 2;
case CLOSED:
return 3;
default:

View file

@ -16,7 +16,6 @@ import java.util.EnumMap;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
@ -35,6 +34,7 @@ final class IndicatorData {
final Indicator indicator,
final int index,
final int tableIndex,
final ColorData colorData,
final Display display) {
this.indicator = indicator;
@ -42,20 +42,21 @@ final class IndicatorData {
this.tableIndex = tableIndex;
this.defaultColor = new Color(display, Utils.toRGB(indicator.defaultColor), 255);
this.defaultTextColor = Utils.darkColor(this.defaultColor.getRGB())
? new Color(display, Constants.BLACK_RGB)
: new Color(display, Constants.WHITE_RGB);
? colorData.darkColor
: colorData.lightColor;
this.thresholdColor = new ThresholdColor[indicator.thresholds.size()];
final ArrayList<Threshold> sortedThresholds = new ArrayList<>(indicator.thresholds);
Collections.sort(sortedThresholds, (t1, t2) -> t1.value.compareTo(t2.value));
for (int i = 0; i < indicator.thresholds.size(); i++) {
this.thresholdColor[i] = new ThresholdColor(sortedThresholds.get(i), display);
this.thresholdColor[i] = new ThresholdColor(sortedThresholds.get(i), display, colorData);
}
}
static final EnumMap<IndicatorType, IndicatorData> createFormIndicators(
final Collection<Indicator> indicators,
final Display display,
final ColorData colorData,
final int tableIndexOffset) {
final EnumMap<IndicatorType, IndicatorData> indicatorMapping = new EnumMap<>(IndicatorType.class);
@ -65,6 +66,7 @@ final class IndicatorData {
indicator,
i,
i + tableIndexOffset,
colorData,
display));
i++;
}
@ -86,12 +88,12 @@ final class IndicatorData {
final Color color;
final Color textColor;
protected ThresholdColor(final Threshold threshold, final Display display) {
protected ThresholdColor(final Threshold threshold, final Display display, final ColorData colorData) {
this.value = threshold.value;
this.color = new Color(display, Utils.toRGB(threshold.color), 255);
this.textColor = Utils.darkColor(this.color.getRGB())
? new Color(display, Constants.BLACK_RGB)
: new Color(display, Constants.WHITE_RGB);
? colorData.darkColor
: colorData.lightColor;
}
}

View file

@ -50,7 +50,8 @@ public class TableFilter<ROW extends Entity> {
TEXT,
SINGLE_SELECTION,
DATE,
DATE_RANGE
DATE_RANGE,
DATE_TIME_RANGE
}
private final Composite composite;
@ -125,6 +126,8 @@ public class TableFilter<ROW extends Entity> {
return new Date(attribute);
case DATE_RANGE:
return new DateRange(attribute);
case DATE_TIME_RANGE:
return new DateRange(attribute, true);
default:
throw new IllegalArgumentException("Unsupported FilterAttributeType: " + attribute.type);
}
@ -476,17 +479,25 @@ public class TableFilter<ROW extends Entity> {
private Composite innerComposite;
private final GridData rw1 = new GridData(SWT.FILL, SWT.FILL, true, true);
private DateTime fromSelector;
private DateTime toSelector;
private DateTime fromDateSelector;
private DateTime toDateSelector;
private DateTime fromTimeSelector;
private DateTime toTimeSelector;
private final boolean withTime;
DateRange(final TableFilterAttribute attribute) {
this(attribute, false);
}
DateRange(final TableFilterAttribute attribute, final boolean withTime) {
super(attribute);
this.withTime = withTime;
}
@Override
FilterComponent build(final Composite parent) {
this.innerComposite = new Composite(parent, SWT.NONE);
final GridLayout gridLayout = new GridLayout(2, false);
final GridLayout gridLayout = new GridLayout((this.withTime) ? 3 : 2, false);
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
gridLayout.horizontalSpacing = 5;
@ -496,13 +507,25 @@ public class TableFilter<ROW extends Entity> {
TableFilter.this.entityTable.widgetFactory
.labelLocalized(this.innerComposite, DATE_FROM_TEXT);
this.fromSelector = new DateTime(this.innerComposite, SWT.DATE | SWT.BORDER);
this.fromSelector.setLayoutData(this.rw1);
this.fromDateSelector =
new DateTime(this.innerComposite, SWT.DATE | SWT.BORDER);
this.fromDateSelector.setLayoutData(this.rw1);
if (this.withTime) {
this.fromTimeSelector =
new DateTime(this.innerComposite, SWT.TIME | SWT.BORDER);
this.fromTimeSelector.setLayoutData(this.rw1);
}
TableFilter.this.entityTable.widgetFactory
.labelLocalized(this.innerComposite, DATE_TO_TEXT);
this.toSelector = new DateTime(this.innerComposite, SWT.DATE | SWT.BORDER);
this.toSelector.setLayoutData(this.rw1);
this.toDateSelector =
new DateTime(this.innerComposite, SWT.DATE | SWT.BORDER);
this.toDateSelector.setLayoutData(this.rw1);
if (this.withTime) {
this.toTimeSelector =
new DateTime(this.innerComposite, SWT.TIME | SWT.BORDER);
this.toTimeSelector.setLayoutData(this.rw1);
}
return this;
}
@ -510,44 +533,66 @@ public class TableFilter<ROW extends Entity> {
@Override
FilterComponent reset() {
final org.joda.time.DateTime now = org.joda.time.DateTime.now(DateTimeZone.UTC);
if (this.fromSelector != null) {
if (this.fromDateSelector != null) {
try {
final org.joda.time.DateTime parse = org.joda.time.DateTime.parse(this.attribute.initValue);
this.fromSelector.setDate(
this.fromDateSelector.setDate(
parse.getYear(),
parse.getMonthOfYear() - 1,
parse.getDayOfMonth());
if (this.fromTimeSelector != null) {
this.fromTimeSelector.setTime(
parse.getHourOfDay(),
parse.getMinuteOfHour(),
parse.getSecondOfMinute());
}
} catch (final RuntimeException e) {
this.fromSelector.setDate(
this.fromDateSelector.setDate(
now.getYear(),
now.getMonthOfYear() - 1,
now.getDayOfMonth());
if (this.fromTimeSelector != null) {
this.fromTimeSelector.setTime(
now.getHourOfDay(),
now.getMinuteOfHour(),
now.getSecondOfMinute());
}
}
}
if (this.toSelector != null) {
this.toSelector.setDate(
if (this.toDateSelector != null) {
this.toDateSelector.setDate(
now.getYear(),
now.getMonthOfYear() - 1,
now.getDayOfMonth());
if (this.toTimeSelector != null) {
this.toTimeSelector.setTime(
now.getHourOfDay(),
now.getMinuteOfHour(),
now.getSecondOfMinute());
}
}
return this;
}
@Override
String getValue() {
if (this.fromSelector != null && this.toSelector != null) {
if (this.fromDateSelector != null && this.toDateSelector != null) {
final org.joda.time.DateTime fromDate = org.joda.time.DateTime.now(DateTimeZone.UTC)
.withYear(this.fromSelector.getYear())
.withMonthOfYear(this.fromSelector.getMonth() + 1)
.withDayOfMonth(this.fromSelector.getDay())
.withTimeAtStartOfDay();
.withYear(this.fromDateSelector.getYear())
.withMonthOfYear(this.fromDateSelector.getMonth() + 1)
.withDayOfMonth(this.fromDateSelector.getDay())
.withHourOfDay((this.fromTimeSelector != null) ? this.fromTimeSelector.getHours() : 0)
.withMinuteOfHour((this.fromTimeSelector != null) ? this.fromTimeSelector.getMinutes() : 0)
.withSecondOfMinute((this.fromTimeSelector != null) ? this.fromTimeSelector.getSeconds() : 0);
final org.joda.time.DateTime toDate = org.joda.time.DateTime.now(DateTimeZone.UTC)
.withYear(this.toSelector.getYear())
.withMonthOfYear(this.toSelector.getMonth() + 1)
.withDayOfMonth(this.toSelector.getDay())
.withTime(23, 59, 59, 0);
.withYear(this.toDateSelector.getYear())
.withMonthOfYear(this.toDateSelector.getMonth() + 1)
.withDayOfMonth(this.toDateSelector.getDay())
.withHourOfDay((this.toTimeSelector != null) ? this.toTimeSelector.getHours() : 0)
.withMinuteOfHour((this.toTimeSelector != null) ? this.toTimeSelector.getMinutes() : 0)
.withSecondOfMinute((this.toTimeSelector != null) ? this.toTimeSelector.getSeconds() : 0);
return fromDate.toString(Constants.STANDARD_DATE_TIME_FORMATTER) +
Constants.EMBEDDED_LIST_SEPARATOR +
@ -559,14 +604,33 @@ public class TableFilter<ROW extends Entity> {
@Override
void setValue(final String value) {
if (this.fromSelector != null && this.toSelector != null) {
if (this.fromDateSelector != null && this.toDateSelector != null) {
try {
final String[] split = StringUtils.split(value, Constants.EMBEDDED_LIST_SEPARATOR);
final org.joda.time.DateTime fromDate = Utils.toDateTime(split[0]);
final org.joda.time.DateTime toDate = Utils.toDateTime(split[1]);
this.fromSelector.setDate(fromDate.getYear(), fromDate.getMonthOfYear() - 1,
this.fromDateSelector.setDate(
fromDate.getYear(),
fromDate.getMonthOfYear() - 1,
fromDate.getDayOfMonth());
this.toSelector.setDate(toDate.getYear(), toDate.getMonthOfYear() - 1, toDate.getDayOfMonth());
if (this.fromTimeSelector != null) {
this.fromTimeSelector.setTime(
fromDate.getHourOfDay(),
fromDate.getMinuteOfHour(),
fromDate.getSecondOfMinute());
}
this.toDateSelector.setDate(
toDate.getYear(),
toDate.getMonthOfYear() - 1,
toDate.getDayOfMonth());
if (this.toTimeSelector != null) {
this.toTimeSelector.setTime(
toDate.getHourOfDay(),
toDate.getMinuteOfHour(),
toDate.getSecondOfMinute());
}
} catch (final Exception e) {
log.error("Failed to set date range filter attribute: ", e);
}

View file

@ -50,6 +50,7 @@ public interface ClientConnectionDAO extends EntityDAO<ClientConnection, ClientC
Result<ClientConnection> createNew(ClientConnection data);
@Override
// TODO check if this is needed
@CacheEvict(cacheNames = CONNECTION_TOKENS_CACHE, allEntries = true)
Result<ClientConnection> save(ClientConnection data);

View file

@ -95,7 +95,7 @@ public class AsyncBatchEventSaveStrategy implements EventHandlingStrategy {
runWorkers();
try {
Thread.sleep(Constants.SECOND_IN_MILLIS);
Thread.sleep(Constants.SECOND_IN_MILLIS / 2);
} catch (final Exception e) {
log.error("Failed to wait");
}
@ -110,8 +110,7 @@ public class AsyncBatchEventSaveStrategy implements EventHandlingStrategy {
@Override
public void accept(final ClientEventRecord record) {
if (!this.workersRunning) {
log.error("Received ClientEvent on none enabled AsyncBatchEventSaveStrategy. ClientEvent is ignored");
if (record == null || !this.workersRunning) {
return;
}

View file

@ -24,6 +24,8 @@ public class ClientConnectionDataInternal extends ClientConnectionData {
final Collection<AbstractPingIndicator> pingMappings;
final EnumMap<EventType, Collection<ClientIndicator>> indicatorMapping;
PingIntervalClientIndicator pingIndicator = null;
protected ClientConnectionDataInternal(
final ClientConnection clientConnection,
final List<ClientIndicator> clientIndicators) {
@ -34,7 +36,14 @@ public class ClientConnectionDataInternal extends ClientConnectionData {
this.pingMappings = new ArrayList<>();
for (final ClientIndicator clientIndicator : clientIndicators) {
if (clientIndicator instanceof AbstractPingIndicator) {
this.pingMappings.add((AbstractPingIndicator) clientIndicator);
if (clientIndicator instanceof PingIntervalClientIndicator) {
this.pingIndicator = (PingIntervalClientIndicator) clientIndicator;
if (!this.pingIndicator.hidden) {
this.pingMappings.add((AbstractPingIndicator) clientIndicator);
}
} else {
this.pingMappings.add((AbstractPingIndicator) clientIndicator);
}
}
for (final EventType eventType : clientIndicator.observedEvents()) {
this.indicatorMapping

View file

@ -22,6 +22,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.IndicatorDAO;
@ -62,12 +63,18 @@ public class ClientIndicatorFactory {
.allForExam(clientConnection.examId)
.getOrThrow();
boolean pingIndicatorAvailable = false;
for (final Indicator indicatorDef : examIndicators) {
try {
final ClientIndicator indicator = this.applicationContext
.getBean(indicatorDef.type.name(), ClientIndicator.class);
if (!pingIndicatorAvailable) {
pingIndicatorAvailable = indicatorDef.type == IndicatorType.LAST_PING;
}
indicator.init(
indicatorDef,
clientConnection.id,
@ -79,6 +86,16 @@ public class ClientIndicatorFactory {
e);
}
}
// If there is no ping interval indicator set from the exam, we add a hidden one
// to at least create missing ping events and track missing state
if (!pingIndicatorAvailable) {
final PingIntervalClientIndicator pingIndicator = this.applicationContext
.getBean(PingIntervalClientIndicator.class);
pingIndicator.hidden = true;
result.add(pingIndicator);
}
} catch (final RuntimeException e) {
log.error("Failed to create ClientIndicator for ClientConnection: {}", clientConnection);
throw e;

View file

@ -333,8 +333,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
}
private static boolean isActiveConnection(final ClientConnectionData connection) {
if (connection.clientConnection.status == ConnectionStatus.ESTABLISHED
|| connection.clientConnection.status == ConnectionStatus.AUTHENTICATED) {
if (connection.clientConnection.status.establishedStatus) {
return true;
}

View file

@ -112,7 +112,7 @@ class ExamSessionControlTask implements DisposableBean {
controlExamEnd(updateId);
}
@Scheduled(fixedRateString = "${sebserver.webservice.api.seb.lostping.update:15000}")
@Scheduled(fixedRateString = "${sebserver.webservice.api.seb.lostping.update:5000}")
public void pingEventUpdateTask() {
if (!this.lostPingUpdateActive) {

View file

@ -39,6 +39,8 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
private long pingErrorThreshold;
private boolean isOnError = false;
boolean hidden = false;
public PingIntervalClientIndicator(final ClientEventExtentionMapper clientEventExtentionMapper) {
super(clientEventExtentionMapper);
this.cachingEnabled = true;
@ -70,7 +72,7 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
@Override
public double getValue() {
final long now = DateTime.now(DateTimeZone.UTC).getMillis();
return now - super.currentValue;
return now - super.getValue();
}
@Override

View file

@ -73,6 +73,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
this.webserviceInfo = sebInstructionService.getWebserviceInfo();
}
@Override
public ExamSessionService getExamSessionService() {
return this.examSessionService;
}
@ -220,7 +221,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
.getOrThrow();
final ClientConnectionDataInternal activeClientConnection =
cacheEvictAndLoad(connectionToken);
realoadConnectionCache(connectionToken);
if (activeClientConnection == null) {
log.warn("Failed to load ClientConnectionDataInternal into cache on update");
@ -286,7 +287,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
clientConnection.id,
null,
(examId != null) ? examId : clientConnection.examId,
ConnectionStatus.ESTABLISHED,
ConnectionStatus.ACTIVE,
null,
userSessionId,
null,
@ -298,7 +299,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
clientConnection.connectionToken == null ||
establishedClientConnection.examId == null ||
clientConnection.clientAddress == null ||
establishedClientConnection.status != ConnectionStatus.ESTABLISHED) {
establishedClientConnection.status != ConnectionStatus.ACTIVE) {
log.error("ClientConnection integrity violation, clientConnection: {}, establishedClientConnection: {}",
clientConnection,
@ -313,7 +314,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
checkExamIntegrity(updatedClientConnection.examId);
final ClientConnectionDataInternal activeClientConnection =
cacheEvictAndLoad(connectionToken);
realoadConnectionCache(connectionToken);
if (activeClientConnection == null) {
log.warn("Failed to load ClientConnectionDataInternal into cache on update");
@ -368,7 +369,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
updatedClientConnection = clientConnection;
}
evictCaches(connectionToken);
realoadConnectionCache(connectionToken);
return updatedClientConnection;
});
}
@ -406,7 +407,7 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
updatedClientConnection = clientConnection;
}
evictCaches(connectionToken);
realoadConnectionCache(connectionToken);
return updatedClientConnection;
});
}
@ -427,9 +428,9 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
.stream())
.map(token -> cache.get(token, ClientConnectionDataInternal.class))
.filter(Objects::nonNull)
.filter(connection -> connection.clientConnection.status == ConnectionStatus.ESTABLISHED)
.flatMap(connection -> connection.pingMappings.stream())
.map(ping -> ping.updateLogEvent())
.filter(connection -> connection.pingIndicator != null &&
connection.clientConnection.status.establishedStatus)
.map(connection -> connection.pingIndicator.updateLogEvent())
.filter(Objects::nonNull)
.forEach(this.eventHandlingStrategy::accept);
@ -497,7 +498,6 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
}
}
// TODO maybe we need a stronger connectionToken but for now a simple UUID is used
private String createToken() {
return UUID.randomUUID().toString();
}
@ -606,19 +606,12 @@ public class SebClientConnectionServiceImpl implements SebClientConnectionServic
.getOrThrow();
}
private void evictCaches(final String connectionToken) {
private ClientConnectionDataInternal realoadConnectionCache(final String connectionToken) {
// evict cached ClientConnection
this.examSessionCacheService.evictClientConnection(connectionToken);
// evict also cached ping record
this.examSessionCacheService.evictPingRecord(connectionToken);
// and load updated ClientConnection into cache
this.examSessionCacheService.getActiveClientConnection(connectionToken);
}
private ClientConnectionDataInternal cacheEvictAndLoad(final String connectionToken) {
// evict cached ClientConnection
this.examSessionCacheService.evictClientConnection(connectionToken);
// and load updated ClientConnection into cache
return this.examSessionCacheService.getActiveClientConnection(connectionToken);
}

View file

@ -18,6 +18,7 @@ sebserver.overall.action.cancel=Cancel
sebserver.overall.action.close=Close
sebserver.overall.action.goAwayFromEditPageConfirm=Are you sure you want to leave this page? Unsaved data will be lost.
sebserver.overall.action.category.varia=Varia
sebserver.overall.action.category.filter=Connection Status Filter
sebserver.overall.status.active=Active
sebserver.overall.status.inactive=Inactive
@ -1065,14 +1066,20 @@ sebserver.monitoring.exam.connection.emptySelection=Please select a connection f
sebserver.monitoring.exam.connection.title=SEB Client Connection
sebserver.monitoring.exam.connection.list.actions=Selected Connection
sebserver.monitoring.exam.connection.action.view=View Details
sebserver.monitoring.exam.connection.action.instruction.quit=Send Quit
sebserver.monitoring.exam.connection.action.instruction.quit.all=Send Quit
sebserver.monitoring.exam.connection.action.instruction.quit=Send SEB Quit
sebserver.monitoring.exam.connection.action.instruction.quit.all=Send SEB Quit
sebserver.monitoring.exam.connection.action.instruction.quit.all.confirm=Are you sure to quit this SEB client connection?
sebserver.monitoring.exam.connection.action.instruction.quit.selected.confirm=Are you sure to quit all selected, active SEB client connections?
sebserver.monitoring.exam.connection.action.instruction.quit.all.confirm=Are you sure to quit all active SEB client connections?
sebserver.monitoring.exam.connection.action.disable=Mark As Disabled
sebserver.monitoring.exam.connection.action.hide.closed=Hide Closed Connections
sebserver.monitoring.exam.connection.action.show.closed=Show Closed Connections
sebserver.monitoring.exam.connection.action.hide.requested=Hide Requested
sebserver.monitoring.exam.connection.action.show.requested=Show Requested
sebserver.monitoring.exam.connection.action.hide.closed=Hide Closed
sebserver.monitoring.exam.connection.action.show.closed=Show Closed
sebserver.monitoring.exam.connection.action.hide.disabled=Hide Disabled
sebserver.monitoring.exam.connection.action.show.disabled=Show Disabled
sebserver.monitoring.exam.connection.action.hide.undefined=Hide Undefined
sebserver.monitoring.exam.connection.action.show.undefined=Show Undefined
sebserver.monitoring.exam.connection.eventlist.title=Events
sebserver.monitoring.exam.connection.eventlist.empty=No event found
@ -1092,7 +1099,7 @@ sebserver.monitoring.exam.connection.event.type.LAST_PING=Last Ping
sebserver.monitoring.exam.connection.status.UNDEFINED=Undefined
sebserver.monitoring.exam.connection.status.CONNECTION_REQUESTED=Connection Requested
sebserver.monitoring.exam.connection.status.AUTHENTICATED=Authenticated
sebserver.monitoring.exam.connection.status.ESTABLISHED=Active
sebserver.monitoring.exam.connection.status.ACTIVE=Active
sebserver.monitoring.exam.connection.status.CLOSED=Closed
sebserver.monitoring.exam.connection.status.ABORTED=Aborted
sebserver.monitoring.exam.connection.status.DISABLED=Disabled

View file

@ -298,6 +298,16 @@ Text[MULTI]:read-only {
padding: 0px 0px 0px 0px;
}
Text:disabled.colorbox,
Text:read-only.colorbox,
Text[MULTI]:disabled.colorbox,
Text[MULTI]:read-only.colorbox {
box-shadow: none;
border: none;
border-radius: 0;
padding: 0px 10px 0px 10px;
}
/* Combo default theme */
Combo, Combo[BORDER] {

View file

@ -104,8 +104,8 @@ public class HTTPClientBot {
this.numberOfConnections = Integer.parseInt(properties.getProperty("numberOfConnections", "4"));
this.pingInterval = Long.parseLong(properties.getProperty("pingInterval", "200"));
this.establishDelay = Long.parseLong(properties.getProperty("establishDelay", "0"));
this.pingPause = Long.parseLong(properties.getProperty("pingPause", "0"));
this.pingPauseDelay = Long.parseLong(properties.getProperty("pingPauseDelay", "0"));
this.pingPause = Long.parseLong(properties.getProperty("pingPause", "20000"));
this.pingPauseDelay = Long.parseLong(properties.getProperty("pingPauseDelay", "5000"));
this.errorInterval = Long.parseLong(properties.getProperty("errorInterval", String.valueOf(TEN_SECONDS)));
this.warnInterval = Long.parseLong(properties.getProperty("errorInterval", String.valueOf(TEN_SECONDS / 2)));
// this.runtime = Long.parseLong(properties.getProperty("runtime", String.valueOf(ONE_MINUTE)));

View file

@ -295,7 +295,7 @@ public class SebConnectionTest extends ExamAPIIntegrationTester {
final ClientConnectionRecord clientConnectionRecord = records.get(0);
assertEquals("1", String.valueOf(clientConnectionRecord.getInstitutionId()));
assertEquals("2", String.valueOf(clientConnectionRecord.getExamId()));
assertEquals("ESTABLISHED", String.valueOf(clientConnectionRecord.getStatus()));
assertEquals("ACTIVE", String.valueOf(clientConnectionRecord.getStatus()));
assertNotNull(clientConnectionRecord.getConnectionToken());
assertNotNull(clientConnectionRecord.getClientAddress());
assertEquals("userSessionId", clientConnectionRecord.getExamUserSessionId());