Merge branch 'development' into development_VDI
This commit is contained in:
commit
5440f4bdcd
9 changed files with 101 additions and 38 deletions
|
@ -215,7 +215,9 @@ public class SEBClientEventDetailsPopup {
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
QuizData.QUIZ_ATTR_DESCRIPTION,
|
QuizData.QUIZ_ATTR_DESCRIPTION,
|
||||||
FORM_DESC_TEXT_KEY,
|
FORM_DESC_TEXT_KEY,
|
||||||
exam.description))
|
exam.description)
|
||||||
|
.asArea()
|
||||||
|
.asHTML(true))
|
||||||
.addField(FormBuilder.text(
|
.addField(FormBuilder.text(
|
||||||
Domain.EXAM.ATTR_TYPE,
|
Domain.EXAM.ATTR_TYPE,
|
||||||
FORM_EXAM_TYPE_TEXT_KEY,
|
FORM_EXAM_TYPE_TEXT_KEY,
|
||||||
|
|
|
@ -8,12 +8,31 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
||||||
|
|
||||||
|
/** Data access object for webservice info data.
|
||||||
|
* This info is used to verify parallel running webservices and nominate one as master.
|
||||||
|
* It shows also the history of SEB webservice registrations that has not been correctly shot down and still remain in
|
||||||
|
* the persistent data table. */
|
||||||
public interface WebserviceInfoDAO {
|
public interface WebserviceInfoDAO {
|
||||||
|
|
||||||
|
/** Register a SEB webservice within the persistent storage
|
||||||
|
*
|
||||||
|
* @param uuid A unique identifier that was generated by the webservice on startup
|
||||||
|
* @param address the IP address of the webservice
|
||||||
|
* @return true if registration was successful */
|
||||||
boolean register(String uuid, String address);
|
boolean register(String uuid, String address);
|
||||||
|
|
||||||
|
/** This can periodically be called by a specific running webservice to verify whether the webservice is (still) the
|
||||||
|
* master or a slave
|
||||||
|
*
|
||||||
|
* @param uuid The unique identifier of the webservice generated on startup
|
||||||
|
* @return true if the calling webservice is (still) the master service */
|
||||||
boolean isMaster(String uuid);
|
boolean isMaster(String uuid);
|
||||||
|
|
||||||
|
/** When a webservice has a controlled shout down, it unregister itself within this method.
|
||||||
|
* This removes the data entry of the webservice from persistent storage.
|
||||||
|
*
|
||||||
|
* @param uuid he unique identifier of the webservice generated on startup
|
||||||
|
* @return true when the unregistering was successful */
|
||||||
boolean unregister(String uuid);
|
boolean unregister(String uuid);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,25 +61,25 @@ final class MockupLmsAPITemplate implements LmsAPITemplate {
|
||||||
final LmsType lmsType = lmsSetup.getLmsType();
|
final LmsType lmsType = lmsSetup.getLmsType();
|
||||||
this.mockups = new ArrayList<>();
|
this.mockups = new ArrayList<>();
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz1", institutionId, lmsSetupId, lmsType, "Demo Quiz 1 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz1", institutionId, lmsSetupId, lmsType, "Demo Quiz 1 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2020-01-01T09:00:00Z", null, "http://lms.mockup.com/api/"));
|
"2020-01-01T09:00:00Z", null, "http://lms.mockup.com/api/"));
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz2", institutionId, lmsSetupId, lmsType, "Demo Quiz 2 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz2", institutionId, lmsSetupId, lmsType, "Demo Quiz 2 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2020-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
"2020-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz3", institutionId, lmsSetupId, lmsType, "Demo Quiz 3 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz3", institutionId, lmsSetupId, lmsType, "Demo Quiz 3 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2018-07-30T09:00:00Z", "2018-08-01T00:00:00Z", "http://lms.mockup.com/api/"));
|
"2018-07-30T09:00:00Z", "2018-08-01T00:00:00Z", "http://lms.mockup.com/api/"));
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz4", institutionId, lmsSetupId, lmsType, "Demo Quiz 4 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz4", institutionId, lmsSetupId, lmsType, "Demo Quiz 4 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2018-01-01T00:00:00Z", "2019-01-01T00:00:00Z", "http://lms.mockup.com/api/"));
|
"2018-01-01T00:00:00Z", "2019-01-01T00:00:00Z", "http://lms.mockup.com/api/"));
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz5", institutionId, lmsSetupId, lmsType, "Demo Quiz 5 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz5", institutionId, lmsSetupId, lmsType, "Demo Quiz 5 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2018-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
"2018-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz6", institutionId, lmsSetupId, lmsType, "Demo Quiz 6 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz6", institutionId, lmsSetupId, lmsType, "Demo Quiz 6 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2019-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
"2019-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
"quiz7", institutionId, lmsSetupId, lmsType, "Demo Quiz 7 (MOCKUP)", "Demo Quiz Mockup",
|
"quiz7", institutionId, lmsSetupId, lmsType, "Demo Quiz 7 (MOCKUP)", "<p>Demo Quiz Mockup</p>",
|
||||||
"2018-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
"2018-01-01T09:00:00Z", "2022-01-01T09:00:00Z", "http://lms.mockup.com/api/"));
|
||||||
|
|
||||||
this.mockups.add(new QuizData(
|
this.mockups.add(new QuizData(
|
||||||
|
|
|
@ -14,6 +14,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
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.session.ClientEvent.EventType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.IndicatorValue;
|
import ch.ethz.seb.sebserver.gbl.model.session.IndicatorValue;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||||
|
|
||||||
/** A client indicator is a indicator value holder for a specific Indicator
|
/** A client indicator is a indicator value holder for a specific Indicator
|
||||||
* on a running client connection.
|
* on a running client connection.
|
||||||
|
@ -58,4 +59,6 @@ public interface ClientIndicator extends IndicatorValue {
|
||||||
* @param event The ClientEvent instance */
|
* @param event The ClientEvent instance */
|
||||||
void notifyValueChange(ClientEvent event);
|
void notifyValueChange(ClientEvent event);
|
||||||
|
|
||||||
|
void notifyValueChange(ClientEventRecord clientEventRecord);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ class ExamSessionControlTask implements DisposableBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRateString = "${sebserver.webservice.api.seb.lostping.update:5000}")
|
@Scheduled(fixedRateString = "${sebserver.webservice.api.seb.lostping.update:5000}")
|
||||||
public void pingEventUpdateTask() {
|
public void examSessionUpdateTask() {
|
||||||
|
|
||||||
if (!this.webserviceInfoDAO.isMaster(this.webserviceInfo.getWebserviceUUID())) {
|
if (!this.webserviceInfoDAO.isMaster(this.webserviceInfo.getWebserviceUUID())) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -31,6 +31,7 @@ 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.model.session.ClientConnectionData;
|
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;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
|
||||||
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.WebserviceInfo;
|
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||||
|
@ -524,34 +525,39 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
final String connectionToken,
|
final String connectionToken,
|
||||||
final ClientEvent event) {
|
final ClientEvent event) {
|
||||||
|
|
||||||
final ClientConnectionDataInternal activeClientConnection =
|
try {
|
||||||
this.examSessionCacheService.getClientConnection(connectionToken);
|
final ClientConnectionDataInternal activeClientConnection =
|
||||||
|
this.examSessionCacheService.getClientConnection(connectionToken);
|
||||||
|
|
||||||
if (activeClientConnection != null) {
|
if (activeClientConnection != null) {
|
||||||
|
|
||||||
// store event
|
// store event
|
||||||
this.eventHandlingStrategy.accept(ClientEvent.toRecord(
|
this.eventHandlingStrategy.accept(ClientEvent.toRecord(
|
||||||
event,
|
event,
|
||||||
activeClientConnection.getConnectionId()));
|
activeClientConnection.getConnectionId()));
|
||||||
|
|
||||||
switch (event.eventType) {
|
switch (event.eventType) {
|
||||||
case NOTIFICATION: {
|
case NOTIFICATION: {
|
||||||
this.sebClientNotificationService.notifyNewNotification(activeClientConnection.getConnectionId());
|
this.sebClientNotificationService
|
||||||
break;
|
.notifyNewNotification(activeClientConnection.getConnectionId());
|
||||||
}
|
break;
|
||||||
case NOTIFICATION_CONFIRMED: {
|
}
|
||||||
this.sebClientNotificationService.confirmPendingNotification(event, connectionToken);
|
case NOTIFICATION_CONFIRMED: {
|
||||||
break;
|
this.sebClientNotificationService.confirmPendingNotification(event, connectionToken);
|
||||||
}
|
break;
|
||||||
default: {
|
}
|
||||||
// update indicators
|
default: {
|
||||||
activeClientConnection.getIndicatorMapping(event.eventType)
|
// update indicators
|
||||||
.forEach(indicator -> indicator.notifyValueChange(event));
|
activeClientConnection.getIndicatorMapping(event.eventType)
|
||||||
|
.forEach(indicator -> indicator.notifyValueChange(event));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.warn("No active ClientConnection found for connectionToken: {}", connectionToken);
|
||||||
}
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
} else {
|
log.error("Failed to process SEB client event: ", e);
|
||||||
log.warn("No active ClientConnection found for connectionToken: {}", connectionToken);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,6 +740,12 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
this.clientConnectionDAO.save(connection.clientConnection);
|
this.clientConnectionDAO.save(connection.clientConnection);
|
||||||
this.examSessionCacheService.evictClientConnection(
|
this.examSessionCacheService.evictClientConnection(
|
||||||
connection.clientConnection.connectionToken);
|
connection.clientConnection.connectionToken);
|
||||||
|
} else {
|
||||||
|
// update indicators
|
||||||
|
if (clientEventRecord.getType() != null && EventType.ERROR_LOG.id == clientEventRecord.getType()) {
|
||||||
|
connection.getIndicatorMapping(EventType.ERROR_LOG)
|
||||||
|
.forEach(indicator -> indicator.notifyValueChange(clientEventRecord));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordMapper;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||||
|
|
||||||
public abstract class AbstractLogLevelCountIndicator extends AbstractLogIndicator {
|
public abstract class AbstractLogLevelCountIndicator extends AbstractLogIndicator {
|
||||||
|
|
||||||
|
@ -37,9 +38,18 @@ public abstract class AbstractLogLevelCountIndicator extends AbstractLogIndicato
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyValueChange(final ClientEvent event) {
|
public void notifyValueChange(final ClientEvent event) {
|
||||||
|
valueChanged(event.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyValueChange(final ClientEventRecord clientEventRecord) {
|
||||||
|
valueChanged(clientEventRecord.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void valueChanged(final String eventText) {
|
||||||
if (this.tags == null || this.tags.length == 0) {
|
if (this.tags == null || this.tags.length == 0) {
|
||||||
this.currentValue = getValue() + 1d;
|
this.currentValue = getValue() + 1d;
|
||||||
} else if (hasTag(event.text)) {
|
} else if (hasTag(eventText)) {
|
||||||
this.currentValue = getValue() + 1d;
|
this.currentValue = getValue() + 1d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,22 @@ public abstract class AbstractLogNumberIndicator extends AbstractLogIndicator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyValueChange(final ClientEvent event) {
|
public void notifyValueChange(final ClientEvent event) {
|
||||||
|
valueChanged(event.text, event.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyValueChange(final ClientEventRecord clientEventRecord) {
|
||||||
|
final BigDecimal numericValue = clientEventRecord.getNumericValue();
|
||||||
|
if (numericValue != null) {
|
||||||
|
valueChanged(clientEventRecord.getText(), numericValue.doubleValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void valueChanged(final String text, final double value) {
|
||||||
if (this.tags == null || this.tags.length == 0) {
|
if (this.tags == null || this.tags.length == 0) {
|
||||||
this.currentValue = event.getValue();
|
this.currentValue = value;
|
||||||
} else if (hasTag(event.text)) {
|
} else if (hasTag(text)) {
|
||||||
this.currentValue = event.getValue();
|
this.currentValue = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,11 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyValueChange(final ClientEventRecord clientEventRecord) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientEventRecord updateLogEvent(final long now) {
|
public ClientEventRecord updateLogEvent(final long now) {
|
||||||
final long value = now - (long) super.currentValue;
|
final long value = now - (long) super.currentValue;
|
||||||
|
|
Loading…
Reference in a new issue