Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== RCS file: /usr/local/cvsroot/lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java,v diff -u -r1.86 -r1.87 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java 18 Sep 2008 02:42:19 -0000 1.86 +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java 1 Oct 2008 00:00:05 -0000 1.87 @@ -74,1123 +74,1172 @@ import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.MessageService; +import org.springframework.dao.DeadlockLoserDataAccessException; /** * This class is a facade over the Learning middle tier. + * * @author chris, Jacky Fang */ public class LearnerService implements ICoreLearnerService { - //--------------------------------------------------------------------- - // Instance variables - //--------------------------------------------------------------------- - private static Logger log = Logger.getLogger(LearnerService.class); + // --------------------------------------------------------------------- + // Instance variables + // --------------------------------------------------------------------- + private static Logger log = Logger.getLogger(LearnerService.class); - private ILearnerProgressDAO learnerProgressDAO; - private ILessonDAO lessonDAO; - private IActivityDAO activityDAO; - private IGroupingDAO groupingDAO; - private ProgressEngine progressEngine; - private IToolSessionDAO toolSessionDAO; - private ILamsCoreToolService lamsCoreToolService; - private ActivityMapping activityMapping; - private IUserManagementService userManagementService; - private ILessonService lessonService; - protected MessageService messageService; + private ILearnerProgressDAO learnerProgressDAO; + private ILessonDAO lessonDAO; + private IActivityDAO activityDAO; + private IGroupingDAO groupingDAO; + private ProgressEngine progressEngine; + private IToolSessionDAO toolSessionDAO; + private ILamsCoreToolService lamsCoreToolService; + private ActivityMapping activityMapping; + private IUserManagementService userManagementService; + private ILessonService lessonService; + protected MessageService messageService; - //--------------------------------------------------------------------- - // Inversion of Control Methods - Constructor injection - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Inversion of Control Methods - Constructor injection + // --------------------------------------------------------------------- - /** Creates a new instance of LearnerService*/ - public LearnerService(ProgressEngine progressEngine) { - this.progressEngine = progressEngine; - } + /** Creates a new instance of LearnerService */ + public LearnerService(ProgressEngine progressEngine) { + this.progressEngine = progressEngine; + } - /** Creates a new instance of LearnerService. To be used by Spring, assuming the Spring - * will set up the progress engine via method injection. If you are creating the bean manually - * then use the other constructor. */ - public LearnerService() { - } + /** + * Creates a new instance of LearnerService. To be used by Spring, assuming the Spring will set up the progress + * engine via method injection. If you are creating the bean manually then use the other constructor. + */ + public LearnerService() { + } - //--------------------------------------------------------------------- - // Inversion of Control Methods - Method injection - //--------------------------------------------------------------------- - /** - * Set i18n MessageService - */ - public void setMessageService(MessageService messageService) { - this.messageService = messageService; - } + // --------------------------------------------------------------------- + // Inversion of Control Methods - Method injection + // --------------------------------------------------------------------- + /** + * Set i18n MessageService + */ + public void setMessageService(MessageService messageService) { + this.messageService = messageService; + } - public MessageService getMessageService() { - return messageService; - } + public MessageService getMessageService() { + return messageService; + } - /** - * @param toolSessionDAO The toolSessionDAO to set. - */ - public void setToolSessionDAO(IToolSessionDAO toolSessionDAO) { - this.toolSessionDAO = toolSessionDAO; - } + /** + * @param toolSessionDAO + * The toolSessionDAO to set. + */ + public void setToolSessionDAO(IToolSessionDAO toolSessionDAO) { + this.toolSessionDAO = toolSessionDAO; + } - /** - * @param lessonDAO The lessonDAO to set. - */ - public void setLessonDAO(ILessonDAO lessonDAO) { - this.lessonDAO = lessonDAO; - } + /** + * @param lessonDAO + * The lessonDAO to set. + */ + public void setLessonDAO(ILessonDAO lessonDAO) { + this.lessonDAO = lessonDAO; + } - /** - * @param learnerProgressDAO The learnerProgressDAO to set. - */ - public void setLearnerProgressDAO(ILearnerProgressDAO learnerProgressDAO) { - this.learnerProgressDAO = learnerProgressDAO; - } + /** + * @param learnerProgressDAO + * The learnerProgressDAO to set. + */ + public void setLearnerProgressDAO(ILearnerProgressDAO learnerProgressDAO) { + this.learnerProgressDAO = learnerProgressDAO; + } - /** - * @param lamsToolService The lamsToolService to set. - */ - public void setLamsCoreToolService(ILamsCoreToolService lamsToolService) { - lamsCoreToolService = lamsToolService; - } + /** + * @param lamsToolService + * The lamsToolService to set. + */ + public void setLamsCoreToolService(ILamsCoreToolService lamsToolService) { + lamsCoreToolService = lamsToolService; + } - public void setActivityMapping(ActivityMapping activityMapping) { - this.activityMapping = activityMapping; - } + public void setActivityMapping(ActivityMapping activityMapping) { + this.activityMapping = activityMapping; + } - /** - * @param activityDAO The activityDAO to set. - */ - public void setActivityDAO(IActivityDAO activityDAO) { - this.activityDAO = activityDAO; - } + /** + * @param activityDAO + * The activityDAO to set. + */ + public void setActivityDAO(IActivityDAO activityDAO) { + this.activityDAO = activityDAO; + } - /** - * @param groupingDAO The groupingDAO to set. - */ - public void setGroupingDAO(IGroupingDAO groupingDAO) { - this.groupingDAO = groupingDAO; - } + /** + * @param groupingDAO + * The groupingDAO to set. + */ + public void setGroupingDAO(IGroupingDAO groupingDAO) { + this.groupingDAO = groupingDAO; + } - /** - * @return the User Management Service - */ - public IUserManagementService getUserManagementService() { - return userManagementService; - } + /** + * @return the User Management Service + */ + public IUserManagementService getUserManagementService() { + return userManagementService; + } - /** - * @param userService User Management Service - */ - public void setUserManagementService(IUserManagementService userService) { - userManagementService = userService; - } + /** + * @param userService + * User Management Service + */ + public void setUserManagementService(IUserManagementService userService) { + userManagementService = userService; + } - public void setLessonService(ILessonService lessonService) { - this.lessonService = lessonService; - } + public void setLessonService(ILessonService lessonService) { + this.lessonService = lessonService; + } - //--------------------------------------------------------------------- - // Service Methods - //--------------------------------------------------------------------- - /** - * Delegate to lesson dao to load up the lessons. - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActiveLessonsFor(org.lamsfoundation.lams.usermanagement.User) - */ - public LessonDTO[] getActiveLessonsFor(Integer learnerId) { - User learner = (User) userManagementService.findById(User.class, learnerId); - List activeLessons = lessonDAO.getActiveLessonsForLearner(learner); - return getLessonDataFor(activeLessons); - } + // --------------------------------------------------------------------- + // Service Methods + // --------------------------------------------------------------------- + /** + * Delegate to lesson dao to load up the lessons. + * + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActiveLessonsFor(org.lamsfoundation.lams.usermanagement.User) + */ + public LessonDTO[] getActiveLessonsFor(Integer learnerId) { + User learner = (User) userManagementService.findById(User.class, learnerId); + List activeLessons = lessonDAO.getActiveLessonsForLearner(learner); + return getLessonDataFor(activeLessons); + } - public Lesson getLesson(Long lessonId) { - return lessonDAO.getLesson(lessonId); - } + public Lesson getLesson(Long lessonId) { + return lessonDAO.getLesson(lessonId); + } - /** - * Get the lesson data for a particular lesson. In a DTO format suitable for sending to the client. - */ - public LessonDTO getLessonData(Long lessonId) { - Lesson lesson = getLesson(lessonId); - return lesson != null ? lesson.getLessonData() : null; - } + /** + * Get the lesson data for a particular lesson. In a DTO format suitable for sending to the client. + */ + public LessonDTO getLessonData(Long lessonId) { + Lesson lesson = getLesson(lessonId); + return lesson != null ? lesson.getLessonData() : null; + } - /** - *

Joins a User to a lesson as a learner. It could either be a new lesson - * or a lesson that has been started.

- * - *

In terms of new lesson, a new learner progress would be initialized. - * Tool session for the next activity will be initialized if necessary.

- * - *

In terms of an started lesson, the learner progress will be returned - * without calculation. Tool session will be initialized if necessary. - * Note that we won't initialize tool session for current activity because - * we assume tool session will always initialize before it becomes a - * current activity.

+ * Joins a User to a lesson as a learner. It could either be a new lesson or a lesson that has been started. + *

+ * + *

+ * In terms of new lesson, a new learner progress would be initialized. Tool session for the next activity will be + * initialized if necessary. + *

+ * + *

+ * In terms of an started lesson, the learner progress will be returned without calculation. Tool session will be + * initialized if necessary. Note that we won't initialize tool session for current activity because we assume tool + * session will always initialize before it becomes a current activity.

list = builder.getActivityList(); + LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learnerId, lessonId); + Lesson lesson = progress.getLesson(); - Object[] retValue = new Object[2]; - retValue[0] = list; - retValue[1] = progress.getCurrentActivity() != null ? progress.getCurrentActivity().getActivityId() : null; + ProgressBuilder builder = new ProgressBuilder(progress, activityDAO, activityMapping); + builder.parseLearningDesign(); + List list = builder.getActivityList(); - return retValue; - } + Object[] retValue = new Object[2]; + retValue[0] = list; + retValue[1] = progress.getCurrentActivity() != null ? progress.getCurrentActivity().getActivityId() : null; - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#chooseActivity(org.lamsfoundation.lams.usermanagement.User, java.lang.Long, org.lamsfoundation.lams.learningdesign.Activity) - */ - public LearnerProgress chooseActivity(Integer learnerId, Long lessonId, Activity activity, Boolean clearCompletedFlag) { - LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learnerId, lessonId); + return retValue; + } - if (!progress.getCompletedActivities().contains(activity)) { - // if we skip a sequence in an optional sequence, or have been force completed for branching / optional sequence - // and we go back to the sequence later, then the LessonComplete flag must be reset so that it will step through - // all the activities in the sequence - otherwise it will go to the "Completed" screen after the first activity in the sequence - if (clearCompletedFlag && activity.getParentActivity() != null && activity.getParentActivity().isSequenceActivity() - && progress.isComplete()) { - progress.setLessonComplete(LearnerProgress.LESSON_NOT_COMPLETE); - } + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#chooseActivity(org.lamsfoundation.lams.usermanagement.User, + * java.lang.Long, org.lamsfoundation.lams.learningdesign.Activity) + */ + public LearnerProgress chooseActivity(Integer learnerId, Long lessonId, Activity activity, + Boolean clearCompletedFlag) { + LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learnerId, lessonId); - progressEngine.setActivityAttempted(progress, activity); - progress.setCurrentActivity(activity); - progress.setNextActivity(activity); + if (!progress.getCompletedActivities().contains(activity)) { + // if we skip a sequence in an optional sequence, or have been force completed for branching / optional + // sequence + // and we go back to the sequence later, then the LessonComplete flag must be reset so that it will step + // through + // all the activities in the sequence - otherwise it will go to the "Completed" screen after the first + // activity in the sequence + if (clearCompletedFlag && activity.getParentActivity() != null + && activity.getParentActivity().isSequenceActivity() && progress.isComplete()) { + progress.setLessonComplete(LearnerProgress.LESSON_NOT_COMPLETE); + } - learnerProgressDAO.saveLearnerProgress(progress); - } + progressEngine.setActivityAttempted(progress, activity); + progress.setCurrentActivity(activity); + progress.setNextActivity(activity); - return progress; + learnerProgressDAO.saveLearnerProgress(progress); } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#moveToActivity(java.lang.Integer, java.lang.Long, org.lamsfoundation.lams.learningdesign.Activity, org.lamsfoundation.lams.learningdesign.Activity) - */ - public LearnerProgress moveToActivity(Integer learnerId, Long lessonId, Activity fromActivity, Activity toActivity) { - LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learnerId, lessonId); + return progress; + } - if (fromActivity != null) { - progress.setProgressState(fromActivity, LearnerProgress.ACTIVITY_ATTEMPTED, activityDAO); - } + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#moveToActivity(java.lang.Integer, + * java.lang.Long, org.lamsfoundation.lams.learningdesign.Activity, + * org.lamsfoundation.lams.learningdesign.Activity) + */ + public LearnerProgress moveToActivity(Integer learnerId, Long lessonId, Activity fromActivity, Activity toActivity) { + LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learnerId, lessonId); - if (toActivity != null) { - progress.setProgressState(toActivity, LearnerProgress.ACTIVITY_ATTEMPTED, activityDAO); - progress.setCurrentActivity(toActivity); - progress.setNextActivity(toActivity); - } + if (fromActivity != null) { + progress.setProgressState(fromActivity, LearnerProgress.ACTIVITY_ATTEMPTED, activityDAO); + } - learnerProgressDAO.updateLearnerProgress(progress); - return progress; + if (toActivity != null) { + progress.setProgressState(toActivity, LearnerProgress.ACTIVITY_ATTEMPTED, activityDAO); + progress.setCurrentActivity(toActivity); + progress.setNextActivity(toActivity); } - /** - * Calculates learner progress and returns the data required to be displayed - * to the learner. - * @param completedActivity the activity just completed - * @param learner the Learner - * @param learnerProgress the current progress - * @return the bean containing the display data for the Learner - * @throws LamsToolServiceException - * @throws LearnerServiceException in case of problems. - */ - public LearnerProgress calculateProgress(Activity completedActivity, Integer learnerId, LearnerProgress currentLearnerProgress) { - try { - LearnerProgress learnerProgress = progressEngine.calculateProgress(currentLearnerProgress.getUser(), - completedActivity, currentLearnerProgress); - learnerProgressDAO.updateLearnerProgress(learnerProgress); - return learnerProgress; - } - catch (ProgressException e) { - throw new LearnerServiceException(e.getMessage()); - } + learnerProgressDAO.updateLearnerProgress(progress); + return progress; + } + /** + * Calculates learner progress and returns the data required to be displayed to the learner. + * + * @param completedActivity + * the activity just completed + * @param learner + * the Learner + * @param learnerProgress + * the current progress + * @return the bean containing the display data for the Learner + * @throws LamsToolServiceException + * @throws LearnerServiceException + * in case of problems. + */ + public LearnerProgress calculateProgress(Activity completedActivity, Integer learnerId, + LearnerProgress currentLearnerProgress) { + try { + LearnerProgress learnerProgress = progressEngine.calculateProgress(currentLearnerProgress.getUser(), + completedActivity, currentLearnerProgress); + learnerProgressDAO.updateLearnerProgress(learnerProgress); + return learnerProgress; + } catch (ProgressException e) { + throw new LearnerServiceException(e.getMessage()); } - /** - * @see org.lamsfoundation.lams.learning.service.ILearnerService#completeToolSession(java.lang.Long, java.lang.Long) - */ - public String completeToolSession(Long toolSessionId, Long learnerId) { - // this method is called by tools, so it mustn't do anything that relies on all the tools' Spring beans - // being available in the context. Hence it is defined in the ILearnerService interface, not the IFullLearnerService - // interface. If it calls any other methods then it mustn't use anything on the ICoreLearnerService interface. + } - String returnURL = null; + /** + * @see org.lamsfoundation.lams.learning.service.ILearnerService#completeToolSession(java.lang.Long, java.lang.Long) + */ + public String completeToolSession(Long toolSessionId, Long learnerId) { + // this method is called by tools, so it mustn't do anything that relies on all the tools' Spring beans + // being available in the context. Hence it is defined in the ILearnerService interface, not the + // IFullLearnerService + // interface. If it calls any other methods then it mustn't use anything on the ICoreLearnerService interface. - ToolSession toolSession = lamsCoreToolService.getToolSessionById(toolSessionId); - if (toolSession == null) { - // something has gone wrong - maybe due to Live Edit. The tool session supplied by the tool doesn't exist. - // have to go to a "can't do anything" screen and the user will have to hit resume. - returnURL = activityMapping.getProgressBrokenURL(); + String returnURL = null; - } - else { - Long lessonId = toolSession.getLesson().getLessonId(); - LearnerProgress currentProgress = getProgress(new Integer(learnerId.intValue()), lessonId); - // TODO Cache the learner progress in the session, but mark it with the progress id. Then get the progress out of the session - // for ActivityAction.java.completeActivity(). Update LearningWebUtil to look under the progress id, so we don't get - // a conflict in Preview & Learner. - returnURL = activityMapping.getCompleteActivityURL(toolSession.getToolActivity().getActivityId(), currentProgress - .getLearnerProgressId()); + ToolSession toolSession = lamsCoreToolService.getToolSessionById(toolSessionId); + if (toolSession == null) { + // something has gone wrong - maybe due to Live Edit. The tool session supplied by the tool doesn't exist. + // have to go to a "can't do anything" screen and the user will have to hit resume. + returnURL = activityMapping.getProgressBrokenURL(); - } + } else { + Long lessonId = toolSession.getLesson().getLessonId(); + LearnerProgress currentProgress = getProgress(new Integer(learnerId.intValue()), lessonId); + // TODO Cache the learner progress in the session, but mark it with the progress id. Then get the progress + // out of the session + // for ActivityAction.java.completeActivity(). Update LearningWebUtil to look under the progress id, so we + // don't get + // a conflict in Preview & Learner. + returnURL = activityMapping.getCompleteActivityURL(toolSession.getToolActivity().getActivityId(), + currentProgress.getLearnerProgressId()); - if (LearnerService.log.isDebugEnabled()) { - LearnerService.log.debug("CompleteToolSession() for tool session id " + toolSessionId + " learnerId " + learnerId - + " url is " + returnURL); - } + } - return returnURL; - + if (LearnerService.log.isDebugEnabled()) { + LearnerService.log.debug("CompleteToolSession() for tool session id " + toolSessionId + " learnerId " + + learnerId + " url is " + returnURL); } - /** - * Complete the activity in the progress engine and delegate to the progress - * engine to calculate the next activity in the learning design. - * It is currently triggered by various progress engine related action classes, - * which then calculate the url to go to next, based on the ActivityMapping - * class. - * - * @param learnerId the learner who are running this activity in the design. - * @param activity the activity is being run. - * @param lessonId lesson id - * @return the updated learner progress - */ - public LearnerProgress completeActivity(Integer learnerId, Activity activity, LearnerProgress progress) { - LearnerProgress nextLearnerProgress = null; + return returnURL; - // Need to synchronise the next bit of code so that if the tool calls - // this twice in quick succession, with the same parameters, it won't update - // the database twice! This may happen if a tool has a double submission problem. - // I don't want to synchronise on (this), as this could cause too much of a bottleneck, - // but if its not synchronised, we get db errors if the same tool session is completed twice - // (invalid index). I can'tfind another object on which to synchronise - Hibernate does not give me the - // same object for tool session or current progress and user is cached via login, not userid. + } - // bottleneck synchronized (this) { - if (activity == null) { - try { - nextLearnerProgress = progressEngine.setUpStartPoint(progress); - } - catch (ProgressException e) { - LearnerService.log.error("error occurred in 'setUpStartPoint':" + e.getMessage(), e); - throw new LearnerServiceException(e); - } + /** + * Complete the activity in the progress engine and delegate to the progress engine to calculate the next activity + * in the learning design. It is currently triggered by various progress engine related action classes, which then + * calculate the url to go to next, based on the ActivityMapping class. + * + * @param learnerId + * the learner who are running this activity in the design. + * @param activity + * the activity is being run. + * @param lessonId + * lesson id + * @return the updated learner progress + */ + public LearnerProgress completeActivity(Integer learnerId, Activity activity, LearnerProgress progress) { + LearnerProgress nextLearnerProgress = null; - } - else { + // Need to synchronise the next bit of code so that if the tool calls + // this twice in quick succession, with the same parameters, it won't update + // the database twice! This may happen if a tool has a double submission problem. + // I don't want to synchronise on (this), as this could cause too much of a bottleneck, + // but if its not synchronised, we get db errors if the same tool session is completed twice + // (invalid index). I can'tfind another object on which to synchronise - Hibernate does not give me the + // same object for tool session or current progress and user is cached via login, not userid. - nextLearnerProgress = calculateProgress(activity, learnerId, progress); - } - //} - return nextLearnerProgress; - } + // bottleneck synchronized (this) { + if (activity == null) { + try { + nextLearnerProgress = progressEngine.setUpStartPoint(progress); + } catch (ProgressException e) { + LearnerService.log.error("error occurred in 'setUpStartPoint':" + e.getMessage(), e); + throw new LearnerServiceException(e); + } - /** - * @throws - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#completeActivity(java.lang.Integer, org.lamsfoundation.lams.learningdesign.Activity, java.lang.Long ) - */ - public LearnerProgress completeActivity(Integer learnerId, Activity activity, Long lessonId) { - LearnerProgress currentProgress = getProgress(new Integer(learnerId.intValue()), lessonId); - return completeActivity(learnerId, activity, currentProgress); + } else { + + nextLearnerProgress = calculateProgress(activity, learnerId, progress); } + // } + return nextLearnerProgress; + } - /** - * Exit a lesson. - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#exitLesson(org.lamsfoundation.lams.lesson.LearnerProgress) - */ - public void exitLesson(Integer learnerId, Long lessonId) { + /** + * @throws + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#completeActivity(java.lang.Integer, + * org.lamsfoundation.lams.learningdesign.Activity, java.lang.Long ) + */ + public LearnerProgress completeActivity(Integer learnerId, Activity activity, Long lessonId) { + LearnerProgress currentProgress = getProgress(new Integer(learnerId.intValue()), lessonId); + return completeActivity(learnerId, activity, currentProgress); + } - User learner = (User) userManagementService.findById(User.class, learnerId); + /** + * Exit a lesson. + * + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#exitLesson(org.lamsfoundation.lams.lesson.LearnerProgress) + */ + public void exitLesson(Integer learnerId, Long lessonId) { - LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learner.getUserId(), lessonId); + User learner = (User) userManagementService.findById(User.class, learnerId); - if (progress != null) { - progress.setRestarting(true); - learnerProgressDAO.updateLearnerProgress(progress); - } - else { - String error = "Learner Progress " + lessonId + " does not exist. Cannot exit lesson successfully."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } - } + LearnerProgress progress = learnerProgressDAO.getLearnerProgressByLearner(learner.getUserId(), lessonId); - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActivity(java.lang.Long) - */ - public Activity getActivity(Long activityId) { - return activityDAO.getActivityByActivityId(activityId); + if (progress != null) { + progress.setRestarting(true); + learnerProgressDAO.updateLearnerProgress(progress); + } else { + String error = "Learner Progress " + lessonId + " does not exist. Cannot exit lesson successfully."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); } + } - /** - * @throws LearnerServiceException - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#performGrouping(java.lang.Long, java.lang.Long, java.lang.Integer) - */ - public boolean performGrouping(Long lessonId, Long groupingActivityId, Integer learnerId, boolean forceGrouping) - throws LearnerServiceException { - GroupingActivity groupingActivity = (GroupingActivity) activityDAO.getActivityByActivityId(groupingActivityId, - GroupingActivity.class); - User learner = (User) userManagementService.findById(User.class, learnerId); + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActivity(java.lang.Long) + */ + public Activity getActivity(Long activityId) { + return activityDAO.getActivityByActivityId(activityId); + } - boolean groupingDone = false; - try { - if (groupingActivity != null && groupingActivity.getCreateGrouping() != null && learner != null) { - Grouping grouping = groupingActivity.getCreateGrouping(); + /** + * @throws LearnerServiceException + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#performGrouping(java.lang.Long, java.lang.Long, + * java.lang.Integer) + */ + public boolean performGrouping(Long lessonId, Long groupingActivityId, Integer learnerId, boolean forceGrouping) + throws LearnerServiceException { + GroupingActivity groupingActivity = (GroupingActivity) activityDAO.getActivityByActivityId(groupingActivityId, + GroupingActivity.class); + User learner = (User) userManagementService.findById(User.class, learnerId); - // first check if the grouping already done for the user. If done, then skip the processing. - groupingDone = grouping.doesLearnerExist(learner); + boolean groupingDone = false; + try { + if (groupingActivity != null && groupingActivity.getCreateGrouping() != null && learner != null) { + Grouping grouping = groupingActivity.getCreateGrouping(); - if (!groupingDone) { - if (grouping.isRandomGrouping()) { - // normal and preview cases for random grouping - lessonService.performGrouping(lessonId, groupingActivity, learner); - groupingDone = true; + // first check if the grouping already done for the user. If done, then skip the processing. + groupingDone = grouping.doesLearnerExist(learner); - } - else if (forceGrouping) { - // preview case for chosen grouping - Lesson lesson = getLesson(lessonId); - groupingDone = forceGrouping(lesson, grouping, null, learner); - } - } + if (!groupingDone) { + if (grouping.isRandomGrouping()) { + // normal and preview cases for random grouping + lessonService.performGrouping(lessonId, groupingActivity, learner); + groupingDone = true; - } - else { - String error = "Grouping activity " + groupingActivity + " learner " + learnerId - + " does not exist. Cannot perform grouping."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } + } else if (forceGrouping) { + // preview case for chosen grouping + Lesson lesson = getLesson(lessonId); + groupingDone = forceGrouping(lesson, grouping, null, learner); + } } - catch (LessonServiceException e) { - throw new LearnerServiceException("performGrouping failed due to " + e.getMessage(), e); - } - return groupingDone; + + } else { + String error = "Grouping activity " + groupingActivity + " learner " + learnerId + + " does not exist. Cannot perform grouping."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } + } catch (LessonServiceException e) { + throw new LearnerServiceException("performGrouping failed due to " + e.getMessage(), e); } + return groupingDone; + } - /** - * {@inheritDoc} - */ - public boolean learnerChooseGroup(Long lessonId, Long groupingActivityId, Long groupId, Integer learnerId) - throws LearnerServiceException { - GroupingActivity groupingActivity = (GroupingActivity) activityDAO.getActivityByActivityId(groupingActivityId, - GroupingActivity.class); + /** + * {@inheritDoc} + */ + public boolean learnerChooseGroup(Long lessonId, Long groupingActivityId, Long groupId, Integer learnerId) + throws LearnerServiceException { + GroupingActivity groupingActivity = (GroupingActivity) activityDAO.getActivityByActivityId(groupingActivityId, + GroupingActivity.class); - if (groupingActivity != null && groupId != null && learnerId != null) { - Grouping grouping = groupingDAO.getGroupingById(groupingActivity.getCreateGrouping().getGroupingId()); - if (grouping != null && grouping.isLearnerChoiceGrouping()) { + if (groupingActivity != null && groupId != null && learnerId != null) { + Grouping grouping = groupingDAO.getGroupingById(groupingActivity.getCreateGrouping().getGroupingId()); + if (grouping != null && grouping.isLearnerChoiceGrouping()) { - User learner = (User) userManagementService.findById(User.class, learnerId); - if (learner != null) { - Integer maxNumberOfLearnersPerGroup = null; - Set groups = grouping.getGroups(); - if (((LearnerChoiceGrouping) grouping).getLearnersPerGroup() == null) { - if (((LearnerChoiceGrouping) grouping).getEqualNumberOfLearnersPerGroup()) { - if (((LearnerChoiceGrouping) grouping).getLearnersPerGroup() == null) { - Lesson lesson = getLesson(lessonId); - int learnerCount = lesson.getAllLearners().size(); - int groupCount = grouping.getGroups().size(); - maxNumberOfLearnersPerGroup = learnerCount / groupCount - + (learnerCount % groupCount == 0 ? 0 : 1); - } - } - } - else { - maxNumberOfLearnersPerGroup = ((LearnerChoiceGrouping) grouping).getLearnersPerGroup(); - } - if (maxNumberOfLearnersPerGroup != null) { - for (Group group : groups) { - if (group.getGroupId().equals(groupId)) { - if (group.getUsers().size() >= maxNumberOfLearnersPerGroup) { - return false; - } - } - } - } - - lessonService.performGrouping(grouping, groupId, learner); - return true; + User learner = (User) userManagementService.findById(User.class, learnerId); + if (learner != null) { + Integer maxNumberOfLearnersPerGroup = null; + Set groups = grouping.getGroups(); + if (((LearnerChoiceGrouping) grouping).getLearnersPerGroup() == null) { + if (((LearnerChoiceGrouping) grouping).getEqualNumberOfLearnersPerGroup()) { + if (((LearnerChoiceGrouping) grouping).getLearnersPerGroup() == null) { + Lesson lesson = getLesson(lessonId); + int learnerCount = lesson.getAllLearners().size(); + int groupCount = grouping.getGroups().size(); + maxNumberOfLearnersPerGroup = learnerCount / groupCount + + (learnerCount % groupCount == 0 ? 0 : 1); + } + } + } else { + maxNumberOfLearnersPerGroup = ((LearnerChoiceGrouping) grouping).getLearnersPerGroup(); + } + if (maxNumberOfLearnersPerGroup != null) { + for (Group group : groups) { + if (group.getGroupId().equals(groupId)) { + if (group.getUsers().size() >= maxNumberOfLearnersPerGroup) { + return false; } + } } + } + + lessonService.performGrouping(grouping, groupId, learner); + return true; } - return false; + } } + return false; + } - private boolean forceGrouping(Lesson lesson, Grouping grouping, Group group, User learner) { - boolean groupingDone = false; - if (lesson.isPreviewLesson()) { - ArrayList learnerList = new ArrayList(); - learnerList.add(learner); - if (group != null) { - if (group.getGroupId() != null) { - lessonService.performGrouping(grouping, group.getGroupId(), learnerList); - } - else { - lessonService.performGrouping(grouping, group.getGroupName(), learnerList); - } - } - else { - if (grouping.getGroups().size() > 0) { - // if any group exists, put them in there. - Group aGroup = (Group) grouping.getGroups().iterator().next(); - if (aGroup.getGroupId() != null) { - lessonService.performGrouping(grouping, aGroup.getGroupId(), learnerList); - } - else { - lessonService.performGrouping(grouping, aGroup.getGroupName(), learnerList); - } - } - else { - // just create a group and stick the user in there! - lessonService.performGrouping(grouping, (String) null, learnerList); - } - } - groupingDone = true; + private boolean forceGrouping(Lesson lesson, Grouping grouping, Group group, User learner) { + boolean groupingDone = false; + if (lesson.isPreviewLesson()) { + ArrayList learnerList = new ArrayList(); + learnerList.add(learner); + if (group != null) { + if (group.getGroupId() != null) { + lessonService.performGrouping(grouping, group.getGroupId(), learnerList); + } else { + lessonService.performGrouping(grouping, group.getGroupName(), learnerList); } - return groupingDone; + } else { + if (grouping.getGroups().size() > 0) { + // if any group exists, put them in there. + Group aGroup = (Group) grouping.getGroups().iterator().next(); + if (aGroup.getGroupId() != null) { + lessonService.performGrouping(grouping, aGroup.getGroupId(), learnerList); + } else { + lessonService.performGrouping(grouping, aGroup.getGroupName(), learnerList); + } + } else { + // just create a group and stick the user in there! + lessonService.performGrouping(grouping, (String) null, learnerList); + } + } + groupingDone = true; } + return groupingDone; + } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#knockGate(java.lang.Long, org.lamsfoundation.lams.usermanagement.User) - */ - public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate) { - GateActivity gate = (GateActivity) activityDAO.getActivityByActivityId(gateActivityId, GateActivity.class); - if (gate != null) { - return knockGate(gate, knocker, forceGate); - } - - String error = "Gate activity " + gateActivityId + " does not exist. Cannot knock on gate."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#knockGate(java.lang.Long, + * org.lamsfoundation.lams.usermanagement.User) + */ + public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate) { + GateActivity gate = (GateActivity) activityDAO.getActivityByActivityId(gateActivityId, GateActivity.class); + if (gate != null) { + return knockGate(gate, knocker, forceGate); } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#knockGate(org.lamsfoundation.lams.learningdesign.GateActivity, org.lamsfoundation.lams.usermanagement.User) - */ - public GateActivityDTO knockGate(GateActivity gate, User knocker, boolean forceGate) { - Lesson lesson = getLessonByActivity(gate); - List lessonLearners = getLearnersForGate(gate, lesson); + String error = "Gate activity " + gateActivityId + " does not exist. Cannot knock on gate."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } - boolean gateOpen = false; + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#knockGate(org.lamsfoundation.lams.learningdesign.GateActivity, + * org.lamsfoundation.lams.usermanagement.User) + */ + public GateActivityDTO knockGate(GateActivity gate, User knocker, boolean forceGate) { + Lesson lesson = getLessonByActivity(gate); + List lessonLearners = getLearnersForGate(gate, lesson); - if (forceGate) { - if (lesson.isPreviewLesson()) { - // special case for preview - if forceGate is true then brute force open the gate - gateOpen = gate.forceGateOpen(); - } - } + boolean gateOpen = false; - if (!gateOpen) { - // normal case - knock the gate. - gateOpen = gate.shouldOpenGateFor(knocker, lessonLearners); - if (!gateOpen) { - //only for a condition gate - gateOpen = determineConditionGateStatus(gate, knocker); - } - } + if (forceGate) { + if (lesson.isPreviewLesson()) { + // special case for preview - if forceGate is true then brute force open the gate + gateOpen = gate.forceGateOpen(); + } + } - //update gate including updating the waiting list and gate status in - //the database. - activityDAO.update(gate); - return new GateActivityDTO(gate, lessonLearners, gateOpen); - + if (!gateOpen) { + // normal case - knock the gate. + gateOpen = gate.shouldOpenGateFor(knocker, lessonLearners); + if (!gateOpen) { + // only for a condition gate + gateOpen = determineConditionGateStatus(gate, knocker); + } } - /** - * Get all the learners who may come through this gate. - * For a Group Based branch and the Teacher Grouped branch, it is the group of users in - * the Branch's group, but only the learners who have started the lesson. - * Otherwise we just get all learners who have started the lesson. - * @param gate - * @param lesson - * @return List of User - */ - private List getLearnersForGate(GateActivity gate, Lesson lesson) { + // update gate including updating the waiting list and gate status in + // the database. + activityDAO.update(gate); + return new GateActivityDTO(gate, lessonLearners, gateOpen); - List lessonLearners = null; - Activity branchActivity = gate.getParentBranch(); - while (branchActivity != null - && !(branchActivity.getParentActivity().isChosenBranchingActivity() || branchActivity.getParentActivity() - .isGroupBranchingActivity())) { - branchActivity = branchActivity.getParentBranch(); - } + } - if (branchActivity != null) { - // set up list based on branch - all members of a group attached to the branch are destined for the gate - SequenceActivity branchSequence = (SequenceActivity) activityDAO.getActivityByActivityId(branchActivity - .getActivityId(), SequenceActivity.class); - Set branchEntries = branchSequence.getBranchEntries(); - Iterator entryIterator = branchEntries.iterator(); - while (entryIterator.hasNext()) { - BranchActivityEntry branchActivityEntry = (BranchActivityEntry) entryIterator.next(); - Group group = branchActivityEntry.getGroup(); - if (group != null) { - List groupLearners = lessonService.getActiveLessonLearnersByGroup(lesson.getLessonId(), group.getGroupId()); - if (lessonLearners == null) { - lessonLearners = groupLearners; - } - else { - lessonLearners.addAll(groupLearners); - } - } - } + /** + * Get all the learners who may come through this gate. For a Group Based branch and the Teacher Grouped branch, it + * is the group of users in the Branch's group, but only the learners who have started the lesson. Otherwise we just + * get all learners who have started the lesson. + * + * @param gate + * @param lesson + * @return List of User + */ + private List getLearnersForGate(GateActivity gate, Lesson lesson) { - } - else { - lessonLearners = getActiveLearnersByLesson(lesson.getLessonId()); - } - return lessonLearners; + List lessonLearners = null; + Activity branchActivity = gate.getParentBranch(); + while (branchActivity != null + && !(branchActivity.getParentActivity().isChosenBranchingActivity() || branchActivity + .getParentActivity().isGroupBranchingActivity())) { + branchActivity = branchActivity.getParentBranch(); } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getWaitingGateLearners(org.lamsfoundation.lams.learningdesign.GateActivity) - */ - public List getLearnersForGate(GateActivity gate) { - return getLearnersForGate(gate, getLessonByActivity(gate)); - } + if (branchActivity != null) { + // set up list based on branch - all members of a group attached to the branch are destined for the gate + SequenceActivity branchSequence = (SequenceActivity) activityDAO.getActivityByActivityId(branchActivity + .getActivityId(), SequenceActivity.class); + Set branchEntries = branchSequence.getBranchEntries(); + Iterator entryIterator = branchEntries.iterator(); + while (entryIterator.hasNext()) { + BranchActivityEntry branchActivityEntry = (BranchActivityEntry) entryIterator.next(); + Group group = branchActivityEntry.getGroup(); + if (group != null) { + List groupLearners = lessonService.getActiveLessonLearnersByGroup(lesson.getLessonId(), group + .getGroupId()); + if (lessonLearners == null) { + lessonLearners = groupLearners; + } else { + lessonLearners.addAll(groupLearners); + } + } + } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getLearnerActivityURL(java.lang.Integer, java.lang.Long) - */ - public String getLearnerActivityURL(Integer learnerId, Long activityId) { - User learner = (User) userManagementService.findById(User.class, learnerId); - Activity requestedActivity = getActivity(activityId); - Lesson lesson = getLessonByActivity(requestedActivity); - return activityMapping.calculateActivityURLForProgressView(lesson, learner, requestedActivity); + } else { + lessonLearners = getActiveLearnersByLesson(lesson.getLessonId()); } + return lessonLearners; + } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActiveLearnersByLesson(long) - */ - public List getActiveLearnersByLesson(long lessonId) { - return lessonService.getActiveLessonLearners(lessonId); - } + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getWaitingGateLearners(org.lamsfoundation.lams.learningdesign.GateActivity) + */ + public List getLearnersForGate(GateActivity gate) { + return getLearnersForGate(gate, getLessonByActivity(gate)); + } - /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getCountActiveLessonLearners(long) - */ - public Integer getCountActiveLearnersByLesson(long lessonId) { - return lessonService.getCountActiveLessonLearners(lessonId); - } + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getLearnerActivityURL(java.lang.Integer, + * java.lang.Long) + */ + public String getLearnerActivityURL(Integer learnerId, Long activityId) { + User learner = (User) userManagementService.findById(User.class, learnerId); + Activity requestedActivity = getActivity(activityId); + Lesson lesson = getLessonByActivity(requestedActivity); + return activityMapping.calculateActivityURLForProgressView(lesson, learner, requestedActivity); + } - /** - * Get the lesson for this activity. If the activity is not part of a lesson (ie is from an authoring - * design then it will return null. - */ - public Lesson getLessonByActivity(Activity activity) { - Lesson lesson = lessonDAO.getLessonForActivity(activity.getActivityId()); - if (lesson == null) { - LearnerService.log - .warn("Tried to get lesson id for a non-lesson based activity. An error is likely to be thrown soon. Activity was " - + activity); - } - return lesson; + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActiveLearnersByLesson(long) + */ + public List getActiveLearnersByLesson(long lessonId) { + return lessonService.getActiveLessonLearners(lessonId); + } + + /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getCountActiveLessonLearners(long) + */ + public Integer getCountActiveLearnersByLesson(long lessonId) { + return lessonService.getCountActiveLessonLearners(lessonId); + } + + /** + * Get the lesson for this activity. If the activity is not part of a lesson (ie is from an authoring design then it + * will return null. + */ + public Lesson getLessonByActivity(Activity activity) { + Lesson lesson = lessonDAO.getLessonForActivity(activity.getActivityId()); + if (lesson == null) { + LearnerService.log + .warn("Tried to get lesson id for a non-lesson based activity. An error is likely to be thrown soon. Activity was " + + activity); } + return lesson; + } - //--------------------------------------------------------------------- - // Helper Methods - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Helper Methods + // --------------------------------------------------------------------- - /** - *

Create a lams tool session for learner against a tool activity. This will - * have concurrency issues interms of grouped tool session because it might - * be inserting some tool session that has already been inserted by other - * member in the group. If the unique_check is broken, we need to query - * the database to get the instance instead of inserting it. It should be - * done in the Spring rollback strategy.

- * - * Once lams tool session is inserted, we need to notify the tool to its - * own session. - * - * @param toolActivity - * @param learner - * @throws LamsToolServiceException - */ - private void createToolSessionFor(ToolActivity toolActivity, User learner, Lesson lesson) throws LamsToolServiceException, - ToolException { - // if the tool session already exists, createToolSession() will return null - ToolSession toolSession = lamsCoreToolService.createToolSession(learner, toolActivity, lesson); - if (toolSession != null) { - toolActivity.getToolSessions().add(toolSession); - lamsCoreToolService.notifyToolsToCreateSession(toolSession, toolActivity); - } + /** + *

+ * Create a lams tool session for learner against a tool activity. This will have concurrency issues interms of + * grouped tool session because it might be inserting some tool session that has already been inserted by other + * member in the group. If the unique_check is broken, we need to query the database to get the instance instead of + * inserting it. It should be done in the Spring rollback strategy. + *

+ * + * Once lams tool session is inserted, we need to notify the tool to its own session. + * + * @param toolActivity + * @param learner + * @throws LamsToolServiceException + */ + private void createToolSessionFor(ToolActivity toolActivity, User learner, Lesson lesson) + throws LamsToolServiceException, ToolException { + // if the tool session already exists, createToolSession() will return null + ToolSession toolSession = lamsCoreToolService.createToolSession(learner, toolActivity, lesson); + if (toolSession != null) { + toolActivity.getToolSessions().add(toolSession); + lamsCoreToolService.notifyToolsToCreateSession(toolSession, toolActivity); } + } - /** - * Create an array of lesson dto based a list of lessons. - * @param lessons the list of lessons. - * @return the lesson dto array. - */ - private LessonDTO[] getLessonDataFor(List lessons) { - List lessonDTOList = new ArrayList(); - for (Iterator i = lessons.iterator(); i.hasNext();) { - Lesson currentLesson = (Lesson) i.next(); - lessonDTOList.add(currentLesson.getLessonData()); - } - return lessonDTOList.toArray(new LessonDTO[lessonDTOList.size()]); + /** + * Create an array of lesson dto based a list of lessons. + * + * @param lessons + * the list of lessons. + * @return the lesson dto array. + */ + private LessonDTO[] getLessonDataFor(List lessons) { + List lessonDTOList = new ArrayList(); + for (Iterator i = lessons.iterator(); i.hasNext();) { + Lesson currentLesson = (Lesson) i.next(); + lessonDTOList.add(currentLesson.getLessonData()); } + return lessonDTOList.toArray(new LessonDTO[lessonDTOList.size()]); + } - /** - * @throws LearnerServiceException - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#determineBranch(org.lamsfoundation.lams.lesson.Lesson, org.lamsfoundation.lams.learningdesign.BranchingActivity, java.lang.Integer) - */ - public SequenceActivity determineBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId) - throws LearnerServiceException { - User learner = (User) userManagementService.findById(User.class, learnerId); - if (learner == null) { - String error = "determineBranch: learner " + learnerId + " does not exist. Cannot determine branch."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } + /** + * @throws LearnerServiceException + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#determineBranch(org.lamsfoundation.lams.lesson.Lesson, + * org.lamsfoundation.lams.learningdesign.BranchingActivity, java.lang.Integer) + */ + public SequenceActivity determineBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId) + throws LearnerServiceException { + User learner = (User) userManagementService.findById(User.class, learnerId); + if (learner == null) { + String error = "determineBranch: learner " + learnerId + " does not exist. Cannot determine branch."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } - try { - if (branchingActivity.isToolBranchingActivity()) { - return determineToolBasedBranch(lesson, (ToolBranchingActivity) branchingActivity, learner); + try { + if (branchingActivity.isToolBranchingActivity()) { + return determineToolBasedBranch(lesson, (ToolBranchingActivity) branchingActivity, learner); - } - else { - // assume either isGroupBranchingActivity() || isChosenBranchingActivity() ) - // in both cases, the branch is based on the group the learner is in. - return determineGroupBasedBranch(lesson, branchingActivity, learner); + } else { + // assume either isGroupBranchingActivity() || isChosenBranchingActivity() ) + // in both cases, the branch is based on the group the learner is in. + return determineGroupBasedBranch(lesson, branchingActivity, learner); - } - } - catch (LessonServiceException e) { - String message = "determineBranch failed due to " + e.getMessage(); - LearnerService.log.error(message, e); - throw new LearnerServiceException("determineBranch failed due to " + e.getMessage(), e); - } + } + } catch (LessonServiceException e) { + String message = "determineBranch failed due to " + e.getMessage(); + LearnerService.log.error(message, e); + throw new LearnerServiceException("determineBranch failed due to " + e.getMessage(), e); } + } - /** Get all the conditions for this branching activity, ordered by order id. - * Go through each condition until we find one that passes and that is the required branch. - * If no conditions match, use the branch that is the "default" branch for this branching activity. - */ - private SequenceActivity determineToolBasedBranch(Lesson lesson, ToolBranchingActivity branchingActivity, User learner) { - Activity defaultBranch = branchingActivity.getDefaultActivity(); - SequenceActivity matchedBranch = null; + /** + * Get all the conditions for this branching activity, ordered by order id. Go through each condition until we find + * one that passes and that is the required branch. If no conditions match, use the branch that is the "default" + * branch for this branching activity. + */ + private SequenceActivity determineToolBasedBranch(Lesson lesson, ToolBranchingActivity branchingActivity, + User learner) { + Activity defaultBranch = branchingActivity.getDefaultActivity(); + SequenceActivity matchedBranch = null; - // Work out the tool session appropriate for this user and branching activity. We expect there to be only one at this point. - ToolSession toolSession = null; - for (Activity inputActivity : (Set) branchingActivity.getInputActivities()) { - toolSession = lamsCoreToolService.getToolSessionByLearner(learner, inputActivity); - } + // Work out the tool session appropriate for this user and branching activity. We expect there to be only one at + // this point. + ToolSession toolSession = null; + for (Activity inputActivity : (Set) branchingActivity.getInputActivities()) { + toolSession = lamsCoreToolService.getToolSessionByLearner(learner, inputActivity); + } - if (toolSession != null) { + if (toolSession != null) { - // Get all the conditions for this branching activity, ordered by order id. - Map conditionsMap = new TreeMap(); - Iterator branchIterator = branchingActivity.getActivities().iterator(); - while (branchIterator.hasNext()) { - Activity branchActivity = (Activity) branchIterator.next(); - SequenceActivity branchSequence = (SequenceActivity) activityDAO.getActivityByActivityId(branchActivity - .getActivityId(), SequenceActivity.class); - Iterator entryIterator = branchSequence.getBranchEntries().iterator(); - while (entryIterator.hasNext()) { - BranchActivityEntry entry = entryIterator.next(); - if (entry.getCondition() != null) { - conditionsMap.put(entry.getCondition(), branchSequence); - } - } - } + // Get all the conditions for this branching activity, ordered by order id. + Map conditionsMap = new TreeMap(); + Iterator branchIterator = branchingActivity.getActivities().iterator(); + while (branchIterator.hasNext()) { + Activity branchActivity = (Activity) branchIterator.next(); + SequenceActivity branchSequence = (SequenceActivity) activityDAO.getActivityByActivityId(branchActivity + .getActivityId(), SequenceActivity.class); + Iterator entryIterator = branchSequence.getBranchEntries().iterator(); + while (entryIterator.hasNext()) { + BranchActivityEntry entry = entryIterator.next(); + if (entry.getCondition() != null) { + conditionsMap.put(entry.getCondition(), branchSequence); + } + } + } - // Go through each condition until we find one that passes and that is the required branch. - // Cache the tool output so that we aren't calling it over an over again. - Map toolOutputMap = new HashMap(); - Iterator conditionIterator = conditionsMap.keySet().iterator(); + // Go through each condition until we find one that passes and that is the required branch. + // Cache the tool output so that we aren't calling it over an over again. + Map toolOutputMap = new HashMap(); + Iterator conditionIterator = conditionsMap.keySet().iterator(); - while (matchedBranch == null && conditionIterator.hasNext()) { - BranchCondition condition = conditionIterator.next(); - String conditionName = condition.getName(); - ToolOutput toolOutput = toolOutputMap.get(conditionName); - if (toolOutput == null) { - toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, learner.getUserId()); - if (toolOutput == null) { - LearnerService.log.warn("Condition " + condition + " refers to a tool output " + conditionName - + " but tool doesn't return any tool output for that name. Skipping this condition."); - } - else { - toolOutputMap.put(conditionName, toolOutput); - } - } + while (matchedBranch == null && conditionIterator.hasNext()) { + BranchCondition condition = conditionIterator.next(); + String conditionName = condition.getName(); + ToolOutput toolOutput = toolOutputMap.get(conditionName); + if (toolOutput == null) { + toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, learner.getUserId()); + if (toolOutput == null) { + LearnerService.log.warn("Condition " + condition + " refers to a tool output " + conditionName + + " but tool doesn't return any tool output for that name. Skipping this condition."); + } else { + toolOutputMap.put(conditionName, toolOutput); + } + } - if (toolOutput != null && condition.isMet(toolOutput)) { - matchedBranch = conditionsMap.get(condition); - } - } + if (toolOutput != null && condition.isMet(toolOutput)) { + matchedBranch = conditionsMap.get(condition); } + } + } - // If no conditions match, use the branch that is the "default" branch for this branching activity. - if (matchedBranch != null) { - if (LearnerService.log.isDebugEnabled()) { - LearnerService.log.debug("Found branch " + matchedBranch.getActivityId() + ":" + matchedBranch.getTitle() - + " for branching activity " + branchingActivity.getActivityId() + ":" + branchingActivity.getTitle() - + " for learner " + learner.getUserId() + ":" + learner.getLogin()); - } - return matchedBranch; + // If no conditions match, use the branch that is the "default" branch for this branching activity. + if (matchedBranch != null) { + if (LearnerService.log.isDebugEnabled()) { + LearnerService.log.debug("Found branch " + matchedBranch.getActivityId() + ":" + + matchedBranch.getTitle() + " for branching activity " + branchingActivity.getActivityId() + + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + + learner.getLogin()); + } + return matchedBranch; - } - else if (defaultBranch != null) { - if (LearnerService.log.isDebugEnabled()) { - LearnerService.log.debug("Using default branch " + defaultBranch.getActivityId() + ":" + defaultBranch.getTitle() - + " for branching activity " + branchingActivity.getActivityId() + ":" + branchingActivity.getTitle() - + " for learner " + learner.getUserId() + ":" + learner.getLogin()); - } - // have to convert it to a real activity of the correct type, as it could be a cglib value - return (SequenceActivity) activityDAO.getActivityByActivityId(defaultBranch.getActivityId(), SequenceActivity.class); - } - else { - if (LearnerService.log.isDebugEnabled()) { - LearnerService.log - .debug("No branches match and no default branch exists. Uable to allocate learner to a branch for the branching activity" - + branchingActivity.getActivityId() - + ":" - + branchingActivity.getTitle() - + " for learner " - + learner.getUserId() + ":" + learner.getLogin()); - } - return null; - } + } else if (defaultBranch != null) { + if (LearnerService.log.isDebugEnabled()) { + LearnerService.log.debug("Using default branch " + defaultBranch.getActivityId() + ":" + + defaultBranch.getTitle() + " for branching activity " + branchingActivity.getActivityId() + + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + + learner.getLogin()); + } + // have to convert it to a real activity of the correct type, as it could be a cglib value + return (SequenceActivity) activityDAO.getActivityByActivityId(defaultBranch.getActivityId(), + SequenceActivity.class); + } else { + if (LearnerService.log.isDebugEnabled()) { + LearnerService.log + .debug("No branches match and no default branch exists. Uable to allocate learner to a branch for the branching activity" + + branchingActivity.getActivityId() + + ":" + + branchingActivity.getTitle() + + " for learner " + learner.getUserId() + ":" + learner.getLogin()); + } + return null; } + } - private SequenceActivity determineGroupBasedBranch(Lesson lesson, BranchingActivity branchingActivity, User learner) { - SequenceActivity sequenceActivity = null; + private SequenceActivity determineGroupBasedBranch(Lesson lesson, BranchingActivity branchingActivity, User learner) { + SequenceActivity sequenceActivity = null; - if (branchingActivity.getGrouping() != null) { - Grouping grouping = branchingActivity.getGrouping(); + if (branchingActivity.getGrouping() != null) { + Grouping grouping = branchingActivity.getGrouping(); - // If the user is in a group, then check if the group is assigned to a sequence activity. If it - // is then we are done and we return the sequence - Group group = grouping.getGroupBy(learner); - if (group != null) { - if (group.getBranchActivities() != null) { - Iterator branchesIterator = group.getBranchActivities().iterator(); - while (sequenceActivity == null && branchesIterator.hasNext()) { - BranchActivityEntry branchActivityEntry = (BranchActivityEntry) branchesIterator.next(); - if (branchActivityEntry.getBranchingActivity().equals(branchingActivity)) { - sequenceActivity = branchActivityEntry.getBranchSequenceActivity(); - } - } - } + // If the user is in a group, then check if the group is assigned to a sequence activity. If it + // is then we are done and we return the sequence + Group group = grouping.getGroupBy(learner); + if (group != null) { + if (group.getBranchActivities() != null) { + Iterator branchesIterator = group.getBranchActivities().iterator(); + while (sequenceActivity == null && branchesIterator.hasNext()) { + BranchActivityEntry branchActivityEntry = (BranchActivityEntry) branchesIterator.next(); + if (branchActivityEntry.getBranchingActivity().equals(branchingActivity)) { + sequenceActivity = branchActivityEntry.getBranchSequenceActivity(); } + } + } + } - if (sequenceActivity != null) { - if (LearnerService.log.isDebugEnabled()) { - LearnerService.log.debug("Found branch " + sequenceActivity.getActivityId() + ":" - + sequenceActivity.getTitle() + " for branching activity " + branchingActivity.getActivityId() + ":" - + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + learner.getLogin()); - } - } - + if (sequenceActivity != null) { + if (LearnerService.log.isDebugEnabled()) { + LearnerService.log.debug("Found branch " + sequenceActivity.getActivityId() + ":" + + sequenceActivity.getTitle() + " for branching activity " + + branchingActivity.getActivityId() + ":" + branchingActivity.getTitle() + " for learner " + + learner.getUserId() + ":" + learner.getLogin()); } + } - return sequenceActivity; } - /** - * Checks if any of the conditions that open the gate is met. - * @param gate gate to check - * @param learner learner who is knocking to the gate - * @return true if learner satisfied any of the conditions and is allowed to pass - */ - private boolean determineConditionGateStatus(GateActivity gate, User learner) { - boolean shouldOpenGate = false; - if (gate instanceof ConditionGateActivity) { - ConditionGateActivity conditionGate = (ConditionGateActivity) gate; + return sequenceActivity; + } - // Work out the tool session appropriate for this user and gate activity. We expect there to be only one at this point. - ToolSession toolSession = null; - for (Activity inputActivity : (Set) conditionGate.getInputActivities()) { - toolSession = lamsCoreToolService.getToolSessionByLearner(learner, inputActivity); - } + /** + * Checks if any of the conditions that open the gate is met. + * + * @param gate + * gate to check + * @param learner + * learner who is knocking to the gate + * @return true if learner satisfied any of the conditions and is allowed to pass + */ + private boolean determineConditionGateStatus(GateActivity gate, User learner) { + boolean shouldOpenGate = false; + if (gate instanceof ConditionGateActivity) { + ConditionGateActivity conditionGate = (ConditionGateActivity) gate; - if (toolSession != null) { + // Work out the tool session appropriate for this user and gate activity. We expect there to be only one at + // this point. + ToolSession toolSession = null; + for (Activity inputActivity : (Set) conditionGate.getInputActivities()) { + toolSession = lamsCoreToolService.getToolSessionByLearner(learner, inputActivity); + } - Set openingGateConditions = conditionGate.getOpeningGateBranchEntries(); + if (toolSession != null) { - // Go through each condition until we find one that passes and that opens the gate. - // Cache the tool output so that we aren't calling it over an over again. - Map toolOutputMap = new HashMap(); - Iterator conditionIterator = openingGateConditions.iterator(); + Set openingGateConditions = conditionGate.getOpeningGateBranchEntries(); - while (!shouldOpenGate && conditionIterator.hasNext()) { - BranchCondition condition = conditionIterator.next().getCondition(); - String conditionName = condition.getName(); - ToolOutput toolOutput = toolOutputMap.get(conditionName); - if (toolOutput == null) { - toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, learner.getUserId()); - if (toolOutput == null) { - LearnerService.log.warn("Condition " + condition + " refers to a tool output " + conditionName - + " but tool doesn't return any tool output for that name. Skipping this condition."); - } - else { - toolOutputMap.put(conditionName, toolOutput); - } - } + // Go through each condition until we find one that passes and that opens the gate. + // Cache the tool output so that we aren't calling it over an over again. + Map toolOutputMap = new HashMap(); + Iterator conditionIterator = openingGateConditions.iterator(); - if (toolOutput != null && condition.isMet(toolOutput)) { - shouldOpenGate = true; - //save the learner to the "allowed to pass" list so we don't check the conditions over and over again (maybe we should??) - conditionGate.addLeaner(learner, true); - } - } + while (!shouldOpenGate && conditionIterator.hasNext()) { + BranchCondition condition = conditionIterator.next().getCondition(); + String conditionName = condition.getName(); + ToolOutput toolOutput = toolOutputMap.get(conditionName); + if (toolOutput == null) { + toolOutput = lamsCoreToolService.getOutputFromTool(conditionName, toolSession, learner + .getUserId()); + if (toolOutput == null) { + LearnerService.log + .warn("Condition " + + condition + + " refers to a tool output " + + conditionName + + " but tool doesn't return any tool output for that name. Skipping this condition."); + } else { + toolOutputMap.put(conditionName, toolOutput); } + } + + if (toolOutput != null && condition.isMet(toolOutput)) { + shouldOpenGate = true; + // save the learner to the "allowed to pass" list so we don't check the conditions over and over + // again (maybe we should??) + conditionGate.addLeaner(learner, true); + } } - return shouldOpenGate; + } } + return shouldOpenGate; + } - /** - * Select a particular branch - we are in preview mode and the author has selected a particular activity. - * - * @throws LearnerServiceException - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#determineBranch(org.lamsfoundation.lams.lesson.Lesson, org.lamsfoundation.lams.learningdesign.BranchingActivity, java.lang.Integer) - */ - public SequenceActivity selectBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId, Long branchId) - throws LearnerServiceException { + /** + * Select a particular branch - we are in preview mode and the author has selected a particular activity. + * + * @throws LearnerServiceException + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#determineBranch(org.lamsfoundation.lams.lesson.Lesson, + * org.lamsfoundation.lams.learningdesign.BranchingActivity, java.lang.Integer) + */ + public SequenceActivity selectBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId, + Long branchId) throws LearnerServiceException { - User learner = (User) userManagementService.findById(User.class, learnerId); - if (learner == null) { - String error = "selectBranch: learner " + learnerId + " does not exist. Cannot determine branch."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } + User learner = (User) userManagementService.findById(User.class, learnerId); + if (learner == null) { + String error = "selectBranch: learner " + learnerId + " does not exist. Cannot determine branch."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } - SequenceActivity selectedBranch = (SequenceActivity) activityDAO - .getActivityByActivityId(branchId, SequenceActivity.class); - if (selectedBranch != null) { + SequenceActivity selectedBranch = (SequenceActivity) activityDAO.getActivityByActivityId(branchId, + SequenceActivity.class); + if (selectedBranch != null) { - if (selectedBranch.getParentActivity() == null || !selectedBranch.getParentActivity().equals(branchingActivity)) { - String error = "selectBranch: activity " + selectedBranch + " is not a branch within the branching activity " - + branchingActivity + ". Unable to branch."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } + if (selectedBranch.getParentActivity() == null + || !selectedBranch.getParentActivity().equals(branchingActivity)) { + String error = "selectBranch: activity " + selectedBranch + + " is not a branch within the branching activity " + branchingActivity + ". Unable to branch."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } - Set groups = selectedBranch.getGroupsForBranch(); - Grouping grouping = branchingActivity.getGrouping(); + Set groups = selectedBranch.getGroupsForBranch(); + Grouping grouping = branchingActivity.getGrouping(); - // Does this matching branch have any groups? If so, see if the learner is in - // the appropriate group and add them if necessary. - if (groups != null && groups.size() > 0) { - boolean isInGroup = false; - Group aGroup = null; - Iterator groupIter = groups.iterator(); - while (!isInGroup && groupIter.hasNext()) { - aGroup = groupIter.next(); - isInGroup = aGroup.hasLearner(learner); - } + // Does this matching branch have any groups? If so, see if the learner is in + // the appropriate group and add them if necessary. + if (groups != null && groups.size() > 0) { + boolean isInGroup = false; + Group aGroup = null; + Iterator groupIter = groups.iterator(); + while (!isInGroup && groupIter.hasNext()) { + aGroup = groupIter.next(); + isInGroup = aGroup.hasLearner(learner); + } - // If the learner is not in the appropriate group, then force the learner in the - // last group we checked. this will only work if the user is in preview. - if (!isInGroup) { - if (!forceGrouping(lesson, grouping, aGroup, learner)) { - String error = "selectBranch: learner " + learnerId + " cannot be added to the group " + aGroup - + " for the branch " + selectedBranch + " for the lesson " + lesson.getLessonName() - + " preview is " + lesson.isPreviewLesson() + ". This will only work if preview is true."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } - } + // If the learner is not in the appropriate group, then force the learner in the + // last group we checked. this will only work if the user is in preview. + if (!isInGroup) { + if (!forceGrouping(lesson, grouping, aGroup, learner)) { + String error = "selectBranch: learner " + learnerId + " cannot be added to the group " + aGroup + + " for the branch " + selectedBranch + " for the lesson " + lesson.getLessonName() + + " preview is " + lesson.isPreviewLesson() + + ". This will only work if preview is true."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } + } - // if no matching groups exist (just to Define in Monitor), then create one and assign it to the branch. - // if it is a chosen grouping, make sure we allow it to go over the normal number of groups (the real groups will exist - // but it too hard to reuse them.) - } - else { - if (grouping.isChosenGrouping() && grouping.getMaxNumberOfGroups() != null) { - grouping.setMaxNumberOfGroups(null); - } + // if no matching groups exist (just to Define in Monitor), then create one and assign it to the branch. + // if it is a chosen grouping, make sure we allow it to go over the normal number of groups (the real + // groups will exist + // but it too hard to reuse them.) + } else { + if (grouping.isChosenGrouping() && grouping.getMaxNumberOfGroups() != null) { + grouping.setMaxNumberOfGroups(null); + } - Group group = lessonService.createGroup(grouping, selectedBranch.getTitle()); - group.allocateBranchToGroup(null, selectedBranch, branchingActivity); - if (!forceGrouping(lesson, grouping, group, learner)) { - String error = "selectBranch: learner " + learnerId + " cannot be added to the group " + group - + " for the branch " + selectedBranch + " for the lesson " + lesson.getLessonName() + " preview is " - + lesson.isPreviewLesson() + ". This will only work if preview is true."; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } - } - groupingDAO.update(grouping); + Group group = lessonService.createGroup(grouping, selectedBranch.getTitle()); + group.allocateBranchToGroup(null, selectedBranch, branchingActivity); + if (!forceGrouping(lesson, grouping, group, learner)) { + String error = "selectBranch: learner " + learnerId + " cannot be added to the group " + group + + " for the branch " + selectedBranch + " for the lesson " + lesson.getLessonName() + + " preview is " + lesson.isPreviewLesson() + ". This will only work if preview is true."; + LearnerService.log.error(error); + throw new LearnerServiceException(error); + } + } + groupingDAO.update(grouping); - if (LearnerService.log.isDebugEnabled()) { - LearnerService.log.debug("Found branch " + selectedBranch.getActivityId() + ":" + selectedBranch.getTitle() - + " for branching activity " + branchingActivity.getActivityId() + ":" + branchingActivity.getTitle() - + " for learner " + learner.getUserId() + ":" + learner.getLogin()); - } + if (LearnerService.log.isDebugEnabled()) { + LearnerService.log.debug("Found branch " + selectedBranch.getActivityId() + ":" + + selectedBranch.getTitle() + " for branching activity " + branchingActivity.getActivityId() + + ":" + branchingActivity.getTitle() + " for learner " + learner.getUserId() + ":" + + learner.getLogin()); + } - return selectedBranch; + return selectedBranch; - } - else { - String error = "selectBranch: Unable to find branch for branch id " + branchId; - LearnerService.log.error(error); - throw new LearnerServiceException(error); - } - + } else { + String error = "selectBranch: Unable to find branch for branch id " + branchId; + LearnerService.log.error(error); + throw new LearnerServiceException(error); } - public ProgressEngine getProgressEngine() { - return progressEngine; - } + } - public void setProgressEngine(ProgressEngine progressEngine) { - this.progressEngine = progressEngine; - } + public ProgressEngine getProgressEngine() { + return progressEngine; + } - /** - * {@inheritDoc} - */ - public Integer calculateMaxNumberOfLearnersPerGroup(Long lessonId, Long groupingId) { - Lesson lesson = getLesson(lessonId); - LearnerChoiceGrouping grouping = (LearnerChoiceGrouping) groupingDAO.getGroupingById(groupingId); - Integer maxNumberOfLearnersPerGroup = null; - int learnerCount = lesson.getAllLearners().size(); - int groupCount = grouping.getGroups().size(); - if (grouping.getLearnersPerGroup() == null) { - if (groupCount == 0) { - ((LearnerChoiceGrouper) grouping.getGrouper()).createGroups(grouping, 2); - groupCount = grouping.getGroups().size(); - groupingDAO.update(grouping); - } - if (grouping.getEqualNumberOfLearnersPerGroup()) { - maxNumberOfLearnersPerGroup = learnerCount / groupCount + (learnerCount % groupCount == 0 ? 0 : 1); - } - } - else { - maxNumberOfLearnersPerGroup = grouping.getLearnersPerGroup(); - int desiredGroupCount = learnerCount / maxNumberOfLearnersPerGroup - + (learnerCount % maxNumberOfLearnersPerGroup == 0 ? 0 : 1); - if (desiredGroupCount > groupCount) { - ((LearnerChoiceGrouper) grouping.getGrouper()).createGroups(grouping, desiredGroupCount - groupCount); - groupingDAO.update(grouping); - } - } - return maxNumberOfLearnersPerGroup; + public void setProgressEngine(ProgressEngine progressEngine) { + this.progressEngine = progressEngine; + } + + /** + * {@inheritDoc} + */ + public Integer calculateMaxNumberOfLearnersPerGroup(Long lessonId, Long groupingId) { + Lesson lesson = getLesson(lessonId); + LearnerChoiceGrouping grouping = (LearnerChoiceGrouping) groupingDAO.getGroupingById(groupingId); + Integer maxNumberOfLearnersPerGroup = null; + int learnerCount = lesson.getAllLearners().size(); + int groupCount = grouping.getGroups().size(); + if (grouping.getLearnersPerGroup() == null) { + if (groupCount == 0) { + ((LearnerChoiceGrouper) grouping.getGrouper()).createGroups(grouping, 2); + groupCount = grouping.getGroups().size(); + groupingDAO.update(grouping); + } + if (grouping.getEqualNumberOfLearnersPerGroup()) { + maxNumberOfLearnersPerGroup = learnerCount / groupCount + (learnerCount % groupCount == 0 ? 0 : 1); + } + } else { + maxNumberOfLearnersPerGroup = grouping.getLearnersPerGroup(); + int desiredGroupCount = learnerCount / maxNumberOfLearnersPerGroup + + (learnerCount % maxNumberOfLearnersPerGroup == 0 ? 0 : 1); + if (desiredGroupCount > groupCount) { + ((LearnerChoiceGrouper) grouping.getGrouper()).createGroups(grouping, desiredGroupCount - groupCount); + groupingDAO.update(grouping); + } } + return maxNumberOfLearnersPerGroup; + } }