SEBSERV-250 improved webservice init
This commit is contained in:
parent
bab4b95609
commit
dfb8afb740
18 changed files with 235 additions and 144 deletions
|
@ -10,11 +10,16 @@ package ch.ethz.seb.sebserver;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.webservice.WebserviceInit;
|
||||||
|
|
||||||
public class SEBServerInitEvent extends ApplicationEvent {
|
public class SEBServerInitEvent extends ApplicationEvent {
|
||||||
|
|
||||||
private static final long serialVersionUID = -3608628289559324471L;
|
private static final long serialVersionUID = -3608628289559324471L;
|
||||||
|
|
||||||
public SEBServerInitEvent(final Object source) {
|
public final WebserviceInit webserviceInit;
|
||||||
super(source);
|
|
||||||
|
public SEBServerInitEvent(final WebserviceInit webserviceInit) {
|
||||||
|
super(webserviceInit);
|
||||||
|
this.webserviceInit = webserviceInit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,16 +43,10 @@ public class GuiInit implements ApplicationListener<ApplicationReadyEvent> {
|
||||||
|
|
||||||
this.sebServerInit.init();
|
this.sebServerInit.init();
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> **** GUI Service starting up... ****");
|
SEBServerInit.INIT_LOGGER.info("----> *** GUI Service starting up... ***");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> GUI Service successfully successfully started up!");
|
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
|
||||||
|
|
||||||
// final String webServiceProtocol = this.environment.getProperty("sebserver.gui.webservice.protocol", "http");
|
|
||||||
// final String webServiceAddress = this.environment.getRequiredProperty("sebserver.gui.webservice.address");
|
|
||||||
// final String webServicePort = this.environment.getProperty("sebserver.gui.webservice.port", "80");
|
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info(
|
SEBServerInit.INIT_LOGGER.info(
|
||||||
"----> Webservice connection: {}",
|
"----> Webservice connection: {}",
|
||||||
|
@ -82,6 +76,11 @@ public class GuiInit implements ApplicationListener<ApplicationReadyEvent> {
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Webservice admin API basic access: --" + webServiceAPIBasicAccess + "--");
|
SEBServerInit.INIT_LOGGER.info("----> Webservice admin API basic access: --" + webServiceAPIBasicAccess + "--");
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *** GUI Service successfully successfully started up! ***");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,8 @@ public class WebserviceInfo {
|
||||||
private final boolean isDistributed;
|
private final boolean isDistributed;
|
||||||
private final String webserviceUUID;
|
private final String webserviceUUID;
|
||||||
|
|
||||||
|
private final long distributedPingUpdateInterval;
|
||||||
|
|
||||||
private Map<String, String> lmsExternalAddressAlias;
|
private Map<String, String> lmsExternalAddressAlias;
|
||||||
|
|
||||||
public WebserviceInfo(final Environment environment) {
|
public WebserviceInfo(final Environment environment) {
|
||||||
|
@ -74,6 +76,11 @@ public class WebserviceInfo {
|
||||||
this.discoveryEndpoint = environment.getRequiredProperty(WEB_SERVICE_EXAM_API_DISCOVERY_ENDPOINT_KEY);
|
this.discoveryEndpoint = environment.getRequiredProperty(WEB_SERVICE_EXAM_API_DISCOVERY_ENDPOINT_KEY);
|
||||||
this.contextPath = environment.getProperty(WEB_SERVICE_CONTEXT_PATH, "");
|
this.contextPath = environment.getProperty(WEB_SERVICE_CONTEXT_PATH, "");
|
||||||
|
|
||||||
|
this.distributedPingUpdateInterval = environment.getProperty(
|
||||||
|
"sebserver.webservice.distributed.pingUpdate",
|
||||||
|
Long.class,
|
||||||
|
3000L);
|
||||||
|
|
||||||
if (StringUtils.isEmpty(this.webserverName)) {
|
if (StringUtils.isEmpty(this.webserverName)) {
|
||||||
log.warn("NOTE: External server name, property : 'sebserver.webservice.http.external.servername' "
|
log.warn("NOTE: External server name, property : 'sebserver.webservice.http.external.servername' "
|
||||||
+ "is not set from configuration. The external server name is set to the server address!");
|
+ "is not set from configuration. The external server name is set to the server address!");
|
||||||
|
@ -160,6 +167,10 @@ public class WebserviceInfo {
|
||||||
return this.serverURLPrefix + this.discoveryEndpoint;
|
return this.serverURLPrefix + this.discoveryEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDistributedPingUpdateInterval() {
|
||||||
|
return this.distributedPingUpdateInterval;
|
||||||
|
}
|
||||||
|
|
||||||
public String getLocalHostName() {
|
public String getLocalHostName() {
|
||||||
try {
|
try {
|
||||||
return InetAddress.getLocalHost().getHostName();
|
return InetAddress.getLocalHost().getHostName();
|
||||||
|
|
|
@ -15,6 +15,7 @@ import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
@ -31,6 +32,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.WebserviceInfoDAO;
|
||||||
@Import(DataSourceAutoConfiguration.class)
|
@Import(DataSourceAutoConfiguration.class)
|
||||||
public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent> {
|
public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent> {
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
private final SEBServerInit sebServerInit;
|
private final SEBServerInit sebServerInit;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
private final WebserviceInfo webserviceInfo;
|
private final WebserviceInfo webserviceInfo;
|
||||||
|
@ -41,20 +43,26 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
|
|
||||||
protected WebserviceInit(
|
protected WebserviceInit(
|
||||||
final SEBServerInit sebServerInit,
|
final SEBServerInit sebServerInit,
|
||||||
final Environment environment,
|
|
||||||
final WebserviceInfo webserviceInfo,
|
final WebserviceInfo webserviceInfo,
|
||||||
final AdminUserInitializer adminUserInitializer,
|
final AdminUserInitializer adminUserInitializer,
|
||||||
final ApplicationEventPublisher applicationEventPublisher,
|
final ApplicationEventPublisher applicationEventPublisher,
|
||||||
final WebserviceInfoDAO webserviceInfoDAO,
|
final WebserviceInfoDAO webserviceInfoDAO,
|
||||||
final DBIntegrityChecker dbIntegrityChecker) {
|
final DBIntegrityChecker dbIntegrityChecker,
|
||||||
|
final ApplicationContext applicationContext) {
|
||||||
|
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
this.sebServerInit = sebServerInit;
|
this.sebServerInit = sebServerInit;
|
||||||
this.environment = environment;
|
this.environment = applicationContext.getEnvironment();
|
||||||
this.webserviceInfo = webserviceInfo;
|
this.webserviceInfo = webserviceInfo;
|
||||||
this.adminUserInitializer = adminUserInitializer;
|
this.adminUserInitializer = adminUserInitializer;
|
||||||
this.applicationEventPublisher = applicationEventPublisher;
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
this.webserviceInfoDAO = webserviceInfoDAO;
|
this.webserviceInfoDAO = webserviceInfoDAO;
|
||||||
this.dbIntegrityChecker = dbIntegrityChecker;
|
this.dbIntegrityChecker = dbIntegrityChecker;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationContext getApplicationContext() {
|
||||||
|
return this.applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,17 +70,21 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
|
|
||||||
this.sebServerInit.init();
|
this.sebServerInit.init();
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("----> **** Webservice starting up... ****");
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *** Webservice starting up... ***");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Register Webservice: {}", this.webserviceInfo.getWebserviceUUID());
|
SEBServerInit.INIT_LOGGER.info("----> Register Webservice: {}", this.webserviceInfo.getWebserviceUUID());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.webserviceInfoDAO.register(
|
final boolean register = this.webserviceInfoDAO.register(
|
||||||
this.webserviceInfo.getWebserviceUUID(),
|
this.webserviceInfo.getWebserviceUUID(),
|
||||||
InetAddress.getLocalHost().getHostAddress());
|
InetAddress.getLocalHost().getHostAddress());
|
||||||
|
if (register) {
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> Successfully register Webservice instance");
|
||||||
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
SEBServerInit.INIT_LOGGER.error("Failed to register webservice: ", e);
|
SEBServerInit.INIT_LOGGER.error("----> Failed to register webservice: ", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
|
@ -81,23 +93,31 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
|
|
||||||
this.applicationEventPublisher.publishEvent(new SEBServerInitEvent(this));
|
this.applicationEventPublisher.publishEvent(new SEBServerInitEvent(this));
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
// Run the data base integrity checks and fixes if configured
|
||||||
SEBServerInit.INIT_LOGGER.info("----> **** Webservice successfully started up! **** ");
|
this.dbIntegrityChecker.checkIntegrity();
|
||||||
|
|
||||||
|
// Create an initial admin account if requested and not already in the data-base
|
||||||
|
this.adminUserInitializer.initAdminAccount();
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *** Webservice Info: ***");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> *** Info:");
|
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("----> JDBC connection pool max size: {}",
|
SEBServerInit.INIT_LOGGER.info("----> JDBC connection pool max size: {}",
|
||||||
this.environment.getProperty("spring.datasource.hikari.maximumPoolSize"));
|
this.environment.getProperty("spring.datasource.hikari.maximumPoolSize"));
|
||||||
|
|
||||||
if (this.webserviceInfo.isDistributed()) {
|
if (this.webserviceInfo.isDistributed()) {
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Distributed Setup: {}", this.webserviceInfo.getWebserviceUUID());
|
SEBServerInit.INIT_LOGGER.info("----> Distributed Setup: {}", this.webserviceInfo.getWebserviceUUID());
|
||||||
SEBServerInit.INIT_LOGGER.info("------> Ping update time: {}",
|
SEBServerInit.INIT_LOGGER.info("----> Ping update time: {}",
|
||||||
this.environment.getProperty("sebserver.webservice.distributed.pingUpdate"));
|
this.environment.getProperty("sebserver.webservice.distributed.pingUpdate"));
|
||||||
SEBServerInit.INIT_LOGGER.info("------> Connection update time: {}",
|
SEBServerInit.INIT_LOGGER.info("----> Connection update time: {}",
|
||||||
this.environment.getProperty("sebserver.webservice.distributed.connectionUpdate", "2000"));
|
this.environment.getProperty("sebserver.webservice.distributed.connectionUpdate", "2000"));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Server address: {}", this.environment.getProperty("server.address"));
|
SEBServerInit.INIT_LOGGER.info("----> Server address: {}", this.environment.getProperty("server.address"));
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Server port: {}", this.environment.getProperty("server.port"));
|
SEBServerInit.INIT_LOGGER.info("----> Server port: {}", this.environment.getProperty("server.port"));
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
|
@ -122,19 +142,18 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Property Override Test: {}", this.webserviceInfo.getTestProperty());
|
SEBServerInit.INIT_LOGGER.info("----> Property Override Test: {}", this.webserviceInfo.getTestProperty());
|
||||||
|
|
||||||
// Run the data base integrity checks and fixes if configured
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
this.dbIntegrityChecker.checkIntegrity();
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> *** Webservice successfully started up! ***");
|
||||||
// Create an initial admin account if requested and not already in the data-base
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
this.adminUserInitializer.initAdminAccount();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void gracefulShutdown() {
|
public void gracefulShutdown() {
|
||||||
SEBServerInit.INIT_LOGGER.info("**** Gracefully Shutdown of SEB Server instance {} ****",
|
SEBServerInit.INIT_LOGGER.info("*********************************************************");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("**** Gracefully Shutdown of SEB Server instance {}",
|
||||||
this.webserviceInfo.getHostAddress());
|
this.webserviceInfo.getHostAddress());
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Unregister Webservice: {}", this.webserviceInfo.getWebserviceUUID());
|
SEBServerInit.INIT_LOGGER.info("----> Unregister Webservice: {}", this.webserviceInfo.getWebserviceUUID());
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,12 @@ public interface ClientPingMapper {
|
||||||
int update(UpdateStatementProvider updateStatement);
|
int update(UpdateStatementProvider updateStatement);
|
||||||
|
|
||||||
@SelectProvider(type = SqlProviderAdapter.class, method = "select")
|
@SelectProvider(type = SqlProviderAdapter.class, method = "select")
|
||||||
@ResultType(ClientEventLastPingRecord.class)
|
@ResultType(ClientLastPingRecord.class)
|
||||||
@ConstructorArgs({
|
@ConstructorArgs({
|
||||||
@Arg(column = "id", javaType = Long.class, jdbcType = JdbcType.BIGINT),
|
@Arg(column = "id", javaType = Long.class, jdbcType = JdbcType.BIGINT),
|
||||||
@Arg(column = "value", javaType = Long.class, jdbcType = JdbcType.BIGINT)
|
@Arg(column = "value", javaType = Long.class, jdbcType = JdbcType.BIGINT)
|
||||||
})
|
})
|
||||||
Collection<ClientEventLastPingRecord> selectMany(SelectStatementProvider select);
|
Collection<ClientLastPingRecord> selectMany(SelectStatementProvider select);
|
||||||
|
|
||||||
default Long selectPingTimeByPrimaryKey(final Long id_) {
|
default Long selectPingTimeByPrimaryKey(final Long id_) {
|
||||||
return SelectDSL.selectWithMapper(
|
return SelectDSL.selectWithMapper(
|
||||||
|
@ -78,7 +78,7 @@ public interface ClientPingMapper {
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
default QueryExpressionDSL<MyBatis3SelectModelAdapter<Collection<ClientEventLastPingRecord>>> selectByExample() {
|
default QueryExpressionDSL<MyBatis3SelectModelAdapter<Collection<ClientLastPingRecord>>> selectByExample() {
|
||||||
|
|
||||||
return SelectDSL.selectWithMapper(
|
return SelectDSL.selectWithMapper(
|
||||||
this::selectMany,
|
this::selectMany,
|
||||||
|
@ -95,12 +95,12 @@ public interface ClientPingMapper {
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ClientEventLastPingRecord {
|
final class ClientLastPingRecord {
|
||||||
|
|
||||||
public final Long id;
|
public final Long id;
|
||||||
public final Long lastPingTime;
|
public final Long lastPingTime;
|
||||||
|
|
||||||
public ClientEventLastPingRecord(
|
public ClientLastPingRecord(
|
||||||
final Long id,
|
final Long id,
|
||||||
final Long value) {
|
final Long value) {
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionR
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionRecordMapper;
|
||||||
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.mapper.ClientIndicatorRecordDynamicSqlSupport;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientIndicatorRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientInstructionRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientInstructionRecordDynamicSqlSupport;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientInstructionRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientInstructionRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
|
||||||
|
@ -63,15 +65,18 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
||||||
private final ClientEventRecordMapper clientEventRecordMapper;
|
private final ClientEventRecordMapper clientEventRecordMapper;
|
||||||
private final ClientInstructionRecordMapper clientInstructionRecordMapper;
|
private final ClientInstructionRecordMapper clientInstructionRecordMapper;
|
||||||
|
private final ClientIndicatorRecordMapper clientIndicatorRecordMapper;
|
||||||
|
|
||||||
protected ClientConnectionDAOImpl(
|
protected ClientConnectionDAOImpl(
|
||||||
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
||||||
final ClientEventRecordMapper clientEventRecordMapper,
|
final ClientEventRecordMapper clientEventRecordMapper,
|
||||||
final ClientInstructionRecordMapper clientInstructionRecordMapper) {
|
final ClientInstructionRecordMapper clientInstructionRecordMapper,
|
||||||
|
final ClientIndicatorRecordMapper clientIndicatorRecordMapper) {
|
||||||
|
|
||||||
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
||||||
this.clientEventRecordMapper = clientEventRecordMapper;
|
this.clientEventRecordMapper = clientEventRecordMapper;
|
||||||
this.clientInstructionRecordMapper = clientInstructionRecordMapper;
|
this.clientInstructionRecordMapper = clientInstructionRecordMapper;
|
||||||
|
this.clientIndicatorRecordMapper = clientIndicatorRecordMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -474,7 +479,15 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// first delete all related client events
|
// delete all related client indicators
|
||||||
|
this.clientIndicatorRecordMapper.deleteByExample()
|
||||||
|
.where(
|
||||||
|
ClientIndicatorRecordDynamicSqlSupport.clientConnectionId,
|
||||||
|
SqlBuilder.isIn(ids))
|
||||||
|
.build()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
// delete all related client events
|
||||||
this.clientEventRecordMapper.deleteByExample()
|
this.clientEventRecordMapper.deleteByExample()
|
||||||
.where(
|
.where(
|
||||||
ClientEventRecordDynamicSqlSupport.clientConnectionId,
|
ClientEventRecordDynamicSqlSupport.clientConnectionId,
|
||||||
|
|
|
@ -237,18 +237,19 @@ public class ExamAdminServiceImpl implements ExamAdminService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Boolean> isProctoringEnabled(final Long examId) {
|
public Result<Boolean> isProctoringEnabled(final Long examId) {
|
||||||
final Result<Boolean> result = this.additionalAttributesDAO.getAdditionalAttribute(
|
return this.additionalAttributesDAO.getAdditionalAttribute(
|
||||||
EntityType.EXAM,
|
EntityType.EXAM,
|
||||||
examId,
|
examId,
|
||||||
ProctoringServiceSettings.ATTR_ENABLE_PROCTORING)
|
ProctoringServiceSettings.ATTR_ENABLE_PROCTORING)
|
||||||
.map(rec -> BooleanUtils.toBoolean(rec.getValue()))
|
.map(rec -> BooleanUtils.toBoolean(rec.getValue()))
|
||||||
.onError(error -> log.warn("Failed to verify proctoring enabled for exam: {}, {}",
|
.onErrorDo(error -> {
|
||||||
examId,
|
if (log.isDebugEnabled()) {
|
||||||
error.getMessage()));
|
log.warn("Failed to verify proctoring enabled for exam: {}, {}",
|
||||||
if (result.hasError()) {
|
examId,
|
||||||
return Result.of(false);
|
error.getMessage());
|
||||||
}
|
}
|
||||||
return result;
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,6 +15,7 @@ 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;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.ClientIndicatorType;
|
||||||
|
|
||||||
/** 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.
|
||||||
|
@ -31,6 +32,11 @@ public interface ClientIndicator extends IndicatorValue {
|
||||||
* @param cachingEnabled defines whether indicator value caching is enabled or not. */
|
* @param cachingEnabled defines whether indicator value caching is enabled or not. */
|
||||||
void init(Indicator indicatorDefinition, Long connectionId, boolean active, boolean cachingEnabled);
|
void init(Indicator indicatorDefinition, Long connectionId, boolean active, boolean cachingEnabled);
|
||||||
|
|
||||||
|
/** Get the client indicator type
|
||||||
|
*
|
||||||
|
* @return the client indicator type */
|
||||||
|
ClientIndicatorType indicatorType();
|
||||||
|
|
||||||
/** Get the exam identifier of the client connection of this ClientIndicator
|
/** Get the exam identifier of the client connection of this ClientIndicator
|
||||||
*
|
*
|
||||||
* @return the exam identifier of the client connection of this ClientIndicator */
|
* @return the exam identifier of the client connection of this ClientIndicator */
|
||||||
|
|
|
@ -44,7 +44,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.DistributedPingCache;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.DistributedPingService;
|
||||||
import ch.ethz.seb.sebserver.webservice.weblayer.api.APIConstraintViolationException;
|
import ch.ethz.seb.sebserver.webservice.weblayer.api.APIConstraintViolationException;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -70,7 +70,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
private final SEBClientInstructionService sebInstructionService;
|
private final SEBClientInstructionService sebInstructionService;
|
||||||
private final SEBClientNotificationService sebClientNotificationService;
|
private final SEBClientNotificationService sebClientNotificationService;
|
||||||
private final ExamAdminService examAdminService;
|
private final ExamAdminService examAdminService;
|
||||||
private final DistributedPingCache distributedPingCache;
|
private final DistributedPingService distributedPingCache;
|
||||||
private final boolean isDistributedSetup;
|
private final boolean isDistributedSetup;
|
||||||
|
|
||||||
protected SEBClientConnectionServiceImpl(
|
protected SEBClientConnectionServiceImpl(
|
||||||
|
@ -80,7 +80,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
final SEBClientInstructionService sebInstructionService,
|
final SEBClientInstructionService sebInstructionService,
|
||||||
final SEBClientNotificationService sebClientNotificationService,
|
final SEBClientNotificationService sebClientNotificationService,
|
||||||
final ExamAdminService examAdminService,
|
final ExamAdminService examAdminService,
|
||||||
final DistributedPingCache distributedPingCache) {
|
final DistributedPingService distributedPingCache) {
|
||||||
|
|
||||||
this.examSessionService = examSessionService;
|
this.examSessionService = examSessionService;
|
||||||
this.examSessionCacheService = examSessionService.getExamSessionCacheService();
|
this.examSessionCacheService = examSessionService.getExamSessionCacheService();
|
||||||
|
|
|
@ -11,18 +11,14 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
||||||
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.util.Utils;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.ClientPingMapper;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.DistributedPingService.PingUpdate;
|
||||||
|
|
||||||
public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
|
|
||||||
|
@ -30,17 +26,11 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
|
|
||||||
private final Set<EventType> EMPTY_SET = Collections.unmodifiableSet(EnumSet.noneOf(EventType.class));
|
private final Set<EventType> EMPTY_SET = Collections.unmodifiableSet(EnumSet.noneOf(EventType.class));
|
||||||
|
|
||||||
private final Executor executor;
|
protected final DistributedPingService distributedPingCache;
|
||||||
protected final DistributedPingCache distributedPingCache;
|
|
||||||
|
|
||||||
protected PingUpdate pingUpdate = null;
|
protected PingUpdate pingUpdate = null;
|
||||||
|
|
||||||
protected AbstractPingIndicator(
|
protected AbstractPingIndicator(final DistributedPingService distributedPingCache) {
|
||||||
final DistributedPingCache distributedPingCache,
|
|
||||||
@Qualifier(AsyncServiceSpringConfig.EXAM_API_PING_SERVICE_EXECUTOR_BEAN_NAME) final Executor executor) {
|
|
||||||
|
|
||||||
super();
|
super();
|
||||||
this.executor = executor;
|
|
||||||
this.distributedPingCache = distributedPingCache;
|
this.distributedPingCache = distributedPingCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +45,9 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
|
|
||||||
if (!this.cachingEnabled && this.active) {
|
if (!this.cachingEnabled && this.active) {
|
||||||
try {
|
try {
|
||||||
createPingUpdate();
|
this.pingUpdate = this.distributedPingCache.createPingUpdate(connectionId);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
createPingUpdate();
|
this.pingUpdate = this.distributedPingCache.createPingUpdate(connectionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,15 +64,7 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update last ping time on persistent storage asynchronously within a defines thread pool with no
|
this.distributedPingCache.updatePingAsync(this.pingUpdate);
|
||||||
// waiting queue to skip further ping updates if all update threads are busy
|
|
||||||
try {
|
|
||||||
this.executor.execute(this.pingUpdate);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.warn("Failed to schedule ping task: {}" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,21 +75,15 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
createPingUpdate();
|
this.pingUpdate = this.distributedPingCache.createPingUpdate(this.connectionId);
|
||||||
if (this.pingUpdate == null) {
|
if (this.pingUpdate == null) {
|
||||||
createPingUpdate();
|
this.pingUpdate = this.distributedPingCache.createPingUpdate(this.connectionId);
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Failed to recover ping record for connection: {}", this.connectionId, e);
|
log.error("Failed to recover ping record for connection: {}", this.connectionId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPingUpdate() {
|
|
||||||
this.pingUpdate = new PingUpdate(
|
|
||||||
this.distributedPingCache.getClientPingMapper(),
|
|
||||||
this.distributedPingCache.initPingForConnection(this.connectionId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<EventType> observedEvents() {
|
public Set<EventType> observedEvents() {
|
||||||
return this.EMPTY_SET;
|
return this.EMPTY_SET;
|
||||||
|
@ -115,26 +91,4 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
|
||||||
|
|
||||||
public abstract ClientEventRecord updateLogEvent(final long now);
|
public abstract ClientEventRecord updateLogEvent(final long now);
|
||||||
|
|
||||||
static final class PingUpdate implements Runnable {
|
|
||||||
|
|
||||||
private final ClientPingMapper clientPingMapper;
|
|
||||||
final Long pingRecord;
|
|
||||||
|
|
||||||
public PingUpdate(final ClientPingMapper clientPingMapper, final Long pingRecord) {
|
|
||||||
this.clientPingMapper = clientPingMapper;
|
|
||||||
this.pingRecord = pingRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
this.clientPingMapper
|
|
||||||
.updatePingTime(this.pingRecord, Utils.getMillisecondsNow());
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("Failed to update ping: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,4 +45,9 @@ public class BatteryStatusIndicator extends AbstractLogNumberIndicator {
|
||||||
return IndicatorType.BATTERY_STATUS;
|
return IndicatorType.BATTERY_STATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientIndicatorType indicatorType() {
|
||||||
|
return ClientIndicatorType.BATTERY_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -20,50 +21,78 @@ import org.joda.time.DateTimeUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.scheduling.TaskScheduler;
|
import org.springframework.scheduling.TaskScheduler;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.SEBServerInit;
|
||||||
|
import ch.ethz.seb.sebserver.SEBServerInitEvent;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.ClientPingMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.ClientPingMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.ClientPingMapper.ClientEventLastPingRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.ClientPingMapper.ClientLastPingRecord;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientIndicatorRecordDynamicSqlSupport;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientIndicatorRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientIndicatorRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientIndicatorRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientIndicatorRecord;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
public class DistributedPingCache implements DisposableBean {
|
public class DistributedPingService implements DisposableBean {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DistributedPingCache.class);
|
private static final Logger log = LoggerFactory.getLogger(DistributedPingService.class);
|
||||||
|
|
||||||
|
private final Executor pingUpdateExecutor;
|
||||||
private final ClientIndicatorRecordMapper clientIndicatorRecordMapper;
|
private final ClientIndicatorRecordMapper clientIndicatorRecordMapper;
|
||||||
private final ClientPingMapper clientPingMapper;
|
private final ClientPingMapper clientPingMapper;
|
||||||
private final long pingUpdateTolerance;
|
private long pingUpdateTolerance;
|
||||||
|
|
||||||
private ScheduledFuture<?> taskRef;
|
private ScheduledFuture<?> taskRef;
|
||||||
private final Map<Long, Long> pingCache = new ConcurrentHashMap<>();
|
private final Map<Long, Long> pingCache = new ConcurrentHashMap<>();
|
||||||
private long lastUpdate = 0L;
|
private long lastUpdate = 0L;
|
||||||
|
|
||||||
public DistributedPingCache(
|
public DistributedPingService(
|
||||||
|
@Qualifier(AsyncServiceSpringConfig.EXAM_API_PING_SERVICE_EXECUTOR_BEAN_NAME) final Executor pingUpdateExecutor,
|
||||||
final ClientIndicatorRecordMapper clientIndicatorRecordMapper,
|
final ClientIndicatorRecordMapper clientIndicatorRecordMapper,
|
||||||
final ClientPingMapper clientPingMapper,
|
final ClientPingMapper clientPingMapper) {
|
||||||
final WebserviceInfo webserviceInfo,
|
|
||||||
final TaskScheduler taskScheduler,
|
|
||||||
@Value("${sebserver.webservice.distributed.pingUpdate:3000}") final long pingUpdate) {
|
|
||||||
|
|
||||||
|
this.pingUpdateExecutor = pingUpdateExecutor;
|
||||||
this.clientIndicatorRecordMapper = clientIndicatorRecordMapper;
|
this.clientIndicatorRecordMapper = clientIndicatorRecordMapper;
|
||||||
this.clientPingMapper = clientPingMapper;
|
this.clientPingMapper = clientPingMapper;
|
||||||
this.pingUpdateTolerance = pingUpdate * 2 / 3;
|
}
|
||||||
|
|
||||||
|
@EventListener(SEBServerInitEvent.class)
|
||||||
|
public void init(final SEBServerInitEvent initEvent) {
|
||||||
|
final ApplicationContext applicationContext = initEvent.webserviceInit.getApplicationContext();
|
||||||
|
final WebserviceInfo webserviceInfo = applicationContext.getBean(WebserviceInfo.class);
|
||||||
if (webserviceInfo.isDistributed()) {
|
if (webserviceInfo.isDistributed()) {
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("------>");
|
||||||
|
SEBServerInit.INIT_LOGGER.info("------> Activate distributed ping service:");
|
||||||
|
|
||||||
|
final TaskScheduler taskScheduler = applicationContext.getBean(TaskScheduler.class);
|
||||||
|
final long distributedPingUpdateInterval = webserviceInfo.getDistributedPingUpdateInterval();
|
||||||
|
this.pingUpdateTolerance = distributedPingUpdateInterval * 2 / 3;
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("------> with distributedPingUpdateInterval: {}",
|
||||||
|
distributedPingUpdateInterval);
|
||||||
|
SEBServerInit.INIT_LOGGER.info("------> with taskScheduler: {}", taskScheduler);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.taskRef = taskScheduler.scheduleAtFixedRate(this::updatePings, pingUpdate);
|
this.taskRef = taskScheduler.scheduleAtFixedRate(
|
||||||
|
this::persistentPingUpdate,
|
||||||
|
distributedPingUpdateInterval);
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("------> distributed ping service successfully initialized!");
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
SEBServerInit.INIT_LOGGER.error("------> Failed to initialize distributed ping service:", e);
|
||||||
log.error("Failed to initialize distributed ping cache update task");
|
log.error("Failed to initialize distributed ping cache update task");
|
||||||
this.taskRef = null;
|
this.taskRef = null;
|
||||||
}
|
}
|
||||||
|
@ -141,10 +170,10 @@ public class DistributedPingCache implements DisposableBean {
|
||||||
log.debug("*** Delete ping record for SEB connection: {}", connectionId);
|
log.debug("*** Delete ping record for SEB connection: {}", connectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Collection<ClientEventLastPingRecord> records = this.clientPingMapper
|
final Collection<ClientLastPingRecord> records = this.clientPingMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(ClientEventRecordDynamicSqlSupport.clientConnectionId, isEqualTo(connectionId))
|
.where(ClientIndicatorRecordDynamicSqlSupport.clientConnectionId, isEqualTo(connectionId))
|
||||||
.and(ClientEventRecordDynamicSqlSupport.type, isEqualTo(ClientIndicatorType.LAST_PING.id))
|
.and(ClientIndicatorRecordDynamicSqlSupport.type, isEqualTo(ClientIndicatorType.LAST_PING.id))
|
||||||
.build()
|
.build()
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
@ -194,8 +223,7 @@ public class DistributedPingCache implements DisposableBean {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePings() {
|
public void persistentPingUpdate() {
|
||||||
|
|
||||||
if (this.pingCache.isEmpty()) {
|
if (this.pingCache.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +243,7 @@ public class DistributedPingCache implements DisposableBean {
|
||||||
final Map<Long, Long> mapping = this.clientPingMapper
|
final Map<Long, Long> mapping = this.clientPingMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(
|
.where(
|
||||||
ClientEventRecordDynamicSqlSupport.type,
|
ClientIndicatorRecordDynamicSqlSupport.type,
|
||||||
isEqualTo(ClientIndicatorType.LAST_PING.id))
|
isEqualTo(ClientIndicatorType.LAST_PING.id))
|
||||||
.build()
|
.build()
|
||||||
.execute()
|
.execute()
|
||||||
|
@ -235,6 +263,45 @@ public class DistributedPingCache implements DisposableBean {
|
||||||
this.lastUpdate = millisecondsNow;
|
this.lastUpdate = millisecondsNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update last ping time on persistent storage asynchronously within a defines thread pool with no
|
||||||
|
// waiting queue to skip further ping updates if all update threads are busy
|
||||||
|
void updatePingAsync(final PingUpdate pingUpdate) {
|
||||||
|
try {
|
||||||
|
this.pingUpdateExecutor.execute(pingUpdate);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.warn("Failed to schedule ping task: {}" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PingUpdate createPingUpdate(final Long connectionId) {
|
||||||
|
return new PingUpdate(
|
||||||
|
this.getClientPingMapper(),
|
||||||
|
this.initPingForConnection(connectionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class PingUpdate implements Runnable {
|
||||||
|
|
||||||
|
private final ClientPingMapper clientPingMapper;
|
||||||
|
final Long pingRecord;
|
||||||
|
|
||||||
|
public PingUpdate(final ClientPingMapper clientPingMapper, final Long pingRecord) {
|
||||||
|
this.clientPingMapper = clientPingMapper;
|
||||||
|
this.pingRecord = pingRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
this.clientPingMapper
|
||||||
|
.updatePingTime(this.pingRecord, Utils.getMillisecondsNow());
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Failed to update ping: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() throws Exception {
|
public void destroy() throws Exception {
|
||||||
if (this.taskRef != null) {
|
if (this.taskRef != null) {
|
|
@ -31,4 +31,9 @@ public final class ErrorLogCountClientIndicator extends AbstractLogLevelCountInd
|
||||||
return IndicatorType.ERROR_COUNT;
|
return IndicatorType.ERROR_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientIndicatorType indicatorType() {
|
||||||
|
return ClientIndicatorType.ERROR_LOG_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,4 +31,9 @@ public class InfoLogCountClientIndicator extends AbstractLogLevelCountIndicator
|
||||||
return IndicatorType.INFO_COUNT;
|
return IndicatorType.INFO_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientIndicatorType indicatorType() {
|
||||||
|
return ClientIndicatorType.INFO_LOG_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import org.joda.time.DateTimeUtils;
|
import org.joda.time.DateTimeUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
|
@ -24,7 +22,6 @@ import org.springframework.stereotype.Component;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
|
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.IndicatorType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
|
@ -47,10 +44,8 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
|
||||||
private boolean missingPing = false;
|
private boolean missingPing = false;
|
||||||
private boolean hidden = false;
|
private boolean hidden = false;
|
||||||
|
|
||||||
public PingIntervalClientIndicator(
|
public PingIntervalClientIndicator(final DistributedPingService distributedPingCache) {
|
||||||
final DistributedPingCache distributedPingCache,
|
super(distributedPingCache);
|
||||||
@Qualifier(AsyncServiceSpringConfig.EXAM_API_PING_SERVICE_EXECUTOR_BEAN_NAME) final Executor executor) {
|
|
||||||
super(distributedPingCache, executor);
|
|
||||||
this.cachingEnabled = true;
|
this.cachingEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +84,11 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientIndicatorType indicatorType() {
|
||||||
|
return ClientIndicatorType.LAST_PING;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public final boolean isMissingPing() {
|
public final boolean isMissingPing() {
|
||||||
return this.missingPing;
|
return this.missingPing;
|
||||||
|
|
|
@ -45,4 +45,9 @@ public class WLANStatusIndicator extends AbstractLogNumberIndicator {
|
||||||
return IndicatorType.WLAN_STATUS;
|
return IndicatorType.WLAN_STATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientIndicatorType indicatorType() {
|
||||||
|
return ClientIndicatorType.WLAN_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,4 +30,9 @@ public class WarnLogCountClientIndicator extends AbstractLogLevelCountIndicator
|
||||||
public IndicatorType getType() {
|
public IndicatorType getType() {
|
||||||
return IndicatorType.WARN_COUNT;
|
return IndicatorType.WARN_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientIndicatorType indicatorType() {
|
||||||
|
return ClientIndicatorType.WARN_LOG_COUNT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import org.joda.time.DateTimeUtils;
|
import org.joda.time.DateTimeUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -20,7 +18,6 @@ import org.mockito.Mockito;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
|
|
||||||
|
|
||||||
public class PingIntervalClientIndicatorTest {
|
public class PingIntervalClientIndicatorTest {
|
||||||
|
|
||||||
|
@ -34,12 +31,10 @@ public class PingIntervalClientIndicatorTest {
|
||||||
|
|
||||||
DateTimeUtils.setCurrentMillisProvider(() -> 1L);
|
DateTimeUtils.setCurrentMillisProvider(() -> 1L);
|
||||||
|
|
||||||
final ClientEventDAO clientEventDAO = Mockito.mock(ClientEventDAO.class);
|
final DistributedPingService distributedPingCache = Mockito.mock(DistributedPingService.class);
|
||||||
final DistributedPingCache distributedPingCache = Mockito.mock(DistributedPingCache.class);
|
|
||||||
final Executor executor = Mockito.mock(Executor.class);
|
|
||||||
|
|
||||||
final PingIntervalClientIndicator pingIntervalClientIndicator =
|
final PingIntervalClientIndicator pingIntervalClientIndicator =
|
||||||
new PingIntervalClientIndicator(distributedPingCache, executor);
|
new PingIntervalClientIndicator(distributedPingCache);
|
||||||
assertEquals("0.0", String.valueOf(pingIntervalClientIndicator.getValue()));
|
assertEquals("0.0", String.valueOf(pingIntervalClientIndicator.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,12 +43,10 @@ public class PingIntervalClientIndicatorTest {
|
||||||
|
|
||||||
DateTimeUtils.setCurrentMillisProvider(() -> 1L);
|
DateTimeUtils.setCurrentMillisProvider(() -> 1L);
|
||||||
|
|
||||||
final ClientEventDAO clientEventDAO = Mockito.mock(ClientEventDAO.class);
|
final DistributedPingService distributedPingCache = Mockito.mock(DistributedPingService.class);
|
||||||
final DistributedPingCache distributedPingCache = Mockito.mock(DistributedPingCache.class);
|
|
||||||
final Executor executor = Mockito.mock(Executor.class);
|
|
||||||
|
|
||||||
final PingIntervalClientIndicator pingIntervalClientIndicator =
|
final PingIntervalClientIndicator pingIntervalClientIndicator =
|
||||||
new PingIntervalClientIndicator(distributedPingCache, executor);
|
new PingIntervalClientIndicator(distributedPingCache);
|
||||||
assertEquals("0.0", String.valueOf(pingIntervalClientIndicator.getValue()));
|
assertEquals("0.0", String.valueOf(pingIntervalClientIndicator.getValue()));
|
||||||
|
|
||||||
DateTimeUtils.setCurrentMillisProvider(() -> 10L);
|
DateTimeUtils.setCurrentMillisProvider(() -> 10L);
|
||||||
|
@ -65,12 +58,10 @@ public class PingIntervalClientIndicatorTest {
|
||||||
public void testSerialization() throws JsonProcessingException {
|
public void testSerialization() throws JsonProcessingException {
|
||||||
DateTimeUtils.setCurrentMillisProvider(() -> 1L);
|
DateTimeUtils.setCurrentMillisProvider(() -> 1L);
|
||||||
|
|
||||||
final ClientEventDAO clientEventDAO = Mockito.mock(ClientEventDAO.class);
|
final DistributedPingService distributedPingCache = Mockito.mock(DistributedPingService.class);
|
||||||
final DistributedPingCache distributedPingCache = Mockito.mock(DistributedPingCache.class);
|
|
||||||
final Executor executor = Mockito.mock(Executor.class);
|
|
||||||
|
|
||||||
final PingIntervalClientIndicator pingIntervalClientIndicator =
|
final PingIntervalClientIndicator pingIntervalClientIndicator =
|
||||||
new PingIntervalClientIndicator(distributedPingCache, executor);
|
new PingIntervalClientIndicator(distributedPingCache);
|
||||||
final JSONMapper jsonMapper = new JSONMapper();
|
final JSONMapper jsonMapper = new JSONMapper();
|
||||||
final String json = jsonMapper.writeValueAsString(pingIntervalClientIndicator);
|
final String json = jsonMapper.writeValueAsString(pingIntervalClientIndicator);
|
||||||
assertEquals("{\"indicatorValue\":0.0,\"indicatorType\":\"LAST_PING\"}", json);
|
assertEquals("{\"indicatorValue\":0.0,\"indicatorType\":\"LAST_PING\"}", json);
|
||||||
|
|
Loading…
Reference in a new issue