various stability fixed for ping and indicator handling
This commit is contained in:
parent
f645192e60
commit
e569b3592b
10 changed files with 184 additions and 84 deletions
|
@ -128,6 +128,9 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
// Create an initial admin account if requested and not already in the data-base
|
// Create an initial admin account if requested and not already in the data-base
|
||||||
this.adminUserInitializer.initAdminAccount();
|
this.adminUserInitializer.initAdminAccount();
|
||||||
|
|
||||||
|
SEBServerInit.INIT_LOGGER.info("----> log4j2.formatMsgNoLookups = {}",
|
||||||
|
this.environment.getProperty("log4j2.formatMsgNoLookups", "none"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
|
|
|
@ -44,6 +44,14 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
|
||||||
* happened */
|
* happened */
|
||||||
Result<Collection<Long>> allIdsOfInstitution(Long institutionId);
|
Result<Collection<Long>> allIdsOfInstitution(Long institutionId);
|
||||||
|
|
||||||
|
/** Get all active and running Exams for a given institution.
|
||||||
|
*
|
||||||
|
* @param institutionId the identifier of the institution
|
||||||
|
* @return Result refer to a collection of all active and running exams of the given institution or refer to an
|
||||||
|
* error if
|
||||||
|
* happened */
|
||||||
|
Result<Collection<Long>> allIdsOfRunning(final Long institutionId);
|
||||||
|
|
||||||
/** Get all institution ids for that a specified exam for given quiz id already exists
|
/** Get all institution ids for that a specified exam for given quiz id already exists
|
||||||
*
|
*
|
||||||
* @param quizId The quiz or external identifier of the exam (LMS)
|
* @param quizId The quiz or external identifier of the exam (LMS)
|
||||||
|
|
|
@ -132,6 +132,18 @@ public interface RemoteProctoringRoomDAO {
|
||||||
* @return Result refer to active break-out rooms or to an error when happened */
|
* @return Result refer to active break-out rooms or to an error when happened */
|
||||||
Result<Collection<String>> getConnectionsInBreakoutRooms(Long examId);
|
Result<Collection<String>> getConnectionsInBreakoutRooms(Long examId);
|
||||||
|
|
||||||
|
/** Mark a specified collecting room as opened or closed by a proctor.
|
||||||
|
*
|
||||||
|
* @param roomId The collecting room identifier
|
||||||
|
* @param isOpen mark open or not */
|
||||||
void setCollectingRoomOpenFlag(Long roomId, boolean isOpen);
|
void setCollectingRoomOpenFlag(Long roomId, boolean isOpen);
|
||||||
|
|
||||||
|
/** Use this to update the current room size of for a proctoring collecting room
|
||||||
|
* by its real number of attached SEB connections. This can be used on error case to
|
||||||
|
* recover and set the re calc the number of participants in a room
|
||||||
|
*
|
||||||
|
* @param remoteProctoringRoomId The proctoring room identifier
|
||||||
|
* @return The newly calculated number of participants in the room. */
|
||||||
|
Result<Long> updateRoomSize(Long remoteProctoringRoomId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,7 +186,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<Collection<ClientConnectionRecord>> getAllConnectionIdsForRoomUpdateActive() {
|
public Result<Collection<ClientConnectionRecord>> getAllConnectionIdsForRoomUpdateActive() {
|
||||||
return Result.tryCatch(() -> {
|
return Result.<Collection<ClientConnectionRecord>> tryCatch(() -> {
|
||||||
|
|
||||||
final Collection<ClientConnectionRecord> records = this.clientConnectionRecordMapper
|
final Collection<ClientConnectionRecord> records = this.clientConnectionRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
||||||
|
@ -210,7 +211,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
return records;
|
return records;
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientConnectionRecord createProctoringRoomUpdateRecord(final int remoteProctoringRoomUpdate) {
|
private ClientConnectionRecord createProctoringRoomUpdateRecord(final int remoteProctoringRoomUpdate) {
|
||||||
|
@ -250,7 +252,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<Collection<ClientConnectionRecord>> getAllConnectionIdsForRoomUpdateInactive() {
|
public Result<Collection<ClientConnectionRecord>> getAllConnectionIdsForRoomUpdateInactive() {
|
||||||
return Result.tryCatch(() -> {
|
return Result.<Collection<ClientConnectionRecord>> tryCatch(() -> {
|
||||||
final Collection<ClientConnectionRecord> records = this.clientConnectionRecordMapper
|
final Collection<ClientConnectionRecord> records = this.clientConnectionRecordMapper
|
||||||
.selectByExample()
|
.selectByExample()
|
||||||
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
.where(ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomUpdate, isNotEqualTo(0))
|
||||||
|
@ -274,13 +276,17 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
return records;
|
return records;
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void setNeedsRoomUpdate(final Long connectionId) {
|
public void setNeedsRoomUpdate(final Long connectionId) {
|
||||||
final ClientConnectionRecord updateRecord = createProctoringRoomUpdateRecord(1);
|
final ClientConnectionRecord updateRecord = new ClientConnectionRecord(
|
||||||
|
connectionId, null, null, null, null, null,
|
||||||
|
null, null, null, null, null, null, null,
|
||||||
|
1);
|
||||||
this.clientConnectionRecordMapper.updateByPrimaryKeySelective(updateRecord);
|
this.clientConnectionRecordMapper.updateByPrimaryKeySelective(updateRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,8 +368,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
data.vdiPairToken,
|
data.vdiPairToken,
|
||||||
null,
|
null,
|
||||||
millisecondsNow,
|
millisecondsNow,
|
||||||
data.remoteProctoringRoomId,
|
null,
|
||||||
BooleanUtils.toIntegerObject(data.remoteProctoringRoomUpdate));
|
null);
|
||||||
|
|
||||||
this.clientConnectionRecordMapper.updateByPrimaryKeySelective(updateRecord);
|
this.clientConnectionRecordMapper.updateByPrimaryKeySelective(updateRecord);
|
||||||
return this.clientConnectionRecordMapper.selectByPrimaryKey(data.id);
|
return this.clientConnectionRecordMapper.selectByPrimaryKey(data.id);
|
||||||
|
@ -386,7 +392,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
null, null, null, null, null, null,
|
null, null, null, null, null, null,
|
||||||
roomId,
|
roomId,
|
||||||
0));
|
0));
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -399,7 +406,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
null, null, null, null, null, null,
|
null, null, null, null, null, null,
|
||||||
null,
|
null,
|
||||||
1));
|
1));
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -426,7 +434,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
} else {
|
} else {
|
||||||
throw new ResourceNotFoundException(EntityType.CLIENT_CONNECTION, String.valueOf(connectionId));
|
throw new ResourceNotFoundException(EntityType.CLIENT_CONNECTION, String.valueOf(connectionId));
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -467,7 +476,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||||
return Result.tryCatch(() -> {
|
return Result.<Collection<EntityKey>> tryCatch(() -> {
|
||||||
|
|
||||||
final List<Long> ids = extractListOfPKs(all);
|
final List<Long> ids = extractListOfPKs(all);
|
||||||
if (ids == null || ids.isEmpty()) {
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
@ -514,7 +523,8 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
|
||||||
return ids.stream()
|
return ids.stream()
|
||||||
.map(id -> new EntityKey(id, EntityType.CLIENT_CONNECTION))
|
.map(id -> new EntityKey(id, EntityType.CLIENT_CONNECTION))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -144,6 +144,7 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
public Result<Collection<Long>> allInstitutionIdsByQuizId(final String quizId) {
|
public Result<Collection<Long>> allInstitutionIdsByQuizId(final String quizId) {
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
return this.examRecordMapper.selectByExample()
|
return this.examRecordMapper.selectByExample()
|
||||||
|
@ -242,6 +243,7 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
public Result<Exam> updateState(final Long examId, final ExamStatus status, final String updateId) {
|
public Result<Exam> updateState(final Long examId, final ExamStatus status, final String updateId) {
|
||||||
return recordById(examId)
|
return recordById(examId)
|
||||||
.map(examRecord -> {
|
.map(examRecord -> {
|
||||||
|
@ -727,6 +729,23 @@ public class ExamDAOImpl implements ExamDAO {
|
||||||
.execute());
|
.execute());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Result<Collection<Long>> allIdsOfRunning(final Long institutionId) {
|
||||||
|
return Result.tryCatch(() -> this.examRecordMapper.selectIdsByExample()
|
||||||
|
.where(
|
||||||
|
ExamRecordDynamicSqlSupport.institutionId,
|
||||||
|
isEqualTo(institutionId))
|
||||||
|
.and(
|
||||||
|
ExamRecordDynamicSqlSupport.active,
|
||||||
|
isEqualToWhenPresent(BooleanUtils.toIntegerObject(true)))
|
||||||
|
.and(
|
||||||
|
ExamRecordDynamicSqlSupport.status,
|
||||||
|
isEqualTo(ExamStatus.RUNNING.name()))
|
||||||
|
.build()
|
||||||
|
.execute());
|
||||||
|
}
|
||||||
|
|
||||||
private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
|
private Result<Collection<EntityDependency>> allIdsOfInstitution(final EntityKey institutionKey) {
|
||||||
return Result.tryCatch(() -> toDependencies(
|
return Result.tryCatch(() -> toDependencies(
|
||||||
this.examRecordMapper.selectByExample()
|
this.examRecordMapper.selectByExample()
|
||||||
|
|
|
@ -29,9 +29,12 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.RemoteProctoringRoom;
|
import ch.ethz.seb.sebserver.gbl.model.session.RemoteProctoringRoom;
|
||||||
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.datalayer.batis.mapper.ClientConnectionRecordDynamicSqlSupport;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientConnectionRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.RemoteProctoringRoomRecordDynamicSqlSupport;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.RemoteProctoringRoomRecordDynamicSqlSupport;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.RemoteProctoringRoomRecordMapper;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.RemoteProctoringRoomRecordMapper;
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.RemoteProctoringRoomRecord;
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.RemoteProctoringRoomRecord;
|
||||||
|
@ -47,16 +50,17 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(RemoteProctoringRoomDAOImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(RemoteProctoringRoomDAOImpl.class);
|
||||||
|
|
||||||
private static final Object RESERVE_ROOM_LOCK = new Object();
|
|
||||||
|
|
||||||
private final RemoteProctoringRoomRecordMapper remoteProctoringRoomRecordMapper;
|
private final RemoteProctoringRoomRecordMapper remoteProctoringRoomRecordMapper;
|
||||||
|
private final ClientConnectionRecordMapper clientConnectionRecordMapper;
|
||||||
private final AdditionalAttributesDAO additionalAttributesDAO;
|
private final AdditionalAttributesDAO additionalAttributesDAO;
|
||||||
|
|
||||||
protected RemoteProctoringRoomDAOImpl(
|
protected RemoteProctoringRoomDAOImpl(
|
||||||
final RemoteProctoringRoomRecordMapper remoteProctoringRoomRecordMapper,
|
final RemoteProctoringRoomRecordMapper remoteProctoringRoomRecordMapper,
|
||||||
|
final ClientConnectionRecordMapper clientConnectionRecordMapper,
|
||||||
final AdditionalAttributesDAO additionalAttributesDAO) {
|
final AdditionalAttributesDAO additionalAttributesDAO) {
|
||||||
|
|
||||||
this.remoteProctoringRoomRecordMapper = remoteProctoringRoomRecordMapper;
|
this.remoteProctoringRoomRecordMapper = remoteProctoringRoomRecordMapper;
|
||||||
|
this.clientConnectionRecordMapper = clientConnectionRecordMapper;
|
||||||
this.additionalAttributesDAO = additionalAttributesDAO;
|
this.additionalAttributesDAO = additionalAttributesDAO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +200,8 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
.map(room -> {
|
.map(room -> {
|
||||||
this.remoteProctoringRoomRecordMapper.deleteByPrimaryKey(room.id);
|
this.remoteProctoringRoomRecordMapper.deleteByPrimaryKey(room.id);
|
||||||
return new EntityKey(room.id, EntityType.REMOTE_PROCTORING_ROOM);
|
return new EntityKey(room.id, EntityType.REMOTE_PROCTORING_ROOM);
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -239,7 +244,8 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
.deleteByPrimaryKey(roomId);
|
.deleteByPrimaryKey(roomId);
|
||||||
|
|
||||||
return new EntityKey(roomId, EntityType.REMOTE_PROCTORING_ROOM);
|
return new EntityKey(roomId, EntityType.REMOTE_PROCTORING_ROOM);
|
||||||
});
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -286,23 +292,21 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
final Function<Long, Result<NewRoom>> newRoomFunction) {
|
final Function<Long, Result<NewRoom>> newRoomFunction) {
|
||||||
|
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
synchronized (RESERVE_ROOM_LOCK) {
|
final Optional<RemoteProctoringRoomRecord> room =
|
||||||
final Optional<RemoteProctoringRoomRecord> room =
|
this.remoteProctoringRoomRecordMapper.selectByExample()
|
||||||
this.remoteProctoringRoomRecordMapper.selectByExample()
|
.where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId))
|
||||||
.where(RemoteProctoringRoomRecordDynamicSqlSupport.examId, isEqualTo(examId))
|
.and(RemoteProctoringRoomRecordDynamicSqlSupport.townhallRoom, isEqualTo(0))
|
||||||
.and(RemoteProctoringRoomRecordDynamicSqlSupport.townhallRoom, isEqualTo(0))
|
.and(RemoteProctoringRoomRecordDynamicSqlSupport.breakOutConnections, isNull())
|
||||||
.and(RemoteProctoringRoomRecordDynamicSqlSupport.breakOutConnections, isNull())
|
.build()
|
||||||
.build()
|
.execute()
|
||||||
.execute()
|
.stream()
|
||||||
.stream()
|
.filter(r -> r.getSize() < roomMaxSize)
|
||||||
.filter(r -> r.getSize() < roomMaxSize)
|
.findFirst();
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (room.isPresent()) {
|
if (room.isPresent()) {
|
||||||
return updateCollectingRoom(room.get());
|
return updateCollectingRoom(room.get());
|
||||||
} else {
|
} else {
|
||||||
return createNewCollectingRoom(examId, newRoomFunction);
|
return createNewCollectingRoom(examId, newRoomFunction);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(this::toDomainModel)
|
.map(this::toDomainModel)
|
||||||
|
@ -313,18 +317,21 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
@Transactional
|
@Transactional
|
||||||
public Result<RemoteProctoringRoom> releasePlaceInCollectingRoom(final Long examId, final Long roomId) {
|
public Result<RemoteProctoringRoom> releasePlaceInCollectingRoom(final Long examId, final Long roomId) {
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
synchronized (RESERVE_ROOM_LOCK) {
|
final RemoteProctoringRoomRecord record = this.remoteProctoringRoomRecordMapper
|
||||||
final RemoteProctoringRoomRecord record = this.remoteProctoringRoomRecordMapper
|
.selectByPrimaryKey(roomId);
|
||||||
.selectByPrimaryKey(roomId);
|
|
||||||
|
|
||||||
final RemoteProctoringRoomRecord remoteProctoringRoomRecord = new RemoteProctoringRoomRecord(
|
final int size = record.getSize() - 1;
|
||||||
record.getId(), null, null,
|
if (size < 0) {
|
||||||
record.getSize() - 1, null, null, null, null, null);
|
throw new IllegalStateException("Room size mismatch, cannot be negative");
|
||||||
|
|
||||||
this.remoteProctoringRoomRecordMapper.updateByPrimaryKeySelective(remoteProctoringRoomRecord);
|
|
||||||
return this.remoteProctoringRoomRecordMapper
|
|
||||||
.selectByPrimaryKey(remoteProctoringRoomRecord.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final RemoteProctoringRoomRecord remoteProctoringRoomRecord = new RemoteProctoringRoomRecord(
|
||||||
|
record.getId(), null, null,
|
||||||
|
size, null, null, null, null, null);
|
||||||
|
|
||||||
|
this.remoteProctoringRoomRecordMapper.updateByPrimaryKeySelective(remoteProctoringRoomRecord);
|
||||||
|
return this.remoteProctoringRoomRecordMapper
|
||||||
|
.selectByPrimaryKey(remoteProctoringRoomRecord.getId());
|
||||||
})
|
})
|
||||||
.map(this::toDomainModel)
|
.map(this::toDomainModel)
|
||||||
.onError(TransactionHandler::rollback);
|
.onError(TransactionHandler::rollback);
|
||||||
|
@ -372,7 +379,34 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
|
||||||
BooleanUtils.toStringTrueFalse(isOpen))
|
BooleanUtils.toStringTrueFalse(isOpen))
|
||||||
.onError(error -> log.error("Failed to set open flag for proctoring room: {} : {}",
|
.onError(error -> log.error("Failed to set open flag for proctoring room: {} : {}",
|
||||||
roomId,
|
roomId,
|
||||||
error.getMessage()));
|
error.getMessage()))
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Result<Long> updateRoomSize(final Long remoteProctoringRoomId) {
|
||||||
|
return Result.tryCatch(() -> {
|
||||||
|
final Long size = this.clientConnectionRecordMapper
|
||||||
|
.countByExample()
|
||||||
|
.where(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.remoteProctoringRoomId,
|
||||||
|
isEqualTo(remoteProctoringRoomId))
|
||||||
|
.and(
|
||||||
|
ClientConnectionRecordDynamicSqlSupport.status,
|
||||||
|
isEqualTo(ConnectionStatus.ACTIVE.name()))
|
||||||
|
.build()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
this.remoteProctoringRoomRecordMapper.updateByPrimaryKeySelective(
|
||||||
|
new RemoteProctoringRoomRecord(
|
||||||
|
remoteProctoringRoomId, null, null,
|
||||||
|
size.intValue(), null, null,
|
||||||
|
null, null, null));
|
||||||
|
|
||||||
|
return size;
|
||||||
|
})
|
||||||
|
.onError(TransactionHandler::rollback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RemoteProctoringRoom toDomainModel(final RemoteProctoringRoomRecord record) {
|
private RemoteProctoringRoom toDomainModel(final RemoteProctoringRoomRecord record) {
|
||||||
|
|
|
@ -109,7 +109,7 @@ class ExamSessionControlTask implements DisposableBean {
|
||||||
this.examDAO.releaseAgedLocks();
|
this.examDAO.releaseAgedLocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedRateString = "${sebserver.webservice.api.seb.lostping.update:5000}")
|
@Scheduled(fixedDelayString = "${sebserver.webservice.api.seb.lostping.update:5000}")
|
||||||
public void examSessionUpdateTask() {
|
public void examSessionUpdateTask() {
|
||||||
|
|
||||||
this.sebClientConnectionService.updatePingEvents();
|
this.sebClientConnectionService.updatePingEvents();
|
||||||
|
|
|
@ -231,7 +231,7 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Collection<Exam>> getRunningExamsForInstitution(final Long institutionId) {
|
public Result<Collection<Exam>> getRunningExamsForInstitution(final Long institutionId) {
|
||||||
return this.examDAO.allIdsOfInstitution(institutionId)
|
return this.examDAO.allIdsOfRunning(institutionId)
|
||||||
.map(col -> col.stream()
|
.map(col -> col.stream()
|
||||||
.map(this::getRunningExam)
|
.map(this::getRunningExam)
|
||||||
.filter(Result::hasValue)
|
.filter(Result::hasValue)
|
||||||
|
|
|
@ -63,7 +63,11 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
|
||||||
|
|
||||||
super.init(indicatorDefinition, connectionId, active, cachingEnabled);
|
super.init(indicatorDefinition, connectionId, active, cachingEnabled);
|
||||||
|
|
||||||
this.currentValue = computeValueAt(DateTimeUtils.currentTimeMillis());
|
final long now = DateTimeUtils.currentTimeMillis();
|
||||||
|
this.currentValue = computeValueAt(now);
|
||||||
|
if (Double.isNaN(this.currentValue)) {
|
||||||
|
this.currentValue = now;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
indicatorDefinition
|
indicatorDefinition
|
||||||
|
|
|
@ -52,6 +52,8 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ExamProctoringRoomServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(ExamProctoringRoomServiceImpl.class);
|
||||||
|
|
||||||
|
private static final Object RESERVE_ROOM_LOCK = new Object();
|
||||||
|
|
||||||
private final RemoteProctoringRoomDAO remoteProctoringRoomDAO;
|
private final RemoteProctoringRoomDAO remoteProctoringRoomDAO;
|
||||||
private final ClientConnectionDAO clientConnectionDAO;
|
private final ClientConnectionDAO clientConnectionDAO;
|
||||||
private final ExamAdminService examAdminService;
|
private final ExamAdminService examAdminService;
|
||||||
|
@ -280,53 +282,61 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignToCollectingRoom(final ClientConnectionRecord cc) {
|
private void assignToCollectingRoom(final ClientConnectionRecord cc) {
|
||||||
try {
|
synchronized (RESERVE_ROOM_LOCK) {
|
||||||
|
try {
|
||||||
|
|
||||||
if (cc.getRemoteProctoringRoomId() == null) {
|
if (cc.getRemoteProctoringRoomId() == null) {
|
||||||
|
|
||||||
final RemoteProctoringRoom proctoringRoom = getProctoringRoom(
|
final RemoteProctoringRoom proctoringRoom = getProctoringRoom(
|
||||||
cc.getExamId(),
|
cc.getExamId(),
|
||||||
cc.getConnectionToken());
|
cc.getConnectionToken());
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Assigning new SEB client to proctoring room: {}, connection: {}",
|
log.debug("Assigning new SEB client to proctoring room: {}, connection: {}",
|
||||||
proctoringRoom.id,
|
proctoringRoom.id,
|
||||||
cc);
|
cc);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clientConnectionDAO
|
||||||
|
.assignToProctoringRoom(
|
||||||
|
cc.getId(),
|
||||||
|
cc.getConnectionToken(),
|
||||||
|
proctoringRoom.id)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
applyProcotringInstruction(cc)
|
||||||
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clientConnectionDAO
|
} catch (final Exception e) {
|
||||||
.assignToProctoringRoom(
|
log.error("Failed to assign connection to collecting room: {}", cc, e);
|
||||||
cc.getId(),
|
|
||||||
cc.getConnectionToken(),
|
|
||||||
proctoringRoom.id)
|
|
||||||
.getOrThrow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyProcotringInstruction(cc)
|
|
||||||
.getOrThrow();
|
|
||||||
|
|
||||||
} catch (final Exception e) {
|
|
||||||
log.error("Failed to assign connection to collecting room: {}", cc, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFromRoom(final ClientConnectionRecord cc) {
|
private void removeFromRoom(final ClientConnectionRecord cc) {
|
||||||
try {
|
synchronized (RESERVE_ROOM_LOCK) {
|
||||||
|
try {
|
||||||
|
|
||||||
this.remoteProctoringRoomDAO.releasePlaceInCollectingRoom(
|
this.remoteProctoringRoomDAO.releasePlaceInCollectingRoom(
|
||||||
cc.getExamId(),
|
cc.getExamId(),
|
||||||
cc.getRemoteProctoringRoomId());
|
cc.getRemoteProctoringRoomId());
|
||||||
|
|
||||||
this.cleanupBreakOutRooms(cc);
|
this.cleanupBreakOutRooms(cc);
|
||||||
|
|
||||||
this.clientConnectionDAO
|
this.clientConnectionDAO
|
||||||
.removeFromProctoringRoom(cc.getId(), cc.getConnectionToken())
|
.removeFromProctoringRoom(cc.getId(), cc.getConnectionToken())
|
||||||
.onError(error -> log.error("Failed to remove client connection form room: ", error))
|
.onError(error -> log.error("Failed to remove client connection from room: ", error))
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Failed to update client connection for proctoring room: ", e);
|
log.error("Failed to update client connection for proctoring room: ", e);
|
||||||
this.clientConnectionDAO.setNeedsRoomUpdate(cc.getId());
|
try {
|
||||||
|
this.remoteProctoringRoomDAO.updateRoomSize(cc.getRemoteProctoringRoomId());
|
||||||
|
} catch (final Exception ee) {
|
||||||
|
log.error("Failed to update room size: ", ee);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +642,7 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sendJoinInstruction(
|
registerJoinInstruction(
|
||||||
examId,
|
examId,
|
||||||
connectionToken,
|
connectionToken,
|
||||||
roomConnection,
|
roomConnection,
|
||||||
|
@ -688,7 +698,7 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
error.getMessage()))
|
error.getMessage()))
|
||||||
.get();
|
.get();
|
||||||
if (proctoringConnection != null) {
|
if (proctoringConnection != null) {
|
||||||
sendJoinInstruction(
|
registerJoinInstruction(
|
||||||
proctoringSettings.examId,
|
proctoringSettings.examId,
|
||||||
connectionToken,
|
connectionToken,
|
||||||
proctoringConnection,
|
proctoringConnection,
|
||||||
|
@ -753,7 +763,7 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
remoteProctoringRoom.subject)
|
remoteProctoringRoom.subject)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
sendJoinInstruction(
|
registerJoinInstruction(
|
||||||
proctoringSettings.examId,
|
proctoringSettings.examId,
|
||||||
clientConnection.clientConnection.connectionToken,
|
clientConnection.clientConnection.connectionToken,
|
||||||
proctoringConnection,
|
proctoringConnection,
|
||||||
|
@ -765,14 +775,14 @@ public class ExamProctoringRoomServiceImpl implements ExamProctoringRoomService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendJoinInstruction(
|
private void registerJoinInstruction(
|
||||||
final Long examId,
|
final Long examId,
|
||||||
final String connectionToken,
|
final String connectionToken,
|
||||||
final ProctoringRoomConnection proctoringConnection,
|
final ProctoringRoomConnection proctoringConnection,
|
||||||
final ExamProctoringService examProctoringService) {
|
final ExamProctoringService examProctoringService) {
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Send proctoring join instruction to connection: {}, room: {}",
|
log.debug("Register proctoring join instruction for connection: {}, room: {}",
|
||||||
connectionToken,
|
connectionToken,
|
||||||
proctoringConnection.roomName);
|
proctoringConnection.roomName);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue