Index: lams_common/src/java/org/lamsfoundation/lams/tool/service/ICommonScratchieService.java =================================================================== diff -u -r122ff0d8419be3fac72ddb842cbbce1cea01e542 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_common/src/java/org/lamsfoundation/lams/tool/service/ICommonScratchieService.java (.../ICommonScratchieService.java) (revision 122ff0d8419be3fac72ddb842cbbce1cea01e542) +++ lams_common/src/java/org/lamsfoundation/lams/tool/service/ICommonScratchieService.java (.../ICommonScratchieService.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -1,10 +1,5 @@ package org.lamsfoundation.lams.tool.service; public interface ICommonScratchieService { - - /** - * - */ - void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid); - -} + void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid, String answer); +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/tool/service/ILamsToolService.java =================================================================== diff -u -r122ff0d8419be3fac72ddb842cbbce1cea01e542 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_common/src/java/org/lamsfoundation/lams/tool/service/ILamsToolService.java (.../ILamsToolService.java) (revision 122ff0d8419be3fac72ddb842cbbce1cea01e542) +++ lams_common/src/java/org/lamsfoundation/lams/tool/service/ILamsToolService.java (.../ILamsToolService.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -226,11 +226,9 @@ Integer requestorUserId, Long requestorToolSessionId); /** - * Recalculate marks for all Scratchie activities that use specified QbQuestion. - * - * @param qbQuestionUid + * Recalculate marks for all Scratchie activities that use specified QbQuestion with given answer. */ - void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid); + void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid, String answer); /** * Get a count of all the users that would be returned by getUsersForActivity(Long toolSessionId); Index: lams_common/src/java/org/lamsfoundation/lams/tool/service/LamsToolService.java =================================================================== diff -u -re97dcb50701feb5f8cfd666de05caf9d0cd69bd6 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_common/src/java/org/lamsfoundation/lams/tool/service/LamsToolService.java (.../LamsToolService.java) (revision e97dcb50701feb5f8cfd666de05caf9d0cd69bd6) +++ lams_common/src/java/org/lamsfoundation/lams/tool/service/LamsToolService.java (.../LamsToolService.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -66,7 +66,6 @@ import org.lamsfoundation.lams.util.CommonConstants; import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.FileUtilException; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; /** * @author Jacky Fang @@ -238,7 +237,7 @@ // check if there is leaderSelectionTool available if (leaderSelectionActivity != null) { - User learner = (User) toolContentDAO.find(User.class, learnerId); + User learner = toolContentDAO.find(User.class, learnerId); String outputName = LamsToolService.LEADER_SELECTION_TOOL_OUTPUT_NAME_LEADER_USERID; ToolSession leaderSelectionSession = toolSessionDAO.getToolSessionByLearner(learner, leaderSelectionActivity); @@ -277,7 +276,7 @@ public Set getLeaderUserId(Long leaderSelectionActivityId) { Activity activity = activityDAO.getActivityByActivityId(leaderSelectionActivityId); List toolSessions = toolSessionDAO.getToolSessionByActivity(activity); - Set result = new TreeSet(); + Set result = new TreeSet<>(); for (ToolSession toolSession : toolSessions) { ToolOutput output = lamsCoreToolService.getOutputFromTool(LEADER_SELECTION_TOOL_OUTPUT_NAME_LEADER_USERID, toolSession, null); @@ -371,10 +370,10 @@ return null; } - Set confidenceProvidingActivityIds = new LinkedHashSet(); + Set confidenceProvidingActivityIds = new LinkedHashSet<>(); findPrecedingAssessmentAndMcqActivities(specifiedActivity, confidenceProvidingActivityIds, true); - Set confidenceProvidingActivities = new LinkedHashSet(); + Set confidenceProvidingActivities = new LinkedHashSet<>(); for (Long confidenceProvidingActivityId : confidenceProvidingActivityIds) { ToolActivity confidenceProvidingActivity = (ToolActivity) activityDAO .getActivityByActivityId(confidenceProvidingActivityId, ToolActivity.class); @@ -389,8 +388,8 @@ * them). Please note, it does not check whether enableConfidenceLevels advanced option is ON in those activities. */ @SuppressWarnings("rawtypes") - private void findPrecedingAssessmentAndMcqActivities(Activity activity, - Set confidenceProvidingActivityIds, boolean isMcqIncluded) { + private void findPrecedingAssessmentAndMcqActivities(Activity activity, Set confidenceProvidingActivityIds, + boolean isMcqIncluded) { // check if current activity is Leader Select one. if so - stop searching and return it. Class activityClass = Hibernate.getClass(activity); if (activityClass.equals(ToolActivity.class)) { @@ -442,7 +441,7 @@ return; } } - + @Override public Set getActivitiesProvidingVsaAnswers(Long toolContentId) { ToolActivity specifiedActivity = activityDAO.getToolActivityByToolContentId(toolContentId); @@ -452,10 +451,10 @@ return null; } - Set providingVsaAnswersActivityIds = new LinkedHashSet(); + Set providingVsaAnswersActivityIds = new LinkedHashSet<>(); findPrecedingAssessmentAndMcqActivities(specifiedActivity, providingVsaAnswersActivityIds, false); - Set activitiesProvidingVsaAnswers = new LinkedHashSet(); + Set activitiesProvidingVsaAnswers = new LinkedHashSet<>(); for (Long confidenceProvidingActivityId : providingVsaAnswersActivityIds) { ToolActivity activityProvidingVsaAnswers = (ToolActivity) activityDAO .getActivityByActivityId(confidenceProvidingActivityId, ToolActivity.class); @@ -468,7 +467,7 @@ @Override public List getConfidenceLevelsByActivity(Integer confidenceLevelActivityUiid, Integer requestorUserId, Long requestorToolSessionId) { - User user = (User) activityDAO.find(User.class, requestorUserId); + User user = activityDAO.find(User.class, requestorUserId); if (user == null) { throw new ToolException("No user found for userId=" + requestorUserId); } @@ -494,11 +493,11 @@ .getConfidenceLevelsByToolSession(confidenceLevelSession); return confidenceLevelDtos; } - + @Override public Collection getVsaAnswersFromAssessment(Integer activityUiidProvidingVsaAnswers, Integer requestorUserId, Long requestorToolSessionId) { - User user = (User) activityDAO.find(User.class, requestorUserId); + User user = activityDAO.find(User.class, requestorUserId); if (user == null) { throw new ToolException("No user found for userId=" + requestorUserId); } @@ -513,13 +512,13 @@ ToolSession assessmentSession = toolSessionDAO.getToolSessionByLearner(user, activityProvidingVsaAnswers); return lamsCoreToolService.getVsaAnswersByToolSession(assessmentSession); } - + @Override - public void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid) { + public void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid, String answer) { Tool scratchieTool = toolDAO.getToolBySignature(CommonConstants.TOOL_SIGNATURE_SCRATCHIE); ICommonScratchieService sessionManager = (ICommonScratchieService) lamsCoreToolService .findToolService(scratchieTool); - sessionManager.recalculateScratchieMarksForVsaQuestion(qbQuestionUid); + sessionManager.recalculateScratchieMarksForVsaQuestion(qbQuestionUid, answer); } @Override Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -rd295cb9148c3c8cbe2e98de79ae41f7eba704fe9 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision d295cb9148c3c8cbe2e98de79ae41f7eba704fe9) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -1559,7 +1559,7 @@ } //recalculate marks in all Scratchie activities, that use modified QbQuestion - toolService.recalculateScratchieMarksForVsaQuestion(qbQuestion.getUid()); + toolService.recalculateScratchieMarksForVsaQuestion(qbQuestion.getUid(), answer); } @Override Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java =================================================================== diff -u -rd295cb9148c3c8cbe2e98de79ae41f7eba704fe9 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision d295cb9148c3c8cbe2e98de79ae41f7eba704fe9) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -298,31 +298,32 @@ @RequestParam Long questionUid, @RequestParam Long targetOptionUid, @RequestParam Long previousOptionUid, @RequestParam Long questionResultUid) { - AssessmentQuestionResult questionRes = service.getAssessmentQuestionResultByUid(questionResultUid); - String answer = questionRes.getAnswer(); - /* - * We need to synchronise this operation. - * When multiple requests are made to modify the same option, for example to add a VSA answer, - * we have a case of dirty reads. - * One answer gets added, but while DB is still flushing, - * another answer reads the option without the first answer, - * because it is not there yet. - * The second answer gets added, but the first one gets lost. - * - * We can not synchronise the method in service - * as the "dirty" transaction is already started before synchronisation kicks in. - * We do it here, before transaction starts. - * It will not work for distributed environment, though. - * If teachers allocate answers on different LAMS servers, - * we can still get the same problem. We will need a more sophisticated solution then. - */ Long optionUid = null; - synchronized (service) { - optionUid = service.allocateAnswerToOption(questionUid, targetOptionUid, previousOptionUid, answer); - } - //recalculate marks for all lessons in all cases except for reshuffling inside the same container if (!targetOptionUid.equals(previousOptionUid)) { + AssessmentQuestionResult questionRes = service.getAssessmentQuestionResultByUid(questionResultUid); + String answer = questionRes.getAnswer(); + /* + * We need to synchronise this operation. + * When multiple requests are made to modify the same option, for example to add a VSA answer, + * we have a case of dirty reads. + * One answer gets added, but while DB is still flushing, + * another answer reads the option without the first answer, + * because it is not there yet. + * The second answer gets added, but the first one gets lost. + * + * We can not synchronise the method in service + * as the "dirty" transaction is already started before synchronisation kicks in. + * We do it here, before transaction starts. + * It will not work for distributed environment, though. + * If teachers allocate answers on different LAMS servers, + * we can still get the same problem. We will need a more sophisticated solution then. + */ + + synchronized (service) { + optionUid = service.allocateAnswerToOption(questionUid, targetOptionUid, previousOptionUid, answer); + } + //recalculate marks for all lessons in all cases except for reshuffling inside the same container service.recalculateMarksForAllocatedAnswer(questionUid, answer); } Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/ScratchieSessionDAO.java =================================================================== diff -u -r122ff0d8419be3fac72ddb842cbbce1cea01e542 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/ScratchieSessionDAO.java (.../ScratchieSessionDAO.java) (revision 122ff0d8419be3fac72ddb842cbbce1cea01e542) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/ScratchieSessionDAO.java (.../ScratchieSessionDAO.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -48,11 +48,8 @@ Object[] getStatsMarksForLeaders(Long toolContentId); /** - * Returns all session ids where specified qbQuestionUid is used. - * - * @param qbQuestionUid - * @return + * Returns all session ids where specified qbQuestionUid is used with the given answer */ - List getSessionIdsByQbQuestion(Long qbQuestionUid); + List getSessionIdsByQbQuestion(Long qbQuestionUid, String answer); } Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieSessionDAOHibernate.java =================================================================== diff -u -r122ff0d8419be3fac72ddb842cbbce1cea01e542 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieSessionDAOHibernate.java (.../ScratchieSessionDAOHibernate.java) (revision 122ff0d8419be3fac72ddb842cbbce1cea01e542) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/dao/hibernate/ScratchieSessionDAOHibernate.java (.../ScratchieSessionDAOHibernate.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -34,7 +34,7 @@ import org.hibernate.type.IntegerType; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.tool.scratchie.dao.ScratchieSessionDAO; -import org.lamsfoundation.lams.tool.scratchie.model.Scratchie; +import org.lamsfoundation.lams.tool.scratchie.model.ScratchieAnswerVisitLog; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieItem; import org.lamsfoundation.lams.tool.scratchie.model.ScratchieSession; import org.lamsfoundation.lams.tool.scratchie.util.ScratchieSessionComparator; @@ -69,12 +69,12 @@ @Override @SuppressWarnings("unchecked") public List getByContentId(Long toolContentId) { - List sessions = (List) doFind(FIND_BY_CONTENT_ID, toolContentId); + List sessions = doFind(FIND_BY_CONTENT_ID, toolContentId); - Set sortedSessions = new TreeSet(new ScratchieSessionComparator()); + Set sortedSessions = new TreeSet<>(new ScratchieSessionComparator()); sortedSessions.addAll(sessions); - return new ArrayList(sortedSessions); + return new ArrayList<>(sortedSessions); } @Override @@ -94,33 +94,33 @@ query.setParameter("toolContentId", toolContentId); return (List) query.list(); } - + @Override public Object[] getStatsMarksForLeaders(Long toolContentId) { NativeQuery query = getSession().createNativeQuery(FIND_MARK_STATS) - .addScalar("min_grade", FloatType.INSTANCE) - .addScalar("avg_grade", FloatType.INSTANCE) - .addScalar("max_grade", FloatType.INSTANCE) - .addScalar("num_complete", IntegerType.INSTANCE); + .addScalar("min_grade", FloatType.INSTANCE).addScalar("avg_grade", FloatType.INSTANCE) + .addScalar("max_grade", FloatType.INSTANCE).addScalar("num_complete", IntegerType.INSTANCE); query.setParameter("toolContentId", toolContentId); @SuppressWarnings("unchecked") List list = (List) query.list(); if ((list == null) || (list.size() == 0)) { return null; } else { - return (Object[]) list.get(0); + return list.get(0); } } @Override - public List getSessionIdsByQbQuestion(Long qbQuestionUid) { - final String FIND_BY_QBQUESTION_AND_FINISHED = "SELECT DISTINCT session.sessionId FROM " + Scratchie.class.getName() - + " AS scratchie, " + ScratchieItem.class.getName() + " AS item, " + ScratchieSession.class.getName() - + " AS session " - + " WHERE session.scratchie.uid = scratchie.uid AND scratchie.uid = item.scratchieUid AND item.qbQuestion.uid =:qbQuestionUid"; - + public List getSessionIdsByQbQuestion(Long qbQuestionUid, String answer) { + final String FIND_BY_QBQUESTION_AND_FINISHED = "SELECT DISTINCT session.sessionId FROM " + + ScratchieItem.class.getName() + " AS item, " + ScratchieSession.class.getName() + " AS session, " + + ScratchieAnswerVisitLog.class.getName() + + " AS visitLog WHERE session.scratchie.uid = item.scratchieUid AND item.qbQuestion.uid =:qbQuestionUid" + + " AND session.sessionId = visitLog.sessionId AND TRIM(visitLog.answer) = TRIM(:answer)"; + Query q = getSession().createQuery(FIND_BY_QBQUESTION_AND_FINISHED, Long.class); q.setParameter("qbQuestionUid", qbQuestionUid); + q.setParameter("answer", answer); return q.list(); } -} +} \ No newline at end of file Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java =================================================================== diff -u -rd4198d73576015c08d18ebf55f3079c84fdf3415 -r2db58f73e88ecef930d486c60cc53fb3fa483415 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision d4198d73576015c08d18ebf55f3079c84fdf3415) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision 2db58f73e88ecef930d486c60cc53fb3fa483415) @@ -31,7 +31,6 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -592,8 +591,8 @@ } @Override - public void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid) { - List sessionIds = scratchieSessionDao.getSessionIdsByQbQuestion(qbQuestionUid); + public void recalculateScratchieMarksForVsaQuestion(Long qbQuestionUid, String answer) { + List sessionIds = scratchieSessionDao.getSessionIdsByQbQuestion(qbQuestionUid, answer); // recalculate marks if it's required for (Long sessionId : sessionIds) { recalculateMarkForSession(sessionId, true); @@ -2722,7 +2721,7 @@ QbCollection collection = null; Set collectionUUIDs = null; - + ArrayNode questions = JsonUtil.optArray(toolContentJSON, RestTags.QUESTIONS); for (int i = 0; i < questions.size(); i++) {