diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java index f100b047..c6fb3825 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/bulkaction/impl/BulkActionServiceImpl.java @@ -87,6 +87,7 @@ public class BulkActionServiceImpl implements BulkActionService { @Override public void collectDependencies(final BulkAction action) { checkProcessing(action); + updateDependencyTypes(action); for (final BulkActionSupportDAO sup : this.supporter.values()) { action.dependencies.addAll(sup.getDependencies(action)); } @@ -107,6 +108,7 @@ public class BulkActionServiceImpl implements BulkActionService { throw new IllegalArgumentException("No bulk action support for: " + action); } + updateDependencyTypes(action); collectDependencies(action); if (!action.dependencies.isEmpty()) { @@ -286,8 +288,15 @@ public class BulkActionServiceImpl implements BulkActionService { } private void checkProcessing(final BulkAction action) { + if (action.alreadyProcessed) { + throw new IllegalStateException("Given BulkAction has already been processed. Use a new one"); + } + + } + + private void updateDependencyTypes(final BulkAction action) { // complete this.directDependancyMap if needed - if (action.includeDependencies != null) { + if (action.includeDependencies != null && !action.includeDependencies.isEmpty()) { this.directDependancyMap.entrySet().stream() .forEach(entry -> { if (action.includeDependencies.contains(entry.getKey())) { @@ -295,9 +304,6 @@ public class BulkActionServiceImpl implements BulkActionService { } }); } - if (action.alreadyProcessed) { - throw new IllegalStateException("Given BulkAction has already been processed. Use a new one"); - } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index 76cbb47c..b92f3dbf 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -59,6 +59,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler; 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.impl.moodle.MoodleCourseAccess; @Lazy @@ -791,9 +792,7 @@ public class ExamDAOImpl implements ExamDAO { // get and map quizzes final Map quizzes = this.lmsAPIService .getLmsAPITemplate(lmsSetupId) - .map(template -> (cached) - ? template.getQuizzesFromCache(recordMapping.keySet()) - : template.getQuizzes(recordMapping.keySet())) + .map(template -> getQuizzesFromLMS(template, recordMapping.keySet(), cached)) .getOrThrow() .stream() .flatMap(Result::skipOnError) @@ -814,6 +813,18 @@ public class ExamDAOImpl implements ExamDAO { }); } + private Collection> getQuizzesFromLMS(final LmsAPITemplate template, final Set ids, + final boolean cached) { + try { + return (cached) + ? template.getQuizzesFromCache(ids) + : template.getQuizzes(ids); + } catch (final Exception e) { + log.error("Unexpected error while using LmsAPITemplate to get quizzes: ", e); + return Collections.emptyList(); + } + } + private QuizData getQuizData( final Map quizzes, final String externalId, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/LmsAPIService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/LmsAPIService.java index 60a81539..468e424a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/LmsAPIService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/LmsAPIService.java @@ -147,11 +147,23 @@ public interface LmsAPIService { return new Page<>(0, 1, sortAttribute, Collections.emptyList()); } - final int start = (pageNumber - 1) * pageSize; + int start = (pageNumber - 1) * pageSize; int end = start + pageSize; if (end > quizzes.size()) { end = quizzes.size(); } + if (start >= end) { + start = end - pageSize; + if (start < 0) { + start = 0; + } + + return new Page<>( + (quizzes.size() <= pageSize) ? 1 : quizzes.size() / pageSize + 1, + start / pageSize + 1, + sortAttribute, + quizzes.subList(start, end)); + } return new Page<>( (quizzes.size() <= pageSize) ? 1 : quizzes.size() / pageSize + 1, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java index c1c621cf..9b2d7298 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseAccess.java @@ -273,6 +273,7 @@ public class MoodleCourseAccess extends CourseAccess { } else if (this.moodleCourseDataAsyncLoader.isLongRunningTask()) { // on long running tasks if we have a different fromCutTime as before // kick off the lazy loading task immediately with the new time filter + courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData(); if (fromCutTime > 0 && fromCutTime != this.moodleCourseDataAsyncLoader.getFromCutTime()) { this.moodleCourseDataAsyncLoader.setFromCutTime(fromCutTime); this.moodleCourseDataAsyncLoader.loadAsync(restTemplate); @@ -281,7 +282,7 @@ public class MoodleCourseAccess extends CourseAccess { * Constants.MINUTE_IN_MILLIS) { this.moodleCourseDataAsyncLoader.loadAsync(restTemplate); } - courseQuizData = this.moodleCourseDataAsyncLoader.getCachedCourseData(); + } else { // just run the task in sync if (fromCutTime >= 0) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseDataAsyncLoader.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseDataAsyncLoader.java index db02a797..be7e510b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseDataAsyncLoader.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/moodle/MoodleCourseDataAsyncLoader.java @@ -64,6 +64,7 @@ public class MoodleCourseDataAsyncLoader { private final int pageSize; private final Set cachedCourseData = new HashSet<>(); + private final Set newIds = new HashSet<>(); private String lmsSetup = Constants.EMPTY_NOTE; private long lastRunTime = 0; @@ -132,7 +133,7 @@ public class MoodleCourseDataAsyncLoader { } public boolean isLongRunningTask() { - return this.lastLoadTime > 30 * Constants.SECOND_IN_MILLIS; + return this.lastLoadTime > 3 * Constants.SECOND_IN_MILLIS; } public Set loadSync(final MoodleAPIRestTemplate restTemplate) { @@ -167,10 +168,12 @@ public class MoodleCourseDataAsyncLoader { private Runnable loadAndCache(final MoodleAPIRestTemplate restTemplate) { return () -> { - this.cachedCourseData.clear(); + //this.cachedCourseData.clear(); + this.newIds.clear(); final long startTime = Utils.getMillisecondsNow(); loadAllQuizzes(restTemplate); + syncCache(); this.lastLoadTime = Utils.getMillisecondsNow() - startTime; this.running = false; @@ -259,6 +262,7 @@ public class MoodleCourseDataAsyncLoader { c); } else { this.cachedCourseData.add(c); + this.newIds.add(c.id); } }); @@ -453,6 +457,20 @@ public class MoodleCourseDataAsyncLoader { }; } + private void syncCache() { + if (!this.cachedCourseData.isEmpty()) { + final Set newData = this.cachedCourseData.stream() + .filter(data -> this.newIds.contains(data.id)) + .collect(Collectors.toSet()); + + synchronized (this.cachedCourseData) { + this.cachedCourseData.clear(); + this.cachedCourseData.addAll(newData); + } + } + this.newIds.clear(); + } + @JsonIgnoreProperties(ignoreUnknown = true) static final class CoursePage { final Collection courseKeys;