LMS Template API

This commit is contained in:
anhefti 2020-12-09 16:56:05 +01:00
parent 29248898ff
commit 49b2ffe338
8 changed files with 14 additions and 45 deletions

View file

@ -46,12 +46,10 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
* @param <T> The of the result of the supplying function */ * @param <T> The of the result of the supplying function */
public final class MemoizingCircuitBreaker<T> implements Supplier<Result<T>> { public final class MemoizingCircuitBreaker<T> implements Supplier<Result<T>> {
// TODO considering invalidation time for memoizing
private static final Logger log = LoggerFactory.getLogger(MemoizingCircuitBreaker.class); private static final Logger log = LoggerFactory.getLogger(MemoizingCircuitBreaker.class);
private final CircuitBreaker<T> delegate; private final CircuitBreaker<T> delegate;
private final Supplier<T> supplier; private Supplier<T> supplier;
private final boolean memoizing; private final boolean memoizing;
private final long maxMemoizingTime; private final long maxMemoizingTime;
@ -121,6 +119,10 @@ public final class MemoizingCircuitBreaker<T> implements Supplier<Result<T>> {
this.maxMemoizingTime = maxMemoizingTime; this.maxMemoizingTime = maxMemoizingTime;
} }
public void setSupplier(final Supplier<T> supplier) {
this.supplier = supplier;
}
@Override @Override
public Result<T> get() { public Result<T> get() {
final Result<T> result = this.delegate.protectedRun(this.supplier); final Result<T> result = this.delegate.protectedRun(this.supplier);

View file

@ -95,8 +95,6 @@ public interface LmsAPITemplate {
.orElse(Result.ofError(new ResourceNotFoundException(EntityType.EXAM, id))); .orElse(Result.ofError(new ResourceNotFoundException(EntityType.EXAM, id)));
} }
Result<QuizData> getQuizFromCache(String id);
/** Convert a an anonymous or temporary user session identifier from SEB Client into a user /** Convert a an anonymous or temporary user session identifier from SEB Client into a user
* account details. * account details.
* *

View file

@ -43,7 +43,7 @@ public abstract class CourseAccess {
protected CourseAccess(final AsyncService asyncService) { protected CourseAccess(final AsyncService asyncService) {
this.allQuizzesRequest = asyncService.createMemoizingCircuitBreaker( this.allQuizzesRequest = asyncService.createMemoizingCircuitBreaker(
allQuizzesSupplier(), allQuizzesSupplier(null),
3, 3,
Constants.MINUTE_IN_MILLIS, Constants.MINUTE_IN_MILLIS,
Constants.MINUTE_IN_MILLIS, Constants.MINUTE_IN_MILLIS,
@ -66,15 +66,6 @@ public abstract class CourseAccess {
Constants.SECOND_IN_MILLIS * 10); Constants.SECOND_IN_MILLIS * 10);
} }
public Result<QuizData> getQuizFromCache(final String id) {
return Result.tryCatch(() -> this.allQuizzesRequest
.getCached()
.stream()
.filter(qd -> id.equals(qd.id))
.findFirst()
.orElseThrow(() -> new NoSuchElementException("No cached quiz: " + id)));
}
public Result<Collection<Result<QuizData>>> getQuizzesFromCache(final Set<String> ids) { public Result<Collection<Result<QuizData>>> getQuizzesFromCache(final Set<String> ids) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final List<QuizData> cached = this.allQuizzesRequest.getCached(); final List<QuizData> cached = this.allQuizzesRequest.getCached();
@ -109,12 +100,9 @@ public abstract class CourseAccess {
}); });
} }
/* Note: this can be overwritten to load missing requested quiz data from specified LMS by id */
protected Map<String, QuizData> loadMissingData(final Set<String> ids) {
throw new RuntimeException("Not all requested quizzes cached");
}
public Result<List<QuizData>> getQuizzes(final FilterMap filterMap) { public Result<List<QuizData>> getQuizzes(final FilterMap filterMap) {
// TODO deal with filter attributes
return this.allQuizzesRequest.get() return this.allQuizzesRequest.get()
.map(LmsAPIService.quizzesFilterFunction(filterMap)); .map(LmsAPIService.quizzesFilterFunction(filterMap));
} }
@ -150,7 +138,7 @@ public abstract class CourseAccess {
protected abstract Supplier<List<QuizData>> quizzesSupplier(final Set<String> ids); protected abstract Supplier<List<QuizData>> quizzesSupplier(final Set<String> ids);
protected abstract Supplier<List<QuizData>> allQuizzesSupplier(); protected abstract Supplier<List<QuizData>> allQuizzesSupplier(final FilterMap filterMap);
protected abstract Supplier<Chapters> getCourseChaptersSupplier(final String courseId); protected abstract Supplier<Chapters> getCourseChaptersSupplier(final String courseId);

View file

@ -169,11 +169,6 @@ final class MockupLmsAPITemplate implements LmsAPITemplate {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public Result<QuizData> getQuizFromCache(final String id) {
return getQuiz(id);
}
@Override @Override
public Collection<Result<QuizData>> getQuizzesFromCache(final Set<String> ids) { public Collection<Result<QuizData>> getQuizzesFromCache(final Set<String> ids) {
return getQuizzes(ids); return getQuizzes(ids);

View file

@ -49,6 +49,7 @@ import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
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.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.CourseAccess; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.CourseAccess;
/** Implements the LmsAPITemplate for Open edX LMS Course API access. /** Implements the LmsAPITemplate for Open edX LMS Course API access.
@ -173,7 +174,7 @@ final class OpenEdxCourseAccess extends CourseAccess {
} }
@Override @Override
protected Supplier<List<QuizData>> allQuizzesSupplier() { protected Supplier<List<QuizData>> allQuizzesSupplier(final FilterMap filterMap) {
return () -> getRestTemplate() return () -> getRestTemplate()
.map(this::collectAllQuizzes) .map(this::collectAllQuizzes)
.getOrThrow(); .getOrThrow();

View file

@ -8,9 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.edx; package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.edx;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -86,13 +84,6 @@ final class OpenEdxLmsAPITemplate implements LmsAPITemplate {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public Result<QuizData> getQuizFromCache(final String id) {
return getQuizzesFromCache(new HashSet<>(Arrays.asList(id)))
.iterator()
.next();
}
@Override @Override
public Collection<Result<QuizData>> getQuizzesFromCache(final Set<String> ids) { public Collection<Result<QuizData>> getQuizzesFromCache(final Set<String> ids) {
return this.openEdxCourseAccess.getQuizzesFromCache(ids) return this.openEdxCourseAccess.getQuizzesFromCache(ids)

View file

@ -46,6 +46,7 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails; import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.CourseAccess; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.CourseAccess;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory.MoodleAPIRestTemplate; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory.MoodleAPIRestTemplate;
@ -175,7 +176,7 @@ public class MoodleCourseAccess extends CourseAccess {
} }
@Override @Override
protected Supplier<List<QuizData>> allQuizzesSupplier() { protected Supplier<List<QuizData>> allQuizzesSupplier(final FilterMap filterMap) {
return () -> getRestTemplate() return () -> getRestTemplate()
.map(this::collectAllQuizzes) .map(this::collectAllQuizzes)
.getOrThrow(); .getOrThrow();
@ -228,9 +229,8 @@ public class MoodleCourseAccess extends CourseAccess {
private List<CourseData> getQuizzesBatch(final MoodleAPIRestTemplate restTemplate, final int page) { private List<CourseData> getQuizzesBatch(final MoodleAPIRestTemplate restTemplate, final int page) {
try { try {
// first get courses from Moodle per page // first get courses from Moodle for page
final Map<String, CourseData> courseData = new HashMap<>(); final Map<String, CourseData> courseData = new HashMap<>();
final Collection<CourseData> coursesPage = getCoursesPage(restTemplate, page, 100); final Collection<CourseData> coursesPage = getCoursesPage(restTemplate, page, 100);
if (coursesPage.isEmpty()) { if (coursesPage.isEmpty()) {

View file

@ -90,12 +90,6 @@ public class MoodleLmsAPITemplate implements LmsAPITemplate {
.getOrElse(() -> getQuizzes(ids)); .getOrElse(() -> getQuizzes(ids));
} }
@Override
public Result<QuizData> getQuizFromCache(final String id) {
return this.moodleCourseAccess.getQuizFromCache(id)
.orElse(() -> getQuiz(id));
}
@Override @Override
public Result<Chapters> getCourseChapters(final String courseId) { public Result<Chapters> getCourseChapters(final String courseId) {
return Result.tryCatch(() -> this.moodleCourseAccess return Result.tryCatch(() -> this.moodleCourseAccess