Index: lams_common/src/java/org/lamsfoundation/lams/tool/service/ILamsToolService.java =================================================================== diff -u -rf6247c953cc7bf9a17d4025ea8e8728ae55c11ed -r6ff1966e270c9f86609b19a72f4906419f89670b --- lams_common/src/java/org/lamsfoundation/lams/tool/service/ILamsToolService.java (.../ILamsToolService.java) (revision f6247c953cc7bf9a17d4025ea8e8728ae55c11ed) +++ lams_common/src/java/org/lamsfoundation/lams/tool/service/ILamsToolService.java (.../ILamsToolService.java) (revision 6ff1966e270c9f86609b19a72f4906419f89670b) @@ -22,12 +22,6 @@ package org.lamsfoundation.lams.tool.service; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.confidencelevel.VsaAnswerDTO; import org.lamsfoundation.lams.learning.service.LearnerServiceException; @@ -39,6 +33,9 @@ import org.lamsfoundation.lams.tool.ToolSession; import org.lamsfoundation.lams.util.FileUtilException; +import java.io.IOException; +import java.util.*; + /** * This interface defines all the service available for self contained tool module from lams. Any service that would be * used by other lams module such as, lams_learning etc, should not appear in this interface. @@ -87,12 +84,12 @@ * Do not change learnerId to Integer (to match the other calls) as all the tools expect this to be a Long. * * @param toolSessionId - * , session ID for completed tool + * , session ID for completed tool * @param learnerId - * the learner who is completing the tool session. + * the learner who is completing the tool session. * @return the URL for the next activity * @throws LearnerServiceException - * in case of problems. + * in case of problems. */ String completeToolSession(Long toolSessionId, Long learnerId); @@ -163,9 +160,9 @@ * if no Leader Selection Tools available. * * @param toolSessionId - * sessionId of the specified activity + * sessionId of the specified activity * @param learnerId - * userId (used to get appropriate Leader Selection Tool's session) + * userId (used to get appropriate Leader Selection Tool's session) * @return */ Long getLeaderUserId(Long toolSessionId, Integer learnerId); @@ -190,7 +187,7 @@ * Returns all activities that precede specified activity and produce confidence levels. * * @param toolContentId - * toolContentId of the specified activity + * toolContentId of the specified activity * @return */ Set getActivitiesProvidingConfidenceLevels(Long toolContentId); @@ -199,7 +196,7 @@ * Returns all activities that precede specified activity and can provide VSA answers. * * @param toolContentId - * toolContentId of the specified activity + * toolContentId of the specified activity * @return */ Set getActivitiesProvidingVsaAnswers(Long toolContentId); @@ -208,11 +205,11 @@ * Returns confidence levels from the specified activity. * * @param activityUiid - * activityUiid of the activity with confidence levels + * activityUiid of the activity with confidence levels * @param requestorUserId - * userId of the requesting user. we need it in order to get confidence level providing tool's sessionId + * userId of the requesting user. we need it in order to get confidence level providing tool's sessionId * @param requestorToolSessionId - * toolSessionId of the activity that calls this method + * toolSessionId of the activity that calls this method * @return */ List getConfidenceLevelsByActivity(Integer confidenceLevelActivityUiid, Integer requestorUserId, @@ -222,11 +219,11 @@ * Returns VSA answers from the specified activity. * * @param activityUiid - * activityUiid of the activity providing VSA answers + * activityUiid of the activity providing VSA answers * @param requestorUserId - * userId of the requesting user. we need it in order to get tool's sessionId providing VSA answers + * userId of the requesting user. we need it in order to get tool's sessionId providing VSA answers * @param requestorToolSessionId - * toolSessionId of the activity that calls this method + * toolSessionId of the activity that calls this method * @return */ Collection getVsaAnswersFromAssessment(Integer activityUiidProvidingVsaAnswers, @@ -248,9 +245,11 @@ * Get a count of all the users that would be returned by getUsersForActivity(Long toolSessionId); */ Integer getCountUsersForActivity(Long toolSessionId); - + /** * Updates TBL iRAT/tRAT activity with questions from matching tRAT/iRAT activity */ boolean syncRatQuestions(long toolContentId, List newQuestionUids); + + void assignGroupsForGalleryWalk(SortedMap> groups, int clusterSize); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/tool/service/LamsToolService.java =================================================================== diff -u -rb8e5c281efce81034ea2675a610ba3ea8faa41fb -r6ff1966e270c9f86609b19a72f4906419f89670b --- lams_common/src/java/org/lamsfoundation/lams/tool/service/LamsToolService.java (.../LamsToolService.java) (revision b8e5c281efce81034ea2675a610ba3ea8faa41fb) +++ lams_common/src/java/org/lamsfoundation/lams/tool/service/LamsToolService.java (.../LamsToolService.java) (revision 6ff1966e270c9f86609b19a72f4906419f89670b) @@ -23,16 +23,6 @@ package org.lamsfoundation.lams.tool.service; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.hibernate.Hibernate; @@ -41,13 +31,7 @@ import org.lamsfoundation.lams.confidencelevel.VsaAnswerDTO; import org.lamsfoundation.lams.gradebook.service.IGradebookService; import org.lamsfoundation.lams.learning.service.ILearnerService; -import org.lamsfoundation.lams.learningdesign.Activity; -import org.lamsfoundation.lams.learningdesign.ActivityEvaluation; -import org.lamsfoundation.lams.learningdesign.DataFlowObject; -import org.lamsfoundation.lams.learningdesign.FloatingActivity; -import org.lamsfoundation.lams.learningdesign.Group; -import org.lamsfoundation.lams.learningdesign.ToolActivity; -import org.lamsfoundation.lams.learningdesign.Transition; +import org.lamsfoundation.lams.learningdesign.*; import org.lamsfoundation.lams.learningdesign.dao.IActivityDAO; import org.lamsfoundation.lams.learningdesign.dao.IDataFlowDAO; import org.lamsfoundation.lams.learningdesign.dto.ActivityPositionDTO; @@ -71,11 +55,14 @@ import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.FileUtilException; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + /** * @author Jacky Fang - * @since 2005-3-17 - * * @author Ozgur Demirtas 24/06/2005 + * @since 2005-3-17 */ public class LamsToolService implements ILamsToolService { private static final Logger log = Logger.getLogger(LamsToolService.class); @@ -347,12 +334,12 @@ if (completedActivity instanceof ToolActivity) { ToolActivity completedToolActivity = (ToolActivity) completedActivity; - if (ILamsToolService.LEADER_SELECTION_TOOL_SIGNATURE - .equals(completedToolActivity.getTool().getToolSignature())) { + if (ILamsToolService.LEADER_SELECTION_TOOL_SIGNATURE.equals( + completedToolActivity.getTool().getToolSignature())) { Date finishDate = completedActivities.get(completedActivity).getFinishDate(); - if ((leaderSelectActivityFinishDate == null) - || (finishDate.compareTo(leaderSelectActivityFinishDate) < 0)) { + if ((leaderSelectActivityFinishDate == null) || ( + finishDate.compareTo(leaderSelectActivityFinishDate) < 0)) { leaderSelectionActivity = completedToolActivity; leaderSelectActivityFinishDate = completedActivities.get(completedActivity).getFinishDate(); } @@ -395,8 +382,8 @@ Set confidenceProvidingActivities = new LinkedHashSet<>(); for (Long confidenceProvidingActivityId : confidenceProvidingActivityIds) { - ToolActivity confidenceProvidingActivity = (ToolActivity) activityDAO - .getActivityByActivityId(confidenceProvidingActivityId, ToolActivity.class); + ToolActivity confidenceProvidingActivity = (ToolActivity) activityDAO.getActivityByActivityId( + confidenceProvidingActivityId, ToolActivity.class); confidenceProvidingActivities.add(confidenceProvidingActivity); } @@ -426,8 +413,8 @@ } String toolSignature = toolActivity.getTool().getToolSignature(); - if (TOOL_SIGNATURE_ASSESSMENT.equals(toolSignature) - || isMcqIncluded && TOOL_SIGNATURE_MCQ.equals(toolSignature)) { + if (TOOL_SIGNATURE_ASSESSMENT.equals(toolSignature) || isMcqIncluded && TOOL_SIGNATURE_MCQ.equals( + toolSignature)) { confidenceProvidingActivityIds.add(toolActivity.getActivityId()); } @@ -476,8 +463,8 @@ Set activitiesProvidingVsaAnswers = new LinkedHashSet<>(); for (Long confidenceProvidingActivityId : providingVsaAnswersActivityIds) { - ToolActivity activityProvidingVsaAnswers = (ToolActivity) activityDAO - .getActivityByActivityId(confidenceProvidingActivityId, ToolActivity.class); + ToolActivity activityProvidingVsaAnswers = (ToolActivity) activityDAO.getActivityByActivityId( + confidenceProvidingActivityId, ToolActivity.class); activitiesProvidingVsaAnswers.add(activityProvidingVsaAnswers); } @@ -509,8 +496,8 @@ return new ArrayList<>(); } - List confidenceLevelDtos = lamsCoreToolService - .getConfidenceLevelsByToolSession(confidenceLevelSession); + List confidenceLevelDtos = lamsCoreToolService.getConfidenceLevelsByToolSession( + confidenceLevelSession); return confidenceLevelDtos; } @@ -541,12 +528,12 @@ ToolActivity specifiedActivity = activityDAO.getToolActivityByToolContentId(toolContentId); Tool tool = specifiedActivity.getTool(); if (tool.getToolSignature().equals(CommonConstants.TOOL_SIGNATURE_ASSESSMENT)) { - ICommonAssessmentService sessionManager = (ICommonAssessmentService) lamsCoreToolService - .findToolService(tool); + ICommonAssessmentService sessionManager = (ICommonAssessmentService) lamsCoreToolService.findToolService( + tool); return sessionManager.getUnallocatedVSAnswers(toolContentId); } else if (tool.getToolSignature().equals(CommonConstants.TOOL_SIGNATURE_SCRATCHIE)) { - ICommonScratchieService sessionManager = (ICommonScratchieService) lamsCoreToolService - .findToolService(tool); + ICommonScratchieService sessionManager = (ICommonScratchieService) lamsCoreToolService.findToolService( + tool); return sessionManager.getUnallocatedVSAnswers(toolContentId); } return null; @@ -561,15 +548,15 @@ private boolean recalculateAssessmentMarksForVsaQuestion(Long toolQuestionUid, String answer) { Tool assessmentTool = toolDAO.getToolBySignature(CommonConstants.TOOL_SIGNATURE_ASSESSMENT); - ICommonAssessmentService sessionManager = (ICommonAssessmentService) lamsCoreToolService - .findToolService(assessmentTool); + ICommonAssessmentService sessionManager = (ICommonAssessmentService) lamsCoreToolService.findToolService( + assessmentTool); return sessionManager.recalculateMarksForVsaQuestion(toolQuestionUid, answer); } private boolean recalculateScratchieMarksForVsaQuestion(Long toolQuestionUid, String answer) { Tool scratchieTool = toolDAO.getToolBySignature(CommonConstants.TOOL_SIGNATURE_SCRATCHIE); - ICommonScratchieService sessionManager = (ICommonScratchieService) lamsCoreToolService - .findToolService(scratchieTool); + ICommonScratchieService sessionManager = (ICommonScratchieService) lamsCoreToolService.findToolService( + scratchieTool); return sessionManager.recalculateMarksForVsaQuestion(toolQuestionUid, answer); } @@ -595,13 +582,90 @@ return qbToolService.syncRatQuestions(matchingRATActivityId, newQuestionUids); } + @Override + public void assignGroupsForGalleryWalk(SortedMap> groups, int clusterSize) { + // focus only on groups that are not assigned to any cluster yet + List nonAssignedGroups = groups.entrySet().stream() + .filter(groupEntry -> groupEntry.getValue().isEmpty()) + .collect(Collectors.mapping(Map.Entry::getKey, Collectors.toList())); + if (nonAssignedGroups.isEmpty()) { + return; + } + + Random random = new Random(); + Map> nonFullClusterGroups = groups.entrySet().stream() + .filter(groupEntry -> groupEntry.getValue().size() < clusterSize) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + // to each session from nonAssignedGroups assign random sessions from nonFullClusterGroups up to at least clusterSize + for (Map.Entry> nonAssignedGroup : nonFullClusterGroups.entrySet()) { + nonFullClusterGroups.remove(nonAssignedGroup); + Map> nonFullClusterSessionsCopy = nonFullClusterGroups.entrySet().stream() + .filter(groupEntry -> groupEntry.getValue().contains(nonAssignedGroup.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // first try to find sessions which are not full yet + while (nonAssignedGroup.getValue().size() < clusterSize && !nonFullClusterSessionsCopy.isEmpty()) { + Map.Entry> targetGroup = nonFullClusterSessionsCopy.entrySet().stream() + .skip(random.nextInt(nonFullClusterSessionsCopy.size())).findFirst().get(); + + // create a new collection with all cluster members and assign it to each member + Set cluster = new HashSet<>(); + cluster.add(nonAssignedGroup.getKey()); + cluster.addAll(nonAssignedGroup.getValue()); + cluster.add(targetGroup.getKey()); + cluster.addAll(targetGroup.getValue()); + + for (String clusterMember : cluster) { + // do not participate in further cluster assignments for this nonAssignedSession + nonFullClusterSessionsCopy.remove(clusterMember); + Set clusterMemberGroups = groups.get(clusterMember); + clusterMemberGroups.addAll(cluster); + // do not assign itself as a cluster member + clusterMemberGroups.remove(clusterMember); + if (clusterMemberGroups.size() >= clusterSize) { + // make is unavailable for further cluster assignments for any next nonAssignedSession + nonFullClusterGroups.remove(clusterMember); + } + } + } + + // if cluster is not full but we run out of sessions which are not full yet, assign to random cluster + // this will make some clusters bigger than clusterSize + if (nonAssignedGroup.getValue().size() < clusterSize) { + // assign to random cluster + Map> otherGroups = groups.entrySet().stream() + .filter(group -> !group.getKey().equals(nonAssignedGroup.getKey()) && !group.getValue() + .contains(nonAssignedGroup.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + while (nonAssignedGroup.getValue().size() < clusterSize && !otherGroups.isEmpty()) { + Map.Entry> targetGroup = otherGroups.entrySet().stream() + .skip(random.nextInt(otherGroups.size())).findFirst().get(); + + Set cluster = new HashSet<>(); + cluster.add(nonAssignedGroup.getKey()); + cluster.addAll(nonAssignedGroup.getValue()); + cluster.add(targetGroup.getKey()); + cluster.addAll(targetGroup.getValue()); + + for (String clusterMember : cluster) { + otherGroups.remove(clusterMember); + Set clusterMemberGroups = groups.get(clusterMember); + clusterMemberGroups.addAll(cluster); + clusterMemberGroups.remove(clusterMember); + } + } + } + } + } + // --------------------------------------------------------------------- // Inversion of Control Methods - Method injection // --------------------------------------------------------------------- /** * @param toolDAO - * The toolDAO to set. + * The toolDAO to set. */ public void setToolDAO(IToolDAO toolDAO) { this.toolDAO = toolDAO; @@ -651,7 +715,7 @@ /** * @param userService - * User Management Service + * User Management Service */ public void setUserManagementService(IUserManagementService userService) { this.userManagementService = userService; Index: lams_tool_doku/src/java/org/lamsfoundation/lams/tool/dokumaran/service/DokumaranService.java =================================================================== diff -u -r66aaa15469871d9f71cafcfc4222ffa90f2d9bb2 -r6ff1966e270c9f86609b19a72f4906419f89670b --- lams_tool_doku/src/java/org/lamsfoundation/lams/tool/dokumaran/service/DokumaranService.java (.../DokumaranService.java) (revision 66aaa15469871d9f71cafcfc4222ffa90f2d9bb2) +++ lams_tool_doku/src/java/org/lamsfoundation/lams/tool/dokumaran/service/DokumaranService.java (.../DokumaranService.java) (revision 6ff1966e270c9f86609b19a72f4906419f89670b) @@ -722,71 +722,26 @@ // focus only on sessions that are not assigned to any cluster yet List allSessions = dokumaranSessionDao.getByContentId(toolContentId); - List nonAssignedSessions = allSessions.stream() - .filter(session -> session.getGalleryWalkCluster().isEmpty()).collect(Collectors.toList()); - if (nonAssignedSessions.isEmpty()) { - return; - } + TreeMap> sessionClusters = allSessions.stream().collect( + Collectors.toMap(session -> session.getSessionName(), + session -> session.getGalleryWalkCluster().stream() + .collect(Collectors.mapping(DokumaranSession::getSessionName, Collectors.toSet())), + (existing, replacement) -> { + existing.addAll(replacement); + return existing; + }, TreeMap::new)); - Random random = new Random(); - List nonFullClusterSessions = allSessions.stream() - .filter(session -> session.getGalleryWalkCluster().size() < clusterSize).collect(Collectors.toList()); - // to each session from nonAssignedSessions assign random sessions from nonFullClusterSessions up to at least clusterSize - for (DokumaranSession nonAssignedSession : nonAssignedSessions) { - nonFullClusterSessions.remove(nonAssignedSession); - List nonFullClusterSessionsCopy = nonFullClusterSessions.stream() - .filter(session -> !session.getGalleryWalkCluster().contains(nonAssignedSession)) - .collect(Collectors.toList()); + toolService.assignGroupsForGalleryWalk(sessionClusters, clusterSize); - // first try to find sessions which are not full yet - while (nonAssignedSession.getGalleryWalkCluster().size() < clusterSize - && !nonFullClusterSessionsCopy.isEmpty()) { - DokumaranSession targetSession = nonFullClusterSessionsCopy.get( - random.nextInt(nonFullClusterSessionsCopy.size())); + Map sessionsByName = allSessions.stream() + .collect(Collectors.toMap(session -> session.getSessionName(), Function.identity())); - // create a new collection with all cluster members and assign it to each member - Set cluster = new HashSet<>(); - cluster.add(nonAssignedSession); - cluster.addAll(nonAssignedSession.getGalleryWalkCluster()); - cluster.add(targetSession); - cluster.addAll(targetSession.getGalleryWalkCluster()); - - for (DokumaranSession clusterMember : cluster) { - // do not participate in further cluster assignments for this nonAssignedSession - nonFullClusterSessionsCopy.remove(clusterMember); - clusterMember.getGalleryWalkCluster().addAll(cluster); - // do not assign itself as a cluster member - clusterMember.getGalleryWalkCluster().remove(clusterMember); - if (clusterMember.getGalleryWalkCluster().size() >= clusterSize) { - // make is unavailable for further cluster assignments for any next nonAssignedSession - nonFullClusterSessions.remove(clusterMember); - } - } - } - - // if cluster is not full but we run out of sessions which are not full yet, assign to random cluster - // this will make some clusters bigger than clusterSize - if (nonAssignedSession.getGalleryWalkCluster().size() < clusterSize) { - // assign to random cluster - List otherSessions = allSessions.stream() - .filter(session -> !session.equals(nonAssignedSession) && !session.getGalleryWalkCluster() - .contains(nonAssignedSession)).collect(Collectors.toList()); - while (nonAssignedSession.getGalleryWalkCluster().size() < clusterSize && !otherSessions.isEmpty()) { - DokumaranSession targetSession = otherSessions.get(random.nextInt(otherSessions.size())); - - Set cluster = new HashSet<>(); - cluster.add(nonAssignedSession); - cluster.addAll(nonAssignedSession.getGalleryWalkCluster()); - cluster.add(targetSession); - cluster.addAll(targetSession.getGalleryWalkCluster()); - - for (DokumaranSession clusterMember : cluster) { - otherSessions.remove(clusterMember); - clusterMember.getGalleryWalkCluster().addAll(cluster); - clusterMember.getGalleryWalkCluster().remove(clusterMember); - } - } - } + for (Map.Entry> sessionClusterEntry : sessionClusters.entrySet()) { + DokumaranSession session = sessionsByName.get(sessionClusterEntry.getKey()); + Set cluster = sessionClusterEntry.getValue().stream() + .map(sessionName -> sessionsByName.get(sessionName)).collect(Collectors.toSet()); + session.getGalleryWalkCluster().clear(); + session.getGalleryWalkCluster().addAll(cluster); } for (DokumaranSession session : allSessions) { @@ -1161,7 +1116,6 @@ etherpadService.createCookie(etherpadSessionIds, response); } - private ObjectNode getTimeLimitSettingsJson(long toolContentId) { ObjectNode timeLimitSettings = JsonNodeFactory.instance.objectNode(); Dokumaran dokumaran = getDokumaranByContentId(toolContentId);