Merge remote-tracking branch 'origin/dev-1.3' into development
Conflicts: src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/mockup/MockupLmsAPITemplate.java
This commit is contained in:
commit
d2ea6eb316
10 changed files with 108 additions and 8 deletions
|
@ -105,4 +105,10 @@ public interface ConfigurationDAO extends EntityDAO<Configuration, Configuration
|
|||
* @return the last version of configuration */
|
||||
Result<Configuration> getConfigurationLastStableVersion(Long configNodeId);
|
||||
|
||||
/** Use this to get the follow-up configuration identifer for a specified configuration node.
|
||||
*
|
||||
* @param configurationNode ConfigurationNode to get the current follow-up configuration from
|
||||
* @return the current follow-up configuration identifier */
|
||||
Result<Long> getFollowupConfigurationId(Long configNodeId);
|
||||
|
||||
}
|
||||
|
|
|
@ -133,8 +133,24 @@ public class ConfigurationDAOImpl implements ConfigurationDAO {
|
|||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.collect(Utils.toSingleton())).flatMap(ConfigurationDAOImpl::toDomainModel);
|
||||
.collect(Utils.toSingleton()))
|
||||
.flatMap(ConfigurationDAOImpl::toDomainModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Long> getFollowupConfigurationId(final Long configNodeId) {
|
||||
return Result.tryCatch(() -> this.configurationRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
ConfigurationRecordDynamicSqlSupport.configurationNodeId,
|
||||
isEqualTo(configNodeId))
|
||||
.and(
|
||||
ConfigurationRecordDynamicSqlSupport.followup,
|
||||
isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.collect(Utils.toSingleton()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -84,6 +84,13 @@ public class MockCourseAccessAPI implements CourseAccessAPI {
|
|||
DateTime.now(DateTimeZone.UTC).plus(6 * Constants.MINUTE_IN_MILLIS)
|
||||
.toString(Constants.DEFAULT_DATE_TIME_FORMAT),
|
||||
"http://lms.mockup.com/api/"));
|
||||
this.mockups.add(new QuizData(
|
||||
"quiz11", institutionId, lmsSetupId, lmsType, "Demo Quiz 11 (MOCKUP)",
|
||||
"Starts in a minute and ends never",
|
||||
DateTime.now(DateTimeZone.UTC).plus(Constants.MINUTE_IN_MILLIS)
|
||||
.toString(Constants.DEFAULT_DATE_TIME_FORMAT),
|
||||
null,
|
||||
"http://lms.mockup.com/api/"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,6 +36,13 @@ public interface ExamConfigService {
|
|||
* @throws FieldValidationException on validation exception */
|
||||
void validate(ConfigurationTableValues tableValue) throws FieldValidationException;
|
||||
|
||||
/** Get the follow-up configuration identifier for a given configuration node identifier.
|
||||
*
|
||||
* @param examConfigNodeId the exam configuration node identifier
|
||||
* @return Result refer to the follow-up configuration identifier of the given config node or to an error when
|
||||
* happened */
|
||||
Result<Long> getFollowupConfigurationId(final Long examConfigNodeId);
|
||||
|
||||
/** Used to export a specified SEB Exam Configuration as plain XML
|
||||
* This exports the values of the follow-up configuration defined by a given
|
||||
* ConfigurationNode (configurationNodeId)
|
||||
|
|
|
@ -136,6 +136,10 @@ public class ExamConfigServiceImpl implements ExamConfigService {
|
|||
}
|
||||
}
|
||||
|
||||
public Result<Long> getFollowupConfigurationId(final Long examConfigNodeId) {
|
||||
return this.configurationDAO.getFollowupConfigurationId(examConfigNodeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportPlainXML(
|
||||
final OutputStream out,
|
||||
|
|
|
@ -173,8 +173,12 @@ public class ExamSessionCacheService {
|
|||
byteOut,
|
||||
institutionId,
|
||||
examId);
|
||||
final Long followupId = this.sebExamConfigService
|
||||
.getFollowupConfigurationId(configId)
|
||||
.onError(error -> log.error("Failed to get follow-up id for config node: {}", configId, error))
|
||||
.getOr(-1L);
|
||||
|
||||
return new InMemorySEBConfig(configId, examId, byteOut.toByteArray());
|
||||
return new InMemorySEBConfig(configId, followupId, examId, byteOut.toByteArray());
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while getting default exam configuration for running exam; {}", examId, e);
|
||||
|
@ -182,6 +186,19 @@ public class ExamSessionCacheService {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isUpToDate(final InMemorySEBConfig inMemorySEBConfig) {
|
||||
try {
|
||||
final Long followupId = this.sebExamConfigService
|
||||
.getFollowupConfigurationId(inMemorySEBConfig.configId)
|
||||
.getOrThrow();
|
||||
|
||||
return followupId.equals(inMemorySEBConfig.follwupId);
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to check if InMemorySEBConfig is up to date for: {}", inMemorySEBConfig);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@CacheEvict(
|
||||
cacheNames = CACHE_NAME_SEB_CONFIG_EXAM,
|
||||
key = "#examId")
|
||||
|
|
|
@ -157,7 +157,7 @@ public class ExamSessionControlTask implements DisposableBean {
|
|||
.getOrThrow()
|
||||
.stream()
|
||||
.filter(exam -> exam.startTime.minus(this.examTimePrefix).isBefore(now))
|
||||
.filter(exam -> exam.endTime != null && exam.endTime.plus(this.examTimeSuffix).isAfter(now))
|
||||
.filter(exam -> exam.endTime == null || exam.endTime.plus(this.examTimeSuffix).isAfter(now))
|
||||
.flatMap(exam -> Result.skipOnError(this.examUpdateHandler.setRunning(exam, updateId)))
|
||||
.collect(Collectors.toMap(Exam::getId, Exam::getName));
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
|||
log.trace("Trying to get exam from InMemorySEBConfig");
|
||||
}
|
||||
|
||||
final InMemorySEBConfig sebConfigForExam = this.examSessionCacheService
|
||||
InMemorySEBConfig sebConfigForExam = this.examSessionCacheService
|
||||
.getDefaultSEBConfigForExam(connection.examId, institutionId);
|
||||
|
||||
if (sebConfigForExam == null) {
|
||||
|
@ -304,6 +304,23 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
|||
return;
|
||||
}
|
||||
|
||||
// for distributed setups check if cached config is still up to date. Flush and reload if not.
|
||||
if (this.distributedSetup && !this.examSessionCacheService.isUpToDate(sebConfigForExam)) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Detected new version of exam configuration for exam {} ...flush cache", connection.examId);
|
||||
}
|
||||
|
||||
this.examSessionCacheService.evictDefaultSEBConfig(connection.examId);
|
||||
sebConfigForExam = this.examSessionCacheService
|
||||
.getDefaultSEBConfigForExam(connection.examId, institutionId);
|
||||
}
|
||||
|
||||
if (sebConfigForExam == null) {
|
||||
log.error("Failed to get and cache InMemorySEBConfig for connection: {}", connection);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
|
|
|
@ -11,12 +11,19 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
|||
public final class InMemorySEBConfig {
|
||||
|
||||
public final Long configId;
|
||||
public final Long follwupId;
|
||||
public final Long examId;
|
||||
private final byte[] data;
|
||||
|
||||
protected InMemorySEBConfig(final Long configId, final Long examId, final byte[] data) {
|
||||
protected InMemorySEBConfig(
|
||||
final Long configId,
|
||||
final Long follwupId,
|
||||
final Long examId,
|
||||
final byte[] data) {
|
||||
|
||||
super();
|
||||
this.configId = configId;
|
||||
this.follwupId = follwupId;
|
||||
this.examId = examId;
|
||||
this.data = data;
|
||||
}
|
||||
|
@ -39,6 +46,7 @@ public final class InMemorySEBConfig {
|
|||
int result = 1;
|
||||
result = prime * result + ((this.configId == null) ? 0 : this.configId.hashCode());
|
||||
result = prime * result + ((this.examId == null) ? 0 : this.examId.hashCode());
|
||||
result = prime * result + ((this.follwupId == null) ? 0 : this.follwupId.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -61,7 +69,25 @@ public final class InMemorySEBConfig {
|
|||
return false;
|
||||
} else if (!this.examId.equals(other.examId))
|
||||
return false;
|
||||
if (this.follwupId == null) {
|
||||
if (other.follwupId != null)
|
||||
return false;
|
||||
} else if (!this.follwupId.equals(other.follwupId))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("InMemorySEBConfig [configId=");
|
||||
builder.append(this.configId);
|
||||
builder.append(", follwupId=");
|
||||
builder.append(this.follwupId);
|
||||
builder.append(", examId=");
|
||||
builder.append(this.examId);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester {
|
|||
});
|
||||
|
||||
assertNotNull(quizzes);
|
||||
assertTrue(quizzes.content.size() == 8);
|
||||
assertTrue(quizzes.content.size() == 9);
|
||||
|
||||
// for the inactive LmsSetup we should'nt get any quizzes
|
||||
quizzes = new RestAPITestHelper()
|
||||
|
@ -109,7 +109,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester {
|
|||
});
|
||||
|
||||
assertNotNull(quizzes);
|
||||
assertTrue(quizzes.content.size() == 8);
|
||||
assertTrue(quizzes.content.size() == 9);
|
||||
|
||||
// but for the now active lmsSetup2 we should get the quizzes
|
||||
quizzes = new RestAPITestHelper()
|
||||
|
@ -120,7 +120,7 @@ public class QuizDataTest extends AdministrationAPIIntegrationTester {
|
|||
});
|
||||
|
||||
assertNotNull(quizzes);
|
||||
assertTrue(quizzes.content.size() == 8);
|
||||
assertTrue(quizzes.content.size() == 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in a new issue