From 2c9941e42103d7cdfddf9df5c119d488282cacbb Mon Sep 17 00:00:00 2001 From: Daniel Gerhardt <code@dgerhardt.net> Date: Tue, 2 Jun 2015 22:36:22 +0200 Subject: [PATCH] Introduce architechture for pagination --- .../java/de/thm/arsnova/aop/RangeAspect.java | 67 +++++++++++++++++++ .../AudienceQuestionController.java | 6 +- .../LecturerQuestionController.java | 23 ++++--- .../controller/PaginationController.java | 28 ++++++++ .../arsnova/controller/SessionController.java | 13 ++-- .../java/de/thm/arsnova/dao/CouchDBDao.java | 38 +++++------ .../java/de/thm/arsnova/dao/IDatabaseDao.java | 30 ++++----- .../arsnova/services/IQuestionService.java | 13 ++-- .../thm/arsnova/services/ISessionService.java | 8 +-- .../thm/arsnova/services/QuestionService.java | 43 ++++++------ .../thm/arsnova/services/SessionService.java | 16 ++--- .../java/de/thm/arsnova/web/Pagination.java | 31 +++++++++ .../webapp/WEB-INF/spring/arsnova-servlet.xml | 6 +- .../de/thm/arsnova/dao/StubDatabaseDao.java | 30 ++++----- .../arsnova/services/QuestionServiceTest.java | 4 +- 15 files changed, 247 insertions(+), 109 deletions(-) create mode 100644 src/main/java/de/thm/arsnova/aop/RangeAspect.java create mode 100644 src/main/java/de/thm/arsnova/controller/PaginationController.java create mode 100644 src/main/java/de/thm/arsnova/web/Pagination.java diff --git a/src/main/java/de/thm/arsnova/aop/RangeAspect.java b/src/main/java/de/thm/arsnova/aop/RangeAspect.java new file mode 100644 index 000000000..3ab757f68 --- /dev/null +++ b/src/main/java/de/thm/arsnova/aop/RangeAspect.java @@ -0,0 +1,67 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.aop; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; + +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import de.thm.arsnova.controller.PaginationController; + +@Component +@Aspect +@Profile("!test") +public class RangeAspect { + @Autowired + private HttpServletRequest request; + + private final Pattern rangePattern = Pattern.compile("^items=([0-9]+)-([0-9]+)?$"); + + private static final Logger logger = LoggerFactory.getLogger(RangeAspect.class); + + /** Sets start and end parameters based on range header + * + * @param controller + */ + @Before("execution(* de.thm.arsnova.controller.*.*(..)) && this(controller) && @annotation(de.thm.arsnova.web.Pagination)") + public void parsePaginationRange(final PaginationController controller) { + String rangeHeader = request.getHeader("Range"); + Matcher matcher = null; + if (rangeHeader != null) { + matcher = rangePattern.matcher(rangeHeader); + } + + if (matcher != null && matcher.matches()) { + int start = matcher.group(1) != null ? Integer.valueOf(matcher.group(1)) : -1; + int end = matcher.group(2) != null ? Integer.valueOf(matcher.group(2)) : -1; + logger.debug("Pagination: {}-{}", start, end); + controller.setRange(start, end); + } else { + controller.setRange(-1, -1); + } + } +} diff --git a/src/main/java/de/thm/arsnova/controller/AudienceQuestionController.java b/src/main/java/de/thm/arsnova/controller/AudienceQuestionController.java index 2202338ca..660c45381 100644 --- a/src/main/java/de/thm/arsnova/controller/AudienceQuestionController.java +++ b/src/main/java/de/thm/arsnova/controller/AudienceQuestionController.java @@ -36,13 +36,14 @@ import de.thm.arsnova.entities.transport.InterposedQuestion; import de.thm.arsnova.exceptions.BadRequestException; import de.thm.arsnova.services.IQuestionService; import de.thm.arsnova.web.DeprecatedApi; +import de.thm.arsnova.web.Pagination; /** * Handles requests related to audience questions, which are also called interposed or feedback questions. */ @RestController @RequestMapping("/audiencequestion") -public class AudienceQuestionController extends AbstractController { +public class AudienceQuestionController extends PaginationController { public static final Logger LOGGER = LoggerFactory.getLogger(AudienceQuestionController.class); @@ -62,8 +63,9 @@ public class AudienceQuestionController extends AbstractController { } @RequestMapping(value = "/", method = RequestMethod.GET) + @Pagination public List<InterposedQuestion> getInterposedQuestions(@RequestParam final String sessionkey) { - return InterposedQuestion.fromList(questionService.getInterposedQuestions(sessionkey)); + return InterposedQuestion.fromList(questionService.getInterposedQuestions(sessionkey, offset, limit)); } @RequestMapping(value = "/{questionId}", method = RequestMethod.GET) diff --git a/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java b/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java index 59df5aaa8..8f4735080 100644 --- a/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java +++ b/src/main/java/de/thm/arsnova/controller/LecturerQuestionController.java @@ -43,13 +43,14 @@ import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NotFoundException; import de.thm.arsnova.services.IQuestionService; import de.thm.arsnova.web.DeprecatedApi; +import de.thm.arsnova.web.Pagination; /** * Handles requests related to questions teachers are asking their students. */ @RestController @RequestMapping("/lecturerquestion") -public class LecturerQuestionController extends AbstractController { +public class LecturerQuestionController extends PaginationController { public static final Logger LOGGER = LoggerFactory.getLogger(LecturerQuestionController.class); @@ -143,10 +144,10 @@ public class LecturerQuestionController extends AbstractController { } if (lectureQuestionsOnly) { - questions = questionService.getLectureQuestions(sessionkey); + questions = questionService.getLectureQuestions(sessionkey, -1, -1); questionService.setVotingAdmissions(sessionkey, disable, questions); } else if (preparationQuestionsOnly) { - questions = questionService.getPreparationQuestions(sessionkey); + questions = questionService.getPreparationQuestions(sessionkey, -1, -1); questionService.setVotingAdmissions(sessionkey, disable, questions); } else { questionService.setVotingAdmissionForAllQuestions(sessionkey, disable); @@ -180,10 +181,10 @@ public class LecturerQuestionController extends AbstractController { } if (lectureQuestionsOnly) { - questions = questionService.getLectureQuestions(sessionkey); + questions = questionService.getLectureQuestions(sessionkey, -1, -1); questionService.publishQuestions(sessionkey, publish, questions); } else if (preparationQuestionsOnly) { - questions = questionService.getPreparationQuestions(sessionkey); + questions = questionService.getPreparationQuestions(sessionkey, -1, -1); questionService.publishQuestions(sessionkey, publish, questions); } else { questionService.publishAll(sessionkey, p); @@ -215,6 +216,7 @@ public class LecturerQuestionController extends AbstractController { } @RequestMapping(value = "/", method = RequestMethod.GET) + @Pagination public List<Question> getSkillQuestions( @RequestParam final String sessionkey, @RequestParam(value = "lecturequestionsonly", defaultValue = "false") final boolean lectureQuestionsOnly, @@ -224,13 +226,13 @@ public class LecturerQuestionController extends AbstractController { ) { List<Question> questions; if (lectureQuestionsOnly) { - questions = questionService.getLectureQuestions(sessionkey); + questions = questionService.getLectureQuestions(sessionkey, offset, limit); } else if (flashcardsOnly) { - questions = questionService.getFlashcards(sessionkey); + questions = questionService.getFlashcards(sessionkey, offset, limit); } else if (preparationQuestionsOnly) { - questions = questionService.getPreparationQuestions(sessionkey); + questions = questionService.getPreparationQuestions(sessionkey, offset, limit); } else { - questions = questionService.getSkillQuestions(sessionkey); + questions = questionService.getSkillQuestions(sessionkey, offset, limit); } if (questions == null || questions.isEmpty()) { response.setStatus(HttpStatus.NO_CONTENT.value()); @@ -484,8 +486,9 @@ public class LecturerQuestionController extends AbstractController { } @RequestMapping(value = "/{questionId}/freetextanswer/", method = RequestMethod.GET) + @Pagination public List<Answer> getFreetextAnswers(@PathVariable final String questionId) { - return questionService.getFreetextAnswers(questionId); + return questionService.getFreetextAnswers(questionId, offset, limit); } @DeprecatedApi diff --git a/src/main/java/de/thm/arsnova/controller/PaginationController.java b/src/main/java/de/thm/arsnova/controller/PaginationController.java new file mode 100644 index 000000000..9b1c7db09 --- /dev/null +++ b/src/main/java/de/thm/arsnova/controller/PaginationController.java @@ -0,0 +1,28 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.controller; + +public class PaginationController extends AbstractController { + protected int offset = -1; + protected int limit = -1; + + public void setRange(int start, int end) { + this.offset = start; + this.limit = end != -1 && start <= end ? end - start + 1 : -1; + } +} diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java index 4a75665e8..3ef4c0363 100644 --- a/src/main/java/de/thm/arsnova/controller/SessionController.java +++ b/src/main/java/de/thm/arsnova/controller/SessionController.java @@ -50,13 +50,14 @@ import de.thm.arsnova.services.SessionService.SessionInfoShortNameComparator; import de.thm.arsnova.services.SessionService.SessionNameComparator; import de.thm.arsnova.services.SessionService.SessionShortNameComparator; import de.thm.arsnova.web.DeprecatedApi; +import de.thm.arsnova.web.Pagination; /** * Handles requests related to ARSnova sessions. */ @RestController @RequestMapping("/session") -public class SessionController extends AbstractController { +public class SessionController extends PaginationController { public static final Logger LOGGER = LoggerFactory.getLogger(SessionController.class); @@ -117,6 +118,7 @@ public class SessionController extends AbstractController { } @RequestMapping(value = "/", method = RequestMethod.GET) + @Pagination public List<Session> getSessions( @RequestParam(value = "ownedonly", defaultValue = "false") final boolean ownedOnly, @RequestParam(value = "visitedonly", defaultValue = "false") final boolean visitedOnly, @@ -128,9 +130,9 @@ public class SessionController extends AbstractController { /* TODO implement all parameter combinations, implement use of user parameter */ try { if (ownedOnly && !visitedOnly) { - sessions = sessionService.getMySessions(); + sessions = sessionService.getMySessions(offset, limit); } else if (visitedOnly && !ownedOnly) { - sessions = sessionService.getMyVisitedSessions(); + sessions = sessionService.getMyVisitedSessions(offset, limit); } else { response.setStatus(HttpStatus.NOT_IMPLEMENTED.value()); return null; @@ -160,6 +162,7 @@ public class SessionController extends AbstractController { * @return */ @RequestMapping(value = "/", method = RequestMethod.GET, params = "statusonly=true") + @Pagination public List<SessionInfo> getMySessions( @RequestParam(value = "visitedonly", defaultValue = "false") final boolean visitedOnly, @RequestParam(value = "sortby", defaultValue = "name") final String sortby, @@ -167,9 +170,9 @@ public class SessionController extends AbstractController { ) { List<SessionInfo> sessions; if (!visitedOnly) { - sessions = sessionService.getMySessionsInfo(); + sessions = sessionService.getMySessionsInfo(offset, limit); } else { - sessions = sessionService.getMyVisitedSessionsInfo(); + sessions = sessionService.getMyVisitedSessionsInfo(offset, limit); } if (sessions == null || sessions.isEmpty()) { diff --git a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java index fe956fbcf..7f739dfee 100644 --- a/src/main/java/de/thm/arsnova/dao/CouchDBDao.java +++ b/src/main/java/de/thm/arsnova/dao/CouchDBDao.java @@ -152,7 +152,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<Session> getMySessions(final User user) { + public List<Session> getMySessions(final User user, final int start, final int limit) { final NovaView view = new NovaView("session/by_creator"); view.setStartKeyArray(user.getUsername()); view.setEndKeyArray(user.getUsername(), "{}"); @@ -227,8 +227,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<SessionInfo> getMySessionsInfo(final User user) { - final List<Session> sessions = this.getMySessions(user); + public List<SessionInfo> getMySessionsInfo(final User user, final int start, final int limit) { + final List<Session> sessions = this.getMySessions(user, start, limit); if (sessions.isEmpty()) { return new ArrayList<SessionInfo>(); } @@ -404,14 +404,14 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @Cacheable("skillquestions") @Override - public List<Question> getSkillQuestionsForUsers(final Session session) { + public List<Question> getSkillQuestionsForUsers(final Session session, final int start, final int limit) { String viewName = "skill_question/by_session_for_all_full"; return getQuestions(new NovaView(viewName), session); } @Cacheable("skillquestions") @Override - public List<Question> getSkillQuestionsForTeachers(final Session session) { + public List<Question> getSkillQuestionsForTeachers(final Session session, final int start, final int limit) { String viewName = "skill_question/by_session_sorted_by_subject_and_text"; return getQuestions(new NovaView(viewName), session); } @@ -1010,7 +1010,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<Answer> getFreetextAnswers(final String questionId) { + public List<Answer> getFreetextAnswers(final String questionId, final int start, final int limit) { final List<Answer> answers = new ArrayList<Answer>(); final NovaView view = new NovaView("skill_question/freetext_answers_full"); view.setKey(questionId); @@ -1142,7 +1142,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<InterposedQuestion> getInterposedQuestions(final Session session) { + public List<InterposedQuestion> getInterposedQuestions(final Session session, final int start, final int limit) { final NovaView view = new NovaView("interposed_question/by_session_full"); view.setKey(session.get_id()); final ViewResults questions = getDatabase().view(view); @@ -1153,7 +1153,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<InterposedQuestion> getInterposedQuestions(final Session session, final User user) { + public List<InterposedQuestion> getInterposedQuestions(final Session session, final User user, final int start, final int limit) { final NovaView view = new NovaView("interposed_question/by_session_and_creator"); view.setKey(session.get_id(), user.getUsername()); final ViewResults questions = getDatabase().view(view); @@ -1276,7 +1276,7 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<Session> getMyVisitedSessions(final User user) { + public List<Session> getMyVisitedSessions(final User user, final int start, final int limit) { final NovaView view = new NovaView("logged_in/visited_sessions_by_user"); view.setKey(user.getUsername()); final ViewResults sessions = getDatabase().view(view); @@ -1336,8 +1336,8 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware } @Override - public List<SessionInfo> getMyVisitedSessionsInfo(final User user) { - List<Session> sessions = this.getMyVisitedSessions(user); + public List<SessionInfo> getMyVisitedSessionsInfo(final User user, final int start, final int limit) { + List<Session> sessions = this.getMyVisitedSessions(user, start, limit); if (sessions.isEmpty()) { return new ArrayList<SessionInfo>(); } @@ -1519,39 +1519,39 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware @Cacheable("lecturequestions") @Override - public List<Question> getLectureQuestionsForUsers(final Session session) { + public List<Question> getLectureQuestionsForUsers(final Session session, final int start, final int limit) { String viewName = "skill_question/lecture_question_by_session_for_all"; return getQuestions(new NovaView(viewName), session); } @Override - public List<Question> getLectureQuestionsForTeachers(final Session session) { + public List<Question> getLectureQuestionsForTeachers(final Session session, final int start, final int limit) { String viewName = "skill_question/lecture_question_by_session"; return getQuestions(new NovaView(viewName), session); } @Cacheable("flashcardquestions") @Override - public List<Question> getFlashcardsForUsers(final Session session) { + public List<Question> getFlashcardsForUsers(final Session session, final int start, final int limit) { String viewName = "skill_question/flashcard_by_session_for_all"; return getQuestions(new NovaView(viewName), session); } @Override - public List<Question> getFlashcardsForTeachers(final Session session) { + public List<Question> getFlashcardsForTeachers(final Session session, final int start, final int limit) { String viewName = "skill_question/flashcard_by_session"; return getQuestions(new NovaView(viewName), session); } @Cacheable("preparationquestions") @Override - public List<Question> getPreparationQuestionsForUsers(final Session session) { + public List<Question> getPreparationQuestionsForUsers(final Session session, final int start, final int limit) { String viewName = "skill_question/preparation_question_by_session_for_all"; return getQuestions(new NovaView(viewName), session); } @Override - public List<Question> getPreparationQuestionsForTeachers(final Session session) { + public List<Question> getPreparationQuestionsForTeachers(final Session session, final int start, final int limit) { String viewName = "skill_question/preparation_question_by_session"; return getQuestions(new NovaView(viewName), session); } @@ -1672,14 +1672,14 @@ public class CouchDBDao implements IDatabaseDao, ApplicationEventPublisherAware public List<String> getUnAnsweredLectureQuestionIds(final Session session, final User user) { final NovaView view = new NovaView("answer/variant_by_user_and_piround"); view.setKey(user.getUsername(), session.get_id(), "lecture"); - return collectUnansweredQuestionIdsByPiRound(getDatabaseDao().getLectureQuestionsForUsers(session), view); + return collectUnansweredQuestionIdsByPiRound(getDatabaseDao().getLectureQuestionsForUsers(session, -1, -1), view); } @Override public List<String> getUnAnsweredPreparationQuestionIds(final Session session, final User user) { final NovaView view = new NovaView("answer/variant_by_user_and_piround"); view.setKey(user.getUsername(), session.get_id(), "preparation"); - return collectUnansweredQuestionIdsByPiRound(getDatabaseDao().getPreparationQuestionsForUsers(session), view); + return collectUnansweredQuestionIdsByPiRound(getDatabaseDao().getPreparationQuestionsForUsers(session, -1, -1), view); } private List<String> collectUnansweredQuestionIds( diff --git a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java index f910ecbba..407d08124 100644 --- a/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java +++ b/src/main/java/de/thm/arsnova/dao/IDatabaseDao.java @@ -40,7 +40,7 @@ import de.thm.arsnova.entities.transport.ImportExportSession; public interface IDatabaseDao { Session getSessionFromKeyword(String keyword); - List<Session> getMySessions(User user); + List<Session> getMySessions(User user, final int start, final int limit); List<Session> getPublicPoolSessions(); @@ -65,9 +65,9 @@ public interface IDatabaseDao { @Deprecated List<Question> getSkillQuestions(User user, Session session); - List<Question> getSkillQuestionsForUsers(Session session); + List<Question> getSkillQuestionsForUsers(Session session, final int start, final int limit); - List<Question> getSkillQuestionsForTeachers(Session session); + List<Question> getSkillQuestionsForTeachers(Session session, final int start, final int limit); int getSkillQuestionCount(Session session); @@ -97,7 +97,7 @@ public interface IDatabaseDao { int getAbstentionAnswerCount(String questionId); - List<Answer> getFreetextAnswers(String questionId); + List<Answer> getFreetextAnswers(String questionId, final int start, final int limit); List<Answer> getMyAnswers(User me, Session session); @@ -109,15 +109,15 @@ public interface IDatabaseDao { InterposedReadingCount getInterposedReadingCount(Session session, User user); - List<InterposedQuestion> getInterposedQuestions(Session session); + List<InterposedQuestion> getInterposedQuestions(Session session, final int start, final int limit); - List<InterposedQuestion> getInterposedQuestions(Session session, User user); + List<InterposedQuestion> getInterposedQuestions(Session session, User user, final int start, final int limit); InterposedQuestion getInterposedQuestion(String questionId); void markInterposedQuestionAsRead(InterposedQuestion question); - List<Session> getMyVisitedSessions(User user); + List<Session> getMyVisitedSessions(User user, final int start, final int limit); Question updateQuestion(Question question); @@ -139,17 +139,17 @@ public interface IDatabaseDao { void deleteSession(Session session); - List<Question> getLectureQuestionsForUsers(Session session); + List<Question> getLectureQuestionsForUsers(Session session, final int start, final int limit); - List<Question> getLectureQuestionsForTeachers(Session session); + List<Question> getLectureQuestionsForTeachers(Session session, final int start, final int limit); - List<Question> getFlashcardsForUsers(Session session); + List<Question> getFlashcardsForUsers(Session session, final int start, final int limit); - List<Question> getFlashcardsForTeachers(Session session); + List<Question> getFlashcardsForTeachers(Session session, final int start, final int limit); - List<Question> getPreparationQuestionsForUsers(Session session); + List<Question> getPreparationQuestionsForUsers(Session session, final int start, final int limit); - List<Question> getPreparationQuestionsForTeachers(Session session); + List<Question> getPreparationQuestionsForTeachers(Session session, final int start, final int limit); int getLectureQuestionCount(Session session); @@ -189,13 +189,13 @@ public interface IDatabaseDao { CourseScore getLearningProgress(Session session); - List<SessionInfo> getMySessionsInfo(User user); + List<SessionInfo> getMySessionsInfo(User user, final int start, final int limit); List<SessionInfo> getPublicPoolSessionsInfo(); List<SessionInfo> getMyPublicPoolSessionsInfo(final User user); - List<SessionInfo> getMyVisitedSessionsInfo(User currentUser); + List<SessionInfo> getMyVisitedSessionsInfo(User currentUser, final int start, final int limit); void deleteAllPreparationAnswers(Session session); diff --git a/src/main/java/de/thm/arsnova/services/IQuestionService.java b/src/main/java/de/thm/arsnova/services/IQuestionService.java index a21d84244..ce28fdb87 100644 --- a/src/main/java/de/thm/arsnova/services/IQuestionService.java +++ b/src/main/java/de/thm/arsnova/services/IQuestionService.java @@ -37,7 +37,7 @@ public interface IQuestionService { Question getQuestion(String id); - List<Question> getSkillQuestions(String sessionkey); + List<Question> getSkillQuestions(String sessionkey, int offset, int limit); int getSkillQuestionCount(String sessionkey); @@ -71,7 +71,8 @@ public interface IQuestionService { int getAnswerCount(String questionId, int piRound); - List<Answer> getFreetextAnswers(String questionId); + List<Answer> getFreetextAnswers(String questionId, int offset, int limit); + List<Answer> getMyAnswers(String sessionKey); @@ -83,7 +84,7 @@ public interface IQuestionService { InterposedReadingCount getInterposedReadingCount(String sessionKey, String username); - List<InterposedQuestion> getInterposedQuestions(String sessionKey); + List<InterposedQuestion> getInterposedQuestions(String sessionKey, int offset, int limit); InterposedQuestion readInterposedQuestion(String questionId); @@ -103,11 +104,11 @@ public interface IQuestionService { void deleteInterposedQuestion(String questionId); - List<Question> getLectureQuestions(String sessionkey); + List<Question> getLectureQuestions(String sessionkey, int offset, int limit); - List<Question> getFlashcards(String sessionkey); + List<Question> getFlashcards(String sessionkey, int offset, int limit); - List<Question> getPreparationQuestions(String sessionkey); + List<Question> getPreparationQuestions(String sessionkey, int offset, int limit); int getLectureQuestionCount(String sessionkey); diff --git a/src/main/java/de/thm/arsnova/services/ISessionService.java b/src/main/java/de/thm/arsnova/services/ISessionService.java index ab4a395af..22ccbf90b 100644 --- a/src/main/java/de/thm/arsnova/services/ISessionService.java +++ b/src/main/java/de/thm/arsnova/services/ISessionService.java @@ -42,9 +42,9 @@ public interface ISessionService { String generateKeyword(); - List<Session> getMySessions(); + List<Session> getMySessions(int offset, int limit); - List<Session> getMyVisitedSessions(); + List<Session> getMyVisitedSessions(int offset, int limit); int countSessions(List<Course> courses); @@ -64,13 +64,13 @@ public interface ISessionService { LearningProgressValues getMyLearningProgress(String sessionkey, String progressType, String questionVariant); - List<SessionInfo> getMySessionsInfo(); + List<SessionInfo> getMySessionsInfo(int offset, int limit); List<SessionInfo> getPublicPoolSessionsInfo(); List<SessionInfo> getMyPublicPoolSessionsInfo(); - List<SessionInfo> getMyVisitedSessionsInfo(); + List<SessionInfo> getMyVisitedSessionsInfo(int offset, int limit); SessionInfo importSession(ImportExportSession session); diff --git a/src/main/java/de/thm/arsnova/services/QuestionService.java b/src/main/java/de/thm/arsnova/services/QuestionService.java index 5edb106f5..1158f57c6 100644 --- a/src/main/java/de/thm/arsnova/services/QuestionService.java +++ b/src/main/java/de/thm/arsnova/services/QuestionService.java @@ -27,7 +27,6 @@ import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -104,13 +103,13 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public List<Question> getSkillQuestions(final String sessionkey) { + public List<Question> getSkillQuestions(final String sessionkey, final int offset, final int limit) { final Session session = getSession(sessionkey); final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getSkillQuestionsForTeachers(session); + return databaseDao.getSkillQuestionsForTeachers(session, offset, limit); } else { - return databaseDao.getSkillQuestionsForUsers(session); + return databaseDao.getSkillQuestionsForUsers(session, offset, limit); } } @@ -486,7 +485,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis throw new NotFoundException(); } return "freetext".equals(question.getQuestionType()) - ? getFreetextAnswers(questionId) + ? getFreetextAnswers(questionId, -1, -1) : databaseDao.getAnswers(question, piRound); } @@ -498,7 +497,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis throw new NotFoundException(); } if ("freetext".equals(question.getQuestionType())) { - return getFreetextAnswers(questionId); + return getFreetextAnswers(questionId, -1, -1); } else { return databaseDao.getAnswers(question); } @@ -512,7 +511,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis throw new NotFoundException(); } if ("freetext".equals(question.getQuestionType())) { - return getFreetextAnswers(questionId); + return getFreetextAnswers(questionId, -1, -1); } else { return databaseDao.getAllAnswers(question); } @@ -564,8 +563,8 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public List<Answer> getFreetextAnswers(final String questionId) { - final List<Answer> answers = databaseDao.getFreetextAnswers(questionId); + public List<Answer> getFreetextAnswers(final String questionId, final int offset, final int limit) { + final List<Answer> answers = databaseDao.getFreetextAnswers(questionId, offset, limit); if (answers == null) { throw new NotFoundException(); } @@ -582,7 +581,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis public List<Answer> getMyAnswers(final String sessionKey) { final Session session = getSession(sessionKey); // Load questions first because we are only interested in answers of the latest piRound. - final List<Question> questions = databaseDao.getSkillQuestionsForUsers(session); + final List<Question> questions = databaseDao.getSkillQuestionsForUsers(session, -1, -1); final Map<String, Question> questionIdToQuestion = new HashMap<String, Question>(); for (final Question question : questions) { questionIdToQuestion.put(question.get_id(), question); @@ -644,13 +643,13 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public List<InterposedQuestion> getInterposedQuestions(final String sessionKey) { + public List<InterposedQuestion> getInterposedQuestions(final String sessionKey, final int offset, final int limit) { final Session session = this.getSession(sessionKey); final User user = getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getInterposedQuestions(session); + return databaseDao.getInterposedQuestions(session, offset, limit); } else { - return databaseDao.getInterposedQuestions(session, user); + return databaseDao.getInterposedQuestions(session, user, offset, limit); } } @@ -800,7 +799,7 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis @Override @PreAuthorize("isAuthenticated()") - public List<Question> getLectureQuestions(final String sessionkey) { + public List<Question> getLectureQuestions(final String sessionkey, final int offset, final int limit) { final Session session = getSession(sessionkey); SortOrder subjectSortOrder = databaseDao.getSortOrder(session.get_id(), "lecture", ""); if (subjectSortOrder == null) { @@ -811,27 +810,27 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis } final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getLectureQuestionsForTeachers(session); + return databaseDao.getLectureQuestionsForTeachers(session, offset, limit); } else { - return databaseDao.getLectureQuestionsForUsers(session); + return databaseDao.getLectureQuestionsForUsers(session, offset, limit); } } @Override @PreAuthorize("isAuthenticated()") - public List<Question> getFlashcards(final String sessionkey) { + public List<Question> getFlashcards(final String sessionkey, final int offset, final int limit) { final Session session = getSession(sessionkey); final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getFlashcardsForTeachers(session); + return databaseDao.getFlashcardsForTeachers(session, offset, limit); } else { - return databaseDao.getFlashcardsForUsers(session); + return databaseDao.getFlashcardsForUsers(session, offset, limit); } } @Override @PreAuthorize("isAuthenticated()") - public List<Question> getPreparationQuestions(final String sessionkey) { + public List<Question> getPreparationQuestions(final String sessionkey, final int offset, final int limit) { final Session session = getSession(sessionkey); SortOrder subjectSortOrder = databaseDao.getSortOrder(session.get_id(), "preparation", ""); if (subjectSortOrder == null) { @@ -842,9 +841,9 @@ public class QuestionService implements IQuestionService, ApplicationEventPublis } final User user = userService.getCurrentUser(); if (session.isCreator(user)) { - return databaseDao.getPreparationQuestionsForTeachers(session); + return databaseDao.getPreparationQuestionsForTeachers(session, offset, limit); } else { - return databaseDao.getPreparationQuestionsForUsers(session); + return databaseDao.getPreparationQuestionsForUsers(session, offset, limit); } } diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java index f9a49bf2f..b404910b3 100644 --- a/src/main/java/de/thm/arsnova/services/SessionService.java +++ b/src/main/java/de/thm/arsnova/services/SessionService.java @@ -187,8 +187,8 @@ public class SessionService implements ISessionService, ApplicationEventPublishe @Override @PreAuthorize("isAuthenticated()") - public List<Session> getMySessions() { - return databaseDao.getMySessions(userService.getCurrentUser()); + public List<Session> getMySessions(final int offset, final int limit) { + return databaseDao.getMySessions(userService.getCurrentUser(), offset, limit); } @Override @@ -205,21 +205,21 @@ public class SessionService implements ISessionService, ApplicationEventPublishe @Override @PreAuthorize("isAuthenticated()") - public List<SessionInfo> getMySessionsInfo() { + public List<SessionInfo> getMySessionsInfo(final int offset, final int limit) { final User user = userService.getCurrentUser(); - return databaseDao.getMySessionsInfo(user); + return databaseDao.getMySessionsInfo(user, offset, limit); } @Override @PreAuthorize("isAuthenticated()") - public List<Session> getMyVisitedSessions() { - return databaseDao.getMyVisitedSessions(userService.getCurrentUser()); + public List<Session> getMyVisitedSessions(final int offset, final int limit) { + return databaseDao.getMyVisitedSessions(userService.getCurrentUser(), offset, limit); } @Override @PreAuthorize("isAuthenticated()") - public List<SessionInfo> getMyVisitedSessionsInfo() { - return databaseDao.getMyVisitedSessionsInfo(userService.getCurrentUser()); + public List<SessionInfo> getMyVisitedSessionsInfo(final int offset, final int limit) { + return databaseDao.getMyVisitedSessionsInfo(userService.getCurrentUser(), offset, limit); } @Override diff --git a/src/main/java/de/thm/arsnova/web/Pagination.java b/src/main/java/de/thm/arsnova/web/Pagination.java new file mode 100644 index 000000000..e8f60df65 --- /dev/null +++ b/src/main/java/de/thm/arsnova/web/Pagination.java @@ -0,0 +1,31 @@ +/* + * This file is part of ARSnova Backend. + * Copyright (C) 2012-2015 The ARSnova Team + * + * ARSnova Backend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ARSnova Backend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package de.thm.arsnova.web; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@Documented +public @interface Pagination { + +} diff --git a/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml b/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml index 2375d536e..5e4bf336a 100644 --- a/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml +++ b/src/main/webapp/WEB-INF/spring/arsnova-servlet.xml @@ -1,17 +1,19 @@ <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" + http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd"> <!-- ARSnova Servlet Context --> - <context:component-scan base-package="de.thm.arsnova.controller,de.thm.arsnova.web" /> + <context:component-scan base-package="de.thm.arsnova.aop,de.thm.arsnova.controller,de.thm.arsnova.web" /> <mvc:annotation-driven content-negotiation-manager="mvcContentNegotiationManager" /> @@ -21,6 +23,8 @@ <bean class="de.thm.arsnova.web.DeprecatedApiInterceptorHandler" /> </mvc:interceptors> + <aop:aspectj-autoproxy /> + <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:ignoreUnresolvablePlaceholders="false" p:ignoreResourceNotFound="true"> diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index 32ec1204a..012593359 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -155,7 +155,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<Session> getMySessions(User user) { + public List<Session> getMySessions(User user, final int start, final int limit) { // TODO Auto-generated method stub return null; } @@ -209,7 +209,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<Answer> getFreetextAnswers(String questionId) { + public List<Answer> getFreetextAnswers(String questionId, final int start, final int limit) { // TODO Auto-generated method stub return null; } @@ -232,7 +232,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<InterposedQuestion> getInterposedQuestions(Session session) { + public List<InterposedQuestion> getInterposedQuestions(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @@ -254,7 +254,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<Session> getMyVisitedSessions(User user) { + public List<Session> getMyVisitedSessions(User user, final int start, final int limit) { // TODO Auto-generated method stub return null; } @@ -445,7 +445,7 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<InterposedQuestion> getInterposedQuestions(Session session, User user) { + public List<InterposedQuestion> getInterposedQuestions(Session session, User user, final int start, final int limit) { // TODO Auto-generated method stub return null; } @@ -463,13 +463,13 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<SessionInfo> getMySessionsInfo(User user) { + public List<SessionInfo> getMySessionsInfo(User user, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<SessionInfo> getMyVisitedSessionsInfo(User currentUser) { + public List<SessionInfo> getMyVisitedSessionsInfo(User currentUser, final int start, final int limit) { // TODO Auto-generated method stub return null; } @@ -499,49 +499,49 @@ public class StubDatabaseDao implements IDatabaseDao { } @Override - public List<Question> getSkillQuestionsForUsers(Session session) { + public List<Question> getSkillQuestionsForUsers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getSkillQuestionsForTeachers(Session session) { + public List<Question> getSkillQuestionsForTeachers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getLectureQuestionsForUsers(Session session) { + public List<Question> getLectureQuestionsForUsers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getLectureQuestionsForTeachers(Session session) { + public List<Question> getLectureQuestionsForTeachers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getFlashcardsForUsers(Session session) { + public List<Question> getFlashcardsForUsers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getFlashcardsForTeachers(Session session) { + public List<Question> getFlashcardsForTeachers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getPreparationQuestionsForUsers(Session session) { + public List<Question> getPreparationQuestionsForUsers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } @Override - public List<Question> getPreparationQuestionsForTeachers(Session session) { + public List<Question> getPreparationQuestionsForTeachers(Session session, final int start, final int limit) { // TODO Auto-generated method stub return null; } diff --git a/src/test/java/de/thm/arsnova/services/QuestionServiceTest.java b/src/test/java/de/thm/arsnova/services/QuestionServiceTest.java index a843bd113..b8d7c8082 100644 --- a/src/test/java/de/thm/arsnova/services/QuestionServiceTest.java +++ b/src/test/java/de/thm/arsnova/services/QuestionServiceTest.java @@ -86,13 +86,13 @@ public class QuestionServiceTest { @Test(expected = AuthenticationCredentialsNotFoundException.class) public void testShouldNotReturnQuestionsIfNotAuthenticated() { setAuthenticated(false, "nobody"); - questionService.getSkillQuestions("12345678"); + questionService.getSkillQuestions("12345678", -1, -1); } @Test(expected = NotFoundException.class) public void testShouldFindQuestionsForNonExistantSession() { setAuthenticated(true, "ptsr00"); - questionService.getSkillQuestions("00000000"); + questionService.getSkillQuestions("00000000", -1, -1); } @Test -- GitLab