code cleanup and docu
This commit is contained in:
parent
70fcbead41
commit
100c5820a2
5 changed files with 38 additions and 41 deletions
|
@ -32,6 +32,9 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
||||||
|
|
||||||
|
/** The open edX SEB course restriction API implementation.
|
||||||
|
*
|
||||||
|
* See also : https://seb-openedx.readthedocs.io/en/latest/ */
|
||||||
public class OpenEdxCourseRestriction {
|
public class OpenEdxCourseRestriction {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(OpenEdxCourseRestriction.class);
|
private static final Logger log = LoggerFactory.getLogger(OpenEdxCourseRestriction.class);
|
||||||
|
@ -43,7 +46,6 @@ public class OpenEdxCourseRestriction {
|
||||||
private final LmsSetup lmsSetup;
|
private final LmsSetup lmsSetup;
|
||||||
private final JSONMapper jsonMapper;
|
private final JSONMapper jsonMapper;
|
||||||
private final OpenEdxRestTemplateFactory openEdxRestTemplateFactory;
|
private final OpenEdxRestTemplateFactory openEdxRestTemplateFactory;
|
||||||
private final int restrictionAPIPushCount;
|
|
||||||
|
|
||||||
private OAuth2RestTemplate restTemplate;
|
private OAuth2RestTemplate restTemplate;
|
||||||
|
|
||||||
|
@ -56,7 +58,6 @@ public class OpenEdxCourseRestriction {
|
||||||
this.lmsSetup = lmsSetup;
|
this.lmsSetup = lmsSetup;
|
||||||
this.jsonMapper = jsonMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
this.openEdxRestTemplateFactory = openEdxRestTemplateFactory;
|
this.openEdxRestTemplateFactory = openEdxRestTemplateFactory;
|
||||||
this.restrictionAPIPushCount = restrictionAPIPushCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LmsSetupTestResult initAPIAccess() {
|
LmsSetupTestResult initAPIAccess() {
|
||||||
|
@ -145,9 +146,9 @@ public class OpenEdxCourseRestriction {
|
||||||
log.debug("PUT SEB Client restriction on course: {} : {}", courseId, restriction);
|
log.debug("PUT SEB Client restriction on course: {} : {}", courseId, restriction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleSEBRestriction(processSEBRestrictionUpdate(pushSEBRestrictionFunction(
|
return handleSEBRestriction(pushSEBRestrictionFunction(
|
||||||
restriction,
|
restriction,
|
||||||
courseId)));
|
courseId));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Boolean> deleteSEBRestriction(final String courseId) {
|
Result<Boolean> deleteSEBRestriction(final String courseId) {
|
||||||
|
@ -156,41 +157,7 @@ public class OpenEdxCourseRestriction {
|
||||||
log.debug("DELETE SEB Client restriction on course: {}", courseId);
|
log.debug("DELETE SEB Client restriction on course: {}", courseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleSEBRestriction(processSEBRestrictionUpdate(deleteSEBRestrictionFunction(courseId)));
|
return handleSEBRestriction(deleteSEBRestrictionFunction(courseId));
|
||||||
}
|
|
||||||
|
|
||||||
private BooleanSupplier processSEBRestrictionUpdate(final BooleanSupplier restrictionUpdate) {
|
|
||||||
return () -> {
|
|
||||||
if (this.restrictionAPIPushCount > 0) {
|
|
||||||
// NOTE: This is a temporary work-around for SEB Restriction API within Open edX SEB integration plugin to
|
|
||||||
// apply on load-balanced infrastructure or infrastructure that has several layers of cache.
|
|
||||||
// The reason for this is that the API (Open edX system) internally don't apply a resource-change that is
|
|
||||||
// done within HTTP API call immediately from an outside perspective.
|
|
||||||
// After a resource-change on the API is done, the system toggles between the old and the new resource
|
|
||||||
// while constantly calling GET. This usually happens for about a minute or two then it stabilizes on the new resource
|
|
||||||
//
|
|
||||||
// This may source on load-balancing or internally caching on Open edX side.
|
|
||||||
// To mitigate this effect the SEB Server can be configured to apply a resource-change on the
|
|
||||||
// API several times in a row to flush as match caches and reach as match as possible server instances.
|
|
||||||
//
|
|
||||||
// Since this is a brute-force method to mitigate the problem, this should only be a temporary
|
|
||||||
// work-around until a better solution on Open edX SEB integration side has been found and applied.
|
|
||||||
|
|
||||||
log.warn("SEB restriction update with multiple API push "
|
|
||||||
+ "(this is a temporary work-around for SEB Restriction API within Open edX SEB integration plugin)");
|
|
||||||
|
|
||||||
for (int i = 0; i < this.restrictionAPIPushCount; i++) {
|
|
||||||
if (!restrictionUpdate.getAsBoolean()) {
|
|
||||||
Result.ofRuntimeError(
|
|
||||||
"Failed to process SEB restriction update. See logs for more information");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return restrictionUpdate.getAsBoolean();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BooleanSupplier pushSEBRestrictionFunction(
|
private BooleanSupplier pushSEBRestrictionFunction(
|
||||||
|
|
|
@ -31,6 +31,10 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
||||||
|
|
||||||
|
/** The OpenEdxLmsAPITemplate is separated into two parts:
|
||||||
|
* - OpenEdxCourseAccess implements the course access API
|
||||||
|
* - OpenEdxCourseRestriction implements the SEB restriction API
|
||||||
|
* - Both uses the OpenEdxRestTemplateFactory to create a spring based RestTemplate to access the LMS API */
|
||||||
final class OpenEdxLmsAPITemplate implements LmsAPITemplate {
|
final class OpenEdxLmsAPITemplate implements LmsAPITemplate {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(OpenEdxLmsAPITemplate.class);
|
private static final Logger log = LoggerFactory.getLogger(OpenEdxLmsAPITemplate.class);
|
||||||
|
|
|
@ -51,7 +51,17 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestT
|
||||||
|
|
||||||
/** Implements the LmsAPITemplate for Open edX LMS Course API access.
|
/** Implements the LmsAPITemplate for Open edX LMS Course API access.
|
||||||
*
|
*
|
||||||
* See also: https://docs.moodle.org/dev/Web_service_API_functions */
|
* See also: https://docs.moodle.org/dev/Web_service_API_functions
|
||||||
|
*
|
||||||
|
* NOTE: Because of the missing integration on Moodle side so far the MoodleCourseAccess
|
||||||
|
* needs to deal with Moodle's standard API functions that don't allow to filter and page course/quiz data
|
||||||
|
* in an easy and proper way. Therefore we have to fetch all course and quiz data from Moodle before
|
||||||
|
* filtering and paging can be applied. Since there are possibly thousands of active courses and quizzes
|
||||||
|
* this moodle course access implements an synchronous fetch as well as an asynchronous fetch strategy.
|
||||||
|
* The asynchronous fetch strategy is started within a background task and fill up a shared cache.
|
||||||
|
* A request will start the background task if needed and return immediately to do not block the request.
|
||||||
|
* The planed Moodle integration on moodle side also defines an improved course access API. This will
|
||||||
|
* possibly make this synchronous fetch strategy obsolete in the future. */
|
||||||
public class MoodleCourseAccess extends CourseAccess {
|
public class MoodleCourseAccess extends CourseAccess {
|
||||||
|
|
||||||
private static final long INITIAL_WAIT_TIME = 3 * Constants.SECOND_IN_MILLIS;
|
private static final long INITIAL_WAIT_TIME = 3 * Constants.SECOND_IN_MILLIS;
|
||||||
|
@ -253,6 +263,7 @@ public class MoodleCourseAccess extends CourseAccess {
|
||||||
final DateTime quizFromTime = (filterMap != null) ? filterMap.getQuizFromTime() : null;
|
final DateTime quizFromTime = (filterMap != null) ? filterMap.getQuizFromTime() : null;
|
||||||
final long fromCutTime = (quizFromTime != null) ? Utils.toUnixTimeInSeconds(quizFromTime) : -1;
|
final long fromCutTime = (quizFromTime != null) ? Utils.toUnixTimeInSeconds(quizFromTime) : -1;
|
||||||
|
|
||||||
|
// Verify and call the proper strategy to get the course and quiz data
|
||||||
Collection<CourseDataShort> courseQuizData = Collections.emptyList();
|
Collection<CourseDataShort> courseQuizData = Collections.emptyList();
|
||||||
if (this.moodleCourseDataAsyncLoader.isRunning()) {
|
if (this.moodleCourseDataAsyncLoader.isRunning()) {
|
||||||
courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData();
|
courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData();
|
||||||
|
|
|
@ -53,6 +53,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestT
|
||||||
@Component
|
@Component
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
/** This implements the (temporary) asynchronous fetch strategy to fetch
|
||||||
|
* course and quiz data within a background task and fill up a shared cache. */
|
||||||
public class MoodleCourseDataAsyncLoader {
|
public class MoodleCourseDataAsyncLoader {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MoodleCourseDataAsyncLoader.class);
|
private static final Logger log = LoggerFactory.getLogger(MoodleCourseDataAsyncLoader.class);
|
||||||
|
|
|
@ -32,6 +32,20 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.NoSEBRestrictionException;
|
||||||
|
|
||||||
|
/** The MoodleLmsAPITemplate is separated into two parts:
|
||||||
|
* - MoodleCourseAccess implements the course access API
|
||||||
|
* - MoodleCourseRestriction implements the SEB restriction API
|
||||||
|
* - Both uses the MoodleRestTemplateFactore to create a spring based RestTemplate to access the LMS API
|
||||||
|
*
|
||||||
|
* NOTE: Because of the missing integration on Moodle side so far the MoodleCourseAccess
|
||||||
|
* needs to deal with Moodle's standard API functions that don't allow to filter and page course/quiz data
|
||||||
|
* in an easy and proper way. Therefore we have to fetch all course and quiz data from Moodle before
|
||||||
|
* filtering and paging can be applied. Since there are possibly thousands of active courses and quizzes
|
||||||
|
* this moodle course access implements an synchronous fetch as well as an asynchronous fetch strategy.
|
||||||
|
* The asynchronous fetch strategy is started within a background task and fill up a shared cache.
|
||||||
|
* A request will start the background task if needed and return immediately to do not block the request.
|
||||||
|
* The planed Moodle integration on moodle side also defines an improved course access API. This will
|
||||||
|
* possibly make this synchronous fetch strategy obsolete in the future. */
|
||||||
public class MoodleLmsAPITemplate implements LmsAPITemplate {
|
public class MoodleLmsAPITemplate implements LmsAPITemplate {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MoodleLmsAPITemplate.class);
|
private static final Logger log = LoggerFactory.getLogger(MoodleLmsAPITemplate.class);
|
||||||
|
@ -63,7 +77,6 @@ public class MoodleLmsAPITemplate implements LmsAPITemplate {
|
||||||
@Override
|
@Override
|
||||||
public LmsSetupTestResult testCourseRestrictionAPI() {
|
public LmsSetupTestResult testCourseRestrictionAPI() {
|
||||||
throw new NoSEBRestrictionException();
|
throw new NoSEBRestrictionException();
|
||||||
//return this.moodleCourseRestriction.initAPIAccess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue