Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r33a5ad24fad4e3e2d3d8f0c67d88ccb5167affe7 -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d Binary files differ Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java =================================================================== diff -u -rb298c498f26d7e881bc2a2064d62988c51be3b1a -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java (.../ILearnerProgressDAO.java) (revision b298c498f26d7e881bc2a2064d62988c51be3b1a) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java (.../ILearnerProgressDAO.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -54,7 +54,7 @@ * the lesson for which the progress data applies * @return the user's progress data */ - LearnerProgress getLearnerProgressByLearner(final Integer learnerId, final Long lessonId); + LearnerProgress getLearnerProgressByLearner(Integer learnerId, Long lessonId); /** * Saves or Updates learner progress data. @@ -84,40 +84,56 @@ * @param activity * @return List */ - List getLearnerProgressReferringToActivity(final Activity activity); + List getLearnerProgressReferringToActivity(Activity activity); /** + * Get progress for learners who most recently entered the activity. + */ + List getLearnerProgressLatestByActivity(Long activityId, Integer limit); + + /** + * Get progress for learners who are at the activity at the moment. + */ + List getLearnerProgressByActivity(Long activityId, Integer limit, Integer offset); + + /** + * Get progress for learners who most recently finished the lesson. + */ + List getCompletedLearnerProgressLatestForLesson(Long lessonId, Integer limit); + + /** * Get all the learner progress records for a lesson where the progress is marked as completed. * * @param lessonId * @return List */ - List getCompletedLearnerProgressForLesson(final Long lessonId); - + List getCompletedLearnerProgressForLesson(Long lessonId); + /** * Get all the learner progress records for a lesson. * * @param lessonId * @return */ - List getLearnerProgressForLesson(final Long lessonId); - + List getLearnerProgressForLesson(Long lessonId); + /** * Get all the learner progress records for a lesson restricted by list of these user ids. * * @param lessonId - * @param userIds return progresses for only these users + * @param userIds + * return progresses for only these users * @return */ - List getLearnerProgressForLesson(final Long lessonId, final List userIds); - + List getLearnerProgressForLesson(Long lessonId, List userIds); + /** * Get all the learner progresses for a lesson list. * * @param lessonIds * @return */ - List getLearnerProgressForLessons(final List lessonIds); + List getLearnerProgressForLessons(List lessonIds); /** * Get all the users records where the user has attempted the given activity. Uses the progress records to determine @@ -126,25 +142,16 @@ * @param activityId * @return List */ - List getLearnersHaveAttemptedActivity(final Activity activity); + List getLearnersHaveAttemptedActivity(Activity activity); /** - * Get all the users records where the user has completed the given activity. Uses the progress records to determine - * the users. - * - * @param activityId - * @return List - */ - List getLearnersHaveCompletedActivity(final Activity activity); - - /** * Count of the number of users that have attempted or completed an activity. Useful for activities that don't have * tool sessions. * * @param activityId * @return List */ - Integer getNumUsersAttemptedActivity(final Activity activity); + Integer getNumUsersAttemptedActivity(Activity activity); /** * Count of the number of users that have completed an activity. Useful for activities that don't have tool @@ -153,24 +160,15 @@ * @param activityId * @return List */ - Integer getNumUsersCompletedActivity(final Activity activity); + Integer getNumUsersCompletedActivity(Activity activity); /** - * Get the count of all learner progress records for an lesson without loading the records. - * - * @return Number of learner progress records for this lesson + * Get number of learners who finished the given lesson. */ - Integer getNumAllLearnerProgress(final Long lessonId); + Integer getNumUsersCompletedLesson(Long lessonId); /** - * Get a batch of learner progress records (size batchSize) for an lesson, sorted by surname and the first name. - * Start at the beginning of the table if no previousUserId is given, otherwise get the batch after lastUserId. - * - * @param lessonId - * @param lastUserId - * @param batchSize - * @return List + * Get number of learners who are at the given activity at the moment. */ - List getBatchLearnerProgress(final Long lessonId, final User lastUser, final int batchSize); - + Integer getNumUsersCurrentActivity(Activity activity); } Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java =================================================================== diff -u -rb298c498f26d7e881bc2a2064d62988c51be3b1a -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java (.../LearnerProgressDAO.java) (revision b298c498f26d7e881bc2a2064d62988c51be3b1a) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java (.../LearnerProgressDAO.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -23,10 +23,13 @@ /* $$Id$$ */ package org.lamsfoundation.lams.lesson.dao.hibernate; +import java.math.BigInteger; +import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; import org.hibernate.HibernateException; +import org.hibernate.Query; import org.hibernate.Session; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.lesson.LearnerProgress; @@ -46,37 +49,44 @@ protected Logger log = Logger.getLogger(LearnerProgressDAO.class); private final static String LOAD_PROGRESS_BY_LEARNER = "from LearnerProgress p where p.user.id = :learnerId and p.lesson.id = :lessonId"; - - private final static String LOAD_PROGRESS_BY_ACTIVITY = "from LearnerProgress p where p.previousActivity = :activity or p.currentActivity = :activity or p.nextActivity = :activity "; - // + - // "or activity in elements(p.previousActivity) or activity in elements(p.completedActivities)"; + + private final static String LOAD_PROGRESS_REFFERING_TO_ACTIVITY = "from LearnerProgress p where p.previousActivity = :activity or p.currentActivity = :activity or p.nextActivity = :activity "; + private final static String LOAD_COMPLETED_PROGRESS_BY_LESSON = "from LearnerProgress p where p.lessonComplete > 0 and p.lesson.id = :lessonId"; + private final static String LOAD_LATEST_COMPLETED_PROGRESS_BY_LESSON = "from LearnerProgress p where p.lessonComplete > 0 and p.lesson.id = :lessonId ORDER BY p.finishDate DESC"; + + private final static String COUNT_COMPLETED_PROGRESS_BY_LESSON = "select count(*) from LearnerProgress p " + + " where p.lessonComplete > 0 and p.lesson.id = :lessonId"; + private final static String COUNT_ATTEMPTED_ACTIVITY = "select count(*) from LearnerProgress prog, " + " Activity act join prog.attemptedActivities attAct " + " where act.id = :activityId and " + " index(attAct) = act"; - + private final static String COUNT_COMPLETED_ACTIVITY = "select count(*) from LearnerProgress prog, " + " Activity act join prog.completedActivities compAct " + " where act.id = :activityId and " + " index(compAct) = act"; - private final static String COUNT_PROGRESS_BY_LESSON = "select count(*) from LearnerProgress p where p.lesson.id = :lessonId"; - + private final static String COUNT_CURRENT_ACTIVITY = "select count(*) from LearnerProgress prog WHERE " + + " prog.currentActivity = :activity"; + private final static String LOAD_PROGRESS_BY_LESSON = "from LearnerProgress p " + " where p.lesson.id = :lessonId order by p.user.lastName, p.user.firstName, p.user.userId"; - + private final static String LOAD_PROGRESS_BY_LESSON_AND_USER_IDS = "from LearnerProgress p " + " where p.lesson.id = :lessonId AND p.user.userId IN (:userIds) order by p.user.lastName, p.user.firstName, p.user.userId"; - private final String LOAD_PROGRESSES_BY_LESSON_LIST = "FROM LearnerProgress progress WHERE " + private final static String LOAD_PROGRESSES_BY_LESSON_LIST = "FROM LearnerProgress progress WHERE " + " progress.lesson.lessonId IN (:lessonIds)"; - - private final static String LOAD_NEXT_BATCH_PROGRESS_BY_LESSON = "from LearnerProgress p where p.lesson.id = :lessonId " - + " and (( p.user.lastName > :lastUserLastName)" - + " or ( p.user.lastName = :lastUserLastName and p.user.firstName > :lastUserFirstName) " - + " or ( p.user.lastName = :lastUserLastName and p.user.firstName = :lastUserFirstName and p.user.userId > :lastUserId))" - + " order by p.user.lastName, p.user.firstName, p.user.userId"; + private final static String LOAD_LATEST_PROGRESS_BY_ACTIVITY = "SELECT prog.learner_progress_id FROM lams_learner_progress AS prog " + + "JOIN lams_progress_attempted AS att USING (learner_progress_id) " + + "WHERE prog.current_activity_id = :activityId AND att.activity_id = :activityId " + + "ORDER BY att.start_date_time DESC"; + + private final static String LOAD_PROGRESS_BY_ACTIVITY = "FROM LearnerProgress p WHERE " + + " p.currentActivity.id = :activityId"; + @Override public LearnerProgress getLearnerProgress(Long learnerProgressId) { return (LearnerProgress) getHibernateTemplate().get(LearnerProgress.class, learnerProgressId); @@ -97,9 +107,10 @@ HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); return (LearnerProgress) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_PROGRESS_BY_LEARNER).setInteger("learnerId", learnerId) - .setLong("lessonId", lessonId).uniqueResult(); + return session.createQuery(LearnerProgressDAO.LOAD_PROGRESS_BY_LEARNER) + .setInteger("learnerId", learnerId).setLong("lessonId", lessonId).uniqueResult(); } }); } @@ -109,58 +120,135 @@ this.getHibernateTemplate().update(learnerProgress); } + @SuppressWarnings("unchecked") @Override - public List getLearnerProgressReferringToActivity(final Activity activity) { + public List getLearnerProgressReferringToActivity(final Activity activity) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); - return (List) hibernateTemplate.execute(new HibernateCallback() { + return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_PROGRESS_BY_ACTIVITY).setEntity("activity", activity).list(); + return session.createQuery(LearnerProgressDAO.LOAD_PROGRESS_REFFERING_TO_ACTIVITY) + .setEntity("activity", activity).list(); } }); } + @SuppressWarnings("unchecked") @Override - public List getCompletedLearnerProgressForLesson(final Long lessonId) { + public List getLearnerProgressLatestByActivity(final Long activityId, final Integer limit) { + final HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); + + return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + Query query = session.createSQLQuery(LearnerProgressDAO.LOAD_LATEST_PROGRESS_BY_ACTIVITY) + .setLong("activityId", activityId); + if (limit != null) { + query.setMaxResults(limit); + } + // first query fetches only progress IDs + List result = query.list(); + // fetch Learner progress objects and return them + List learnerProgresses = new LinkedList(); + for (BigInteger learnerProgressId : result) { + learnerProgresses.add((LearnerProgress) hibernateTemplate.get(LearnerProgress.class, + learnerProgressId.longValue())); + } + return learnerProgresses; + } + }); + } + + @SuppressWarnings("unchecked") + @Override + public List getLearnerProgressByActivity(final Long activityId, final Integer limit, + final Integer offset) { + final HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); + + return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + Query query = session.createQuery(LearnerProgressDAO.LOAD_PROGRESS_BY_ACTIVITY).setLong("activityId", + activityId); + if (limit != null) { + query.setMaxResults(limit); + } + if (offset != null) { + query.setFirstResult(offset); + } + return query.list(); + } + }); + } + + @SuppressWarnings("unchecked") + @Override + public List getCompletedLearnerProgressLatestForLesson(final Long lessonId, final Integer limit) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); - return (List) hibernateTemplate.execute(new HibernateCallback() { + return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_COMPLETED_PROGRESS_BY_LESSON).setLong("lessonId", lessonId).list(); + Query query = session.createQuery(LearnerProgressDAO.LOAD_LATEST_COMPLETED_PROGRESS_BY_LESSON) + .setLong("lessonId", lessonId); + if (limit != null) { + query.setMaxResults(limit); + } + return query.list(); } }); } - + + @SuppressWarnings("unchecked") @Override + public List getCompletedLearnerProgressForLesson(final Long lessonId) { + HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); + + return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + return session.createQuery(LearnerProgressDAO.LOAD_COMPLETED_PROGRESS_BY_LESSON) + .setLong("lessonId", lessonId).list(); + } + }); + } + + @Override public List getLearnerProgressForLesson(final Long lessonId) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_PROGRESS_BY_LESSON).setLong("lessonId", lessonId).list(); + return session.createQuery(LearnerProgressDAO.LOAD_PROGRESS_BY_LESSON).setLong("lessonId", lessonId) + .list(); } }); } - + @Override public List getLearnerProgressForLesson(final Long lessonId, final List userIds) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_PROGRESS_BY_LESSON_AND_USER_IDS).setLong("lessonId", lessonId) - .setParameterList("userIds", userIds).list(); + return session.createQuery(LearnerProgressDAO.LOAD_PROGRESS_BY_LESSON_AND_USER_IDS) + .setLong("lessonId", lessonId).setParameterList("userIds", userIds).list(); } }); } - + + @SuppressWarnings("unchecked") @Override public List getLearnerProgressForLessons(final List lessonIds) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); return (List) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_PROGRESSES_BY_LESSON_LIST) + return session.createQuery(LearnerProgressDAO.LOAD_PROGRESSES_BY_LESSON_LIST) .setParameterList("lessonIds", lessonIds).list(); } }); @@ -173,6 +261,7 @@ HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); learners = (List) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { return session.getNamedQuery("usersAttemptedActivity") .setLong("activityId", activity.getActivityId().longValue()).list(); @@ -186,8 +275,9 @@ public Integer getNumUsersAttemptedActivity(final Activity activity) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); Integer attempted = (Integer) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - Object value = session.createQuery(COUNT_ATTEMPTED_ACTIVITY) + Object value = session.createQuery(LearnerProgressDAO.COUNT_ATTEMPTED_ACTIVITY) .setLong("activityId", activity.getActivityId().longValue()).uniqueResult(); return new Integer(((Number) value).intValue()); } @@ -196,70 +286,41 @@ } @Override - @SuppressWarnings("unchecked") - public List getLearnersHaveCompletedActivity(final Activity activity) { - List learners = null; - + public Integer getNumUsersCompletedActivity(final Activity activity) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); - learners = (List) hibernateTemplate.execute(new HibernateCallback() { + return (Integer) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - return session.getNamedQuery("usersCompletedActivity") - .setLong("activityId", activity.getActivityId().longValue()).list(); + Object value = session.createQuery(LearnerProgressDAO.COUNT_COMPLETED_ACTIVITY) + .setLong("activityId", activity.getActivityId().longValue()).uniqueResult(); + return new Integer(((Number) value).intValue()); } }); - - return learners; } @Override - public Integer getNumUsersCompletedActivity(final Activity activity) { + public Integer getNumUsersCompletedLesson(final Long lessonId) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); return (Integer) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - Object value = session.createQuery(COUNT_COMPLETED_ACTIVITY) - .setLong("activityId", activity.getActivityId().longValue()).uniqueResult(); - return new Integer(((Number) value).intValue()); + Object value = session.createQuery(LearnerProgressDAO.COUNT_COMPLETED_PROGRESS_BY_LESSON) + .setLong("lessonId", lessonId).uniqueResult(); + return ((Number) value).intValue(); } }); } @Override - public Integer getNumAllLearnerProgress(final Long lessonId) { + public Integer getNumUsersCurrentActivity(final Activity activity) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); return (Integer) hibernateTemplate.execute(new HibernateCallback() { + @Override public Object doInHibernate(Session session) throws HibernateException { - Object value = session.createQuery(COUNT_PROGRESS_BY_LESSON).setLong("lessonId", lessonId.longValue()) - .uniqueResult(); - return new Integer(((Number) value).intValue()); + Object value = session.createQuery(LearnerProgressDAO.COUNT_CURRENT_ACTIVITY) + .setEntity("activity", activity).uniqueResult(); + return ((Number) value).intValue(); } }); } - - @Override - @SuppressWarnings("unchecked") - public List getBatchLearnerProgress(final Long lessonId, final User lastUser, final int batchSize) { - HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); - - if (lastUser == null) { - return (List) hibernateTemplate.execute(new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_PROGRESS_BY_LESSON) - .setLong("lessonId", lessonId.longValue()) - .setMaxResults(batchSize).list(); - } - }); - - } else { - return (List) hibernateTemplate.execute(new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException { - return session.createQuery(LOAD_NEXT_BATCH_PROGRESS_BY_LESSON) - .setLong("lessonId", lessonId.longValue()) - .setString("lastUserLastName", lastUser.getLastName()) - .setString("lastUserFirstName", lastUser.getFirstName()) - .setInteger("lastUserId", lastUser.getUserId().intValue()).setMaxResults(batchSize).list(); - } - }); - } - } - -} +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java =================================================================== diff -u -rb298c498f26d7e881bc2a2064d62988c51be3b1a -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision b298c498f26d7e881bc2a2064d62988c51be3b1a) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -316,27 +316,13 @@ List getLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException; /** - * Get the list of users who have completed an activity. This is based on the progress engine records. This will - * give the users in all tool sessions for an activity (if it is a tool activity) or it will give all the users who - * have attempted an activity that doesn't have any tool sessions, i.e. system activities such as branching. - */ - List getLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException; - - /** * Gets the count of the users who have attempted an activity. This is based on the progress engine records. This * will work on all activities, including ones that don't have any tool sessions, i.e. system activities such as * branching. */ Integer getCountLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException; /** - * Gets the count of the users who have completed an activity. This is based on the progress engine records. This - * will work on all activities, including ones that don't have any tool sessions, i.e. system activities such as - * branching. - */ - Integer getCountLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException; - - /** * Returns map of lessons in an organisation for a particular learner or staff user. * * @param userId Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java =================================================================== diff -u -rb298c498f26d7e881bc2a2064d62988c51be3b1a -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision b298c498f26d7e881bc2a2064d62988c51be3b1a) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -308,13 +308,14 @@ public boolean addLearner(Long lessonId, Integer userId) throws LessonServiceException { Lesson lesson = lessonDAO.getLesson(lessonId); if (lesson == null) { - throw new LessonServiceException("Lesson " + lessonId + " does not exist. Unable to add learner to lesson."); + throw new LessonServiceException( + "Lesson " + lessonId + " does not exist. Unable to add learner to lesson."); } LessonClass lessonClass = lesson.getLessonClass(); if (lessonClass == null) { - throw new LessonServiceException("Lesson class for " + lessonId - + " does not exist. Unable to add learner to lesson."); + throw new LessonServiceException( + "Lesson class for " + lessonId + " does not exist. Unable to add learner to lesson."); } // initialise the lesson group, or we get a lazy loading error when logging in @@ -338,12 +339,13 @@ Lesson lesson = lessonDAO.getLesson(lessonId); if (lesson == null) { - throw new LessonServiceException("Lesson " + lessonId + " does not exist. Unable to add learner to lesson."); + throw new LessonServiceException( + "Lesson " + lessonId + " does not exist. Unable to add learner to lesson."); } LessonClass lessonClass = lesson.getLessonClass(); if (lessonClass == null) { - throw new LessonServiceException("Lesson class for " + lessonId - + " does not exist. Unable to add learner to lesson."); + throw new LessonServiceException( + "Lesson class for " + lessonId + " does not exist. Unable to add learner to lesson."); } // initialise the lesson group, or we might get a lazy loading error in the future @@ -381,24 +383,24 @@ int numberOfLearners = lessonClass.setLearners(users); lessonClassDAO.updateLessonClass(lessonClass); if (LessonService.log.isDebugEnabled()) { - LessonService.log.debug("Set " + numberOfLearners + " learners in lessonClass " - + lessonClass.getGroupingId()); + LessonService.log + .debug("Set " + numberOfLearners + " learners in lessonClass " + lessonClass.getGroupingId()); } } @Override public boolean addStaffMember(Long lessonId, Integer userId) { Lesson lesson = lessonDAO.getLesson(lessonId); if (lesson == null) { - throw new LessonServiceException("Lesson " + lessonId - + " does not exist. Unable to add staff member to lesson."); + throw new LessonServiceException( + "Lesson " + lessonId + " does not exist. Unable to add staff member to lesson."); } LessonClass lessonClass = lesson.getLessonClass(); if (lessonClass == null) { - throw new LessonServiceException("Lesson class for " + lessonId - + " does not exist. Unable to add staff member to lesson."); + throw new LessonServiceException( + "Lesson class for " + lessonId + " does not exist. Unable to add staff member to lesson."); } lessonDAO.initialize(lessonClass.getStaffGroup()); @@ -416,12 +418,13 @@ Lesson lesson = lessonDAO.getLesson(lessonId); if (lesson == null) { - throw new LessonServiceException("Lesson " + lessonId + " does not exist. Unable to add learner to lesson."); + throw new LessonServiceException( + "Lesson " + lessonId + " does not exist. Unable to add learner to lesson."); } LessonClass lessonClass = lesson.getLessonClass(); if (lessonClass == null) { - throw new LessonServiceException("Lesson class for " + lessonId - + " does not exist. Unable to add learner to lesson."); + throw new LessonServiceException( + "Lesson class for " + lessonId + " does not exist. Unable to add learner to lesson."); } // initialise the lesson group, or we might get a lazy loading error in the future @@ -446,8 +449,8 @@ lessonClassDAO.updateLessonClass(lessonClass); } if (LessonService.log.isDebugEnabled()) { - LessonService.log.debug("Added " + numAdded + " staff members to lessonClass " - + lessonClass.getGroupingId()); + LessonService.log + .debug("Added " + numAdded + " staff members to lessonClass " + lessonClass.getGroupingId()); } } @@ -458,8 +461,8 @@ int numberOfStaff = lessonClass.setStaffMembers(users); lessonClassDAO.updateLessonClass(lessonClass); if (LessonService.log.isDebugEnabled()) { - LessonService.log.debug("Set " + numberOfStaff + " staff members in lessonClass " - + lessonClass.getGroupingId()); + LessonService.log + .debug("Set " + numberOfStaff + " staff members in lessonClass " + lessonClass.getGroupingId()); } } @@ -561,21 +564,11 @@ } @Override - public List getLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException { - return learnerProgressDAO.getLearnersHaveCompletedActivity(activity); - } - - @Override public Integer getCountLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException { return learnerProgressDAO.getNumUsersAttemptedActivity(activity); } @Override - public Integer getCountLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException { - return learnerProgressDAO.getNumUsersCompletedActivity(activity); - } - - @Override public Map getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, Integer userRole) { TreeMap map = new TreeMap(); @@ -591,8 +584,8 @@ Boolean lessonCompleted = (Boolean) tuple[4]; lessonCompleted = lessonCompleted == null ? false : lessonCompleted.booleanValue(); Boolean enableLessonNotifications = (Boolean) tuple[5]; - enableLessonNotifications = enableLessonNotifications == null ? false : enableLessonNotifications - .booleanValue(); + enableLessonNotifications = enableLessonNotifications == null ? false + : enableLessonNotifications.booleanValue(); Boolean dependent = (Boolean) tuple[6]; dependent = dependent == null ? false : dependent.booleanValue(); Boolean scheduledFinish = (Boolean) tuple[7]; Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java =================================================================== diff -u -r5bead427a3cb053b6fb1f5cb506da28a1f9a9e70 -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java (.../ICoreLearnerService.java) (revision 5bead427a3cb053b6fb1f5cb506da28a1f9a9e70) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java (.../ICoreLearnerService.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -243,12 +243,6 @@ public List getActiveLearnersByLesson(long lessonId); /** - * Returns a count of all the active learners by lesson id. More efficient than calling - * getActiveLearnersByLesson(lessonId).size() - */ - public Integer getCountActiveLearnersByLesson(long lessonId); - - /** * Perform grouping for the learners who have started the lesson, based on the grouping activity. * * @param lessonId Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -r5bead427a3cb053b6fb1f5cb506da28a1f9a9e70 -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 5bead427a3cb053b6fb1f5cb506da28a1f9a9e70) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -997,14 +997,6 @@ } /** - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getCountActiveLessonLearners(long) - */ - @Override - 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. */ Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java =================================================================== diff -u -r27f1c5a7f08417a5d6f5e4c7faff092f520078a6 -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java (.../IMonitoringService.java) (revision 27f1c5a7f08417a5d6f5e4c7faff092f520078a6) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java (.../IMonitoringService.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -70,8 +70,9 @@ * Create new lesson according to the learning design specified by the user. This involves following major steps: *

* - *
  • 1. Make a runtime copy of static learning design defined in authoring
  • 2. Go through all the tool - * activities defined in the learning design, create a runtime copy of all tool's content.
  • + *
  • 1. Make a runtime copy of static learning design defined in authoring
  • + *
  • 2. Go through all the tool activities defined in the learning design, create a runtime copy of all tool's + * content.
  • * *

    * As a runtime design, it is not copied into any folder. @@ -162,7 +163,7 @@ */ Lesson createLessonClassForLesson(long lessonId, Organisation organisation, String learnerGroupName, List organizationUsers, String staffGroupName, List staffs, Integer userID) - throws UserAccessDeniedException; + throws UserAccessDeniedException; /** * Start the specified the lesson. It must be created before calling this service. @@ -188,8 +189,9 @@ * Runs the system scheduler to start the scheduling for opening gate and closing gate. It invlovs a couple of steps * to start the scheduler: *

    - *
  • 1. Initialize the resource needed by scheduling job by setting them into the job data map.
  • 2. Create - * customized triggers for the scheduling.
  • 3. start the scheduling job
  • + *
  • 1. Initialize the resource needed by scheduling job by setting them into the job data map.
  • + *
  • 2. Create customized triggers for the scheduling.
  • + *
  • 3. start the scheduling job
  • * * @param scheduleGate * the gate that needs to be scheduled. @@ -200,7 +202,8 @@ * the name lesson incorporating this gate - used for the description of the Quartz job. Optional. * @returns An updated gate, that should be saved by the calling code. */ - ScheduleGateActivity runGateScheduler(ScheduleGateActivity scheduleGate, Date schedulingStartTime, String lessonName); + ScheduleGateActivity runGateScheduler(ScheduleGateActivity scheduleGate, Date schedulingStartTime, + String lessonName); /** * Start a lesson on scheduled datetime. @@ -678,7 +681,34 @@ /** Get the record of the learner's progress for a particular lesson */ LearnerProgress getLearnerProgress(Integer learnerId, Long lessonId); + /** + * Get progress for learners who most recently entered finished the lesson. + */ + List getCompletedLearnerProgressLatest(Long lessonId, Integer limit); + + /** + * Get progress for learners who most recently entered the activity. + */ + List getLearnerProgressLatest(Long activityId, Integer limit); + + + /** + * Get progress for learners who are at the given activity at the moment. + */ + List getLearnerProgressByActivity(Long activityId, Integer limit, Integer offset); + + /** + * Get number of learners who are at the given activity at the moment. + */ + Integer getCountLearnerProgressCurrentActivity(Activity activity); + + /** + * Get number of learners who finished the given lesson. + */ + Integer getCountLearnerProgressCompletedLesson(Long lessonId); + + /** * Set a groups name */ void setGroupName(Long groupID, String name); @@ -701,4 +731,9 @@ */ int cloneLessons(String[] lessonIds, Boolean addAllStaff, Boolean addAllLearners, String[] staffIds, String[] learnerIds, Organisation group) throws MonitoringServiceException; + + /** + * Get list of users who completed the given lesson. + */ + List getUsersCompletedLesson(Long lessonId); } Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== diff -u -ra207bdecc16a704428826dbf402a97de2e35458b -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision a207bdecc16a704428826dbf402a97de2e35458b) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -120,9 +120,8 @@ * to utilize the Spring's IOC and declarative transaction management. *

    *

    - * It needs to implement ApplicationContextAware interface - * because we need to load up tool's service dynamically according to the - * selected learning design. + * It needs to implement ApplicationContextAware interface because we need to load up tool's service + * dynamically according to the selected learning design. *

    * * TODO Analyse the efficiency of the grouping algorithms for adding/removing users. Possible performance issue. @@ -363,8 +362,8 @@ LearningDesign originalLearningDesign = authoringService.getLearningDesign(new Long(learningDesignId)); if (originalLearningDesign == null) { - throw new MonitoringServiceException("Learning design for id=" + learningDesignId - + " is missing. Unable to initialize lesson."); + throw new MonitoringServiceException( + "Learning design for id=" + learningDesignId + " is missing. Unable to initialize lesson."); } Lesson precedingLesson = (precedingLessonId == null) ? null : lessonDAO.getLesson(precedingLessonId); @@ -410,8 +409,8 @@ Boolean liveEditEnabled) { LearningDesign originalLearningDesign = authoringService.getLearningDesign(new Long(learningDesignId)); if (originalLearningDesign == null) { - throw new MonitoringServiceException("Learning design for id=" + learningDesignId - + " is missing. Unable to initialize lesson."); + throw new MonitoringServiceException( + "Learning design for id=" + learningDesignId + " is missing. Unable to initialize lesson."); } User user = userID != null ? (User) baseDAO.find(User.class, userID) : null; @@ -428,15 +427,15 @@ Integer scheduledNumberDaysToLessonFinish, Lesson precedingLesson) { LearningDesign learningDesign = authoringService.getLearningDesign(learningDesignID); if (learningDesign == null) { - throw new MonitoringServiceException("Learning design for id=" + learningDesignID - + " is missing. Unable to initialize lesson."); + throw new MonitoringServiceException( + "Learning design for id=" + learningDesignID + " is missing. Unable to initialize lesson."); } Lesson lesson = createNewLesson(lessonName, lessonDescription, user, learningDesign, enableLessonIntro, displayDesignImage, learnerExportAvailable, learnerPresenceAvailable, learnerImAvailable, liveEditEnabled, enableLessonNotifications, learnerRestart, scheduledNumberDaysToLessonFinish, precedingLesson); - writeAuditLog(MonitoringService.AUDIT_LESSON_CREATED_KEY, new Object[] { lessonName, learningDesign.getTitle(), - learnerExportAvailable }); + writeAuditLog(MonitoringService.AUDIT_LESSON_CREATED_KEY, + new Object[] { lessonName, learningDesign.getTitle(), learnerExportAvailable }); return lesson; } @@ -446,8 +445,8 @@ Boolean learnerImAvailable, Boolean liveEditEnabled, Boolean enableLessonNotifications, Boolean learnerRestart, Integer scheduledNumberDaysToLessonFinish, Lesson precedingLesson) { // copy the current learning design - LearningDesign copiedLearningDesign = authoringService.copyLearningDesign(originalLearningDesign, new Integer( - copyType), user, workspaceFolder, true, null, customCSV); + LearningDesign copiedLearningDesign = authoringService.copyLearningDesign(originalLearningDesign, + new Integer(copyType), user, workspaceFolder, true, null, customCSV); authoringService.saveLearningDesign(copiedLearningDesign); // Make all efforts to make sure it has a title @@ -568,15 +567,15 @@ if (requestedLesson.isLessonStarted()) { // can't schedule it as it is already started. If the UI is correct, // this should never happen. - MonitoringService.log.error("Lesson for id=" + lessonId - + " has been started. Unable to schedule lesson start."); + MonitoringService.log + .error("Lesson for id=" + lessonId + " has been started. Unable to schedule lesson start."); return; } if (requestedLesson.getScheduleStartDate() != null) { // can't reschedule! - MonitoringService.log.error("Lesson for id=" + lessonId - + " is already scheduled and cannot be rescheduled."); + MonitoringService.log + .error("Lesson for id=" + lessonId + " is already scheduled and cannot be rescheduled."); return; } @@ -603,8 +602,8 @@ scheduler.scheduleJob(startLessonJob, startLessonTrigger); setLessonState(requestedLesson, Lesson.NOT_STARTED_STATE); } catch (SchedulerException e) { - throw new MonitoringServiceException("Error occurred at " - + "[startLessonOnSchedule]- fail to start scheduling", e); + throw new MonitoringServiceException( + "Error occurred at " + "[startLessonOnSchedule]- fail to start scheduling", e); } if (MonitoringService.log.isDebugEnabled()) { @@ -672,8 +671,8 @@ if (scheduledNumberDaysToLessonFinish > 0) { scheduler.rescheduleJob(triggerName, Scheduler.DEFAULT_GROUP, finishLessonTrigger); if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("Finish lesson [" + lessonId + "] job has been rescheduled to " - + endDate); + MonitoringService.log + .debug("Finish lesson [" + lessonId + "] job has been rescheduled to " + endDate); } } else { scheduler.deleteJob(finishLessonJobName, Scheduler.DEFAULT_GROUP); @@ -684,13 +683,13 @@ } else if (scheduledNumberDaysToLessonFinish > 0) { scheduler.scheduleJob(finishLessonJob, finishLessonTrigger); if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("Finish lesson [" + lessonId + "] job has been scheduled to " - + endDate); + MonitoringService.log + .debug("Finish lesson [" + lessonId + "] job has been scheduled to " + endDate); } } } catch (SchedulerException e) { - throw new MonitoringServiceException("Error occurred at " - + "[finishLessonOnSchedule]- fail to start scheduling", e); + throw new MonitoringServiceException( + "Error occurred at " + "[finishLessonOnSchedule]- fail to start scheduling", e); } } @@ -706,10 +705,8 @@ securityService.isLessonMonitor(lessonId, userId, "start lesson", true); } if (requestedLesson.isLessonStarted()) { - MonitoringService.log - .warn("Lesson " - + lessonId - + " has been started. No need to start the lesson. The lesson was probably scheduled, and then the staff used \"Start now\". This message would have then been created by the schedule start"); + MonitoringService.log.warn("Lesson " + lessonId + + " has been started. No need to start the lesson. The lesson was probably scheduled, and then the staff used \"Start now\". This message would have then been created by the schedule start"); return; } @@ -746,13 +743,14 @@ } @Override - public Integer startSystemActivity(Activity activity, Integer currentMaxId, Date lessonStartTime, String lessonName) { + public Integer startSystemActivity(Activity activity, Integer currentMaxId, Date lessonStartTime, + String lessonName) { Integer newMaxId = null; // if it is schedule gate, we need to initialize the sheduler for it. if (activity.getActivityTypeId().intValue() == Activity.SCHEDULE_GATE_ACTIVITY_TYPE) { - ScheduleGateActivity gateActivity = (ScheduleGateActivity) activityDAO.getActivityByActivityId(activity - .getActivityId()); + ScheduleGateActivity gateActivity = (ScheduleGateActivity) activityDAO + .getActivityByActivityId(activity.getActivityId()); // do not run the scheduler if the gate is basen on user completing previous activity if (!Boolean.TRUE.equals(gateActivity.getGateActivityCompletionBased())) { activity = runGateScheduler(gateActivity, lessonStartTime, lessonName); @@ -772,8 +770,8 @@ activity.setGrouping(grouping); if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("startLesson: Created chosen grouping " + grouping - + " for branching activity " + activity); + MonitoringService.log.debug( + "startLesson: Created chosen grouping " + grouping + " for branching activity " + activity); } newMaxId = new Integer(currentMaxId.intValue() + 1); activity.setInitialised(true); @@ -808,7 +806,8 @@ // start the scheduling job try { if (((scheduleGate.getGateStartTimeOffset() == null) && (scheduleGate.getGateEndTimeOffset() == null)) - || ((scheduleGate.getGateStartTimeOffset() != null) && (scheduleGate.getGateEndTimeOffset() == null))) { + || ((scheduleGate.getGateStartTimeOffset() != null) + && (scheduleGate.getGateEndTimeOffset() == null))) { scheduler.scheduleJob(openScheduleGateJob, openGateTrigger); } else if (openGateTrigger.getStartTime().before(closeGateTrigger.getStartTime())) { scheduler.scheduleJob(openScheduleGateJob, openGateTrigger); @@ -883,8 +882,8 @@ requestedLesson.setPreviousLessonStateId(requestedLesson.getLessonStateId()); requestedLesson.setLessonStateId(status); lessonDAO.updateLesson(requestedLesson); - logEventService.logEvent(LogEvent.TYPE_TEACHER_LESSON_CHANGE_STATE, requestedLesson.getUser().getUserId(), - null, requestedLesson.getLessonId(), null); + logEventService.logEvent(LogEvent.TYPE_TEACHER_LESSON_CHANGE_STATE, requestedLesson.getUser().getUserId(), null, + requestedLesson.getLessonId(), null); } /** @@ -922,8 +921,8 @@ } lessonDAO.updateLesson(requestedLesson); - logEventService.logEvent(LogEvent.TYPE_TEACHER_LESSON_CHANGE_STATE, requestedLesson.getUser().getUserId(), - null, requestedLesson.getLessonId(), null); + logEventService.logEvent(LogEvent.TYPE_TEACHER_LESSON_CHANGE_STATE, requestedLesson.getUser().getUserId(), null, + requestedLesson.getLessonId(), null); } @Override @@ -989,10 +988,10 @@ try { scheduler.unscheduleJob("openGateTrigger:" + gate.getActivityId(), Scheduler.DEFAULT_GROUP); } catch (SchedulerException e) { - MonitoringService.log.error( + MonitoringService.log + .error("Error unscheduling trigger for gate activity id:" + gate.getActivityId(), e); + throw new MonitoringServiceException( "Error unscheduling trigger for gate activity id:" + gate.getActivityId(), e); - throw new MonitoringServiceException("Error unscheduling trigger for gate activity id:" - + gate.getActivityId(), e); } @@ -1052,11 +1051,11 @@ // check if the target activity or its parents were completed // if yes, we move user backward, otherwise forward - if ((learnerProgress != null) - && (learnerProgress.getCompletedActivities().containsKey(stopActivity) || ((parentActivity != null) && (learnerProgress - .getCompletedActivities().containsKey(parentActivity) || ((parentActivity - .getParentActivity() != null) && learnerProgress.getCompletedActivities().containsKey( - parentActivity.getParentActivity())))))) { + if ((learnerProgress != null) && (learnerProgress.getCompletedActivities().containsKey(stopActivity) + || ((parentActivity != null) && (learnerProgress.getCompletedActivities() + .containsKey(parentActivity) + || ((parentActivity.getParentActivity() != null) && learnerProgress.getCompletedActivities() + .containsKey(parentActivity.getParentActivity())))))) { return forceUncompleteActivity(learnerProgress, stopActivity, removeLearnerContent); } @@ -1096,8 +1095,8 @@ String stopReason = forceCompleteActivity(learner, lessonId, learnerProgress, currentActivity, stopPreviousActivity, new ArrayList()); - return stopReason != null ? stopReason : messageService - .getMessage(MonitoringService.FORCE_COMPLETE_STOP_MESSAGE_STOPPED_UNEXPECTEDLY); + return stopReason != null ? stopReason + : messageService.getMessage(MonitoringService.FORCE_COMPLETE_STOP_MESSAGE_STOPPED_UNEXPECTEDLY); } /** @@ -1142,8 +1141,8 @@ } learnerService.completeActivity(learner.getUserId(), activity, lessonId); if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("Grouping activity [" + activity.getActivityId() - + "] is completed."); + MonitoringService.log + .debug("Grouping activity [" + activity.getActivityId() + "] is completed."); } } else { // except random grouping, stop here @@ -1154,8 +1153,8 @@ // if group already exist learnerService.completeActivity(learner.getUserId(), activity, lessonId); if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("Grouping activity [" + activity.getActivityId() - + "] is completed."); + MonitoringService.log + .debug("Grouping activity [" + activity.getActivityId() + "] is completed."); } } @@ -1193,9 +1192,9 @@ // Let activity know that the user is force completed. Currently it's been utilized only by leader // aware tools, it copies results from leader to non-leader. lamsCoreToolService.forceCompleteActivity(toolSession, progress.getUser()); - - learnerService.completeToolSession(toolSession.getToolSessionId(), new Long(learner.getUserId() - .longValue())); + + learnerService.completeToolSession(toolSession.getToolSessionId(), + new Long(learner.getUserId().longValue())); learnerService.completeActivity(learner.getUserId(), activity, lessonId); if (MonitoringService.log.isDebugEnabled()) { MonitoringService.log.debug("Tool activity [" + activity.getActivityId() + "] is completed."); @@ -1294,8 +1293,8 @@ } // check if the target is a part of complex activity - CompletedActivityProgress completedActivityProgress = learnerProgress.getCompletedActivities().get( - targetActivity); + CompletedActivityProgress completedActivityProgress = learnerProgress.getCompletedActivities() + .get(targetActivity); Activity previousActivity = null; Activity targetParentActivity = targetActivity.getParentActivity(); if (targetParentActivity != null) { @@ -1343,13 +1342,14 @@ } continue; } else { - ComplexActivity complexActivity = (ComplexActivity) getActivityById(currentActivity.getActivityId()); + ComplexActivity complexActivity = (ComplexActivity) getActivityById( + currentActivity.getActivityId()); // forget all records within complex activity for (Activity childActivity : (Set) complexActivity.getActivities()) { uncompleteActivities.add(childActivity); if (childActivity.isComplexActivity()) { - ComplexActivity complexChildActivity = (ComplexActivity) getActivityById(childActivity - .getActivityId()); + ComplexActivity complexChildActivity = (ComplexActivity) getActivityById( + childActivity.getActivityId()); uncompleteActivities.addAll(complexChildActivity.getActivities()); } @@ -1403,8 +1403,8 @@ learnerProgress.getAttemptedActivities().put(targetActivity, completedActivityProgress.getStartDate()); if (targetParentActivity != null) { // set parent as attempted - learnerProgress.getAttemptedActivities() - .put(targetParentActivity, completedActivityProgress.getStartDate()); + learnerProgress.getAttemptedActivities().put(targetParentActivity, + completedActivityProgress.getStartDate()); targetParentActivity = targetActivity.getParentActivity(); if (targetParentActivity != null) { // if target was part of branch, then immediate parent was Sequence @@ -1433,8 +1433,8 @@ Group group = sequenceActivity.getSoleGroupForBranch(); if ((group != null) && group.hasLearner(learner)) { // remove learner from the branch - removeUsersFromBranch(sequenceActivity.getActivityId(), new String[] { learner.getUserId() - .toString() }); + removeUsersFromBranch(sequenceActivity.getActivityId(), + new String[] { learner.getUserId().toString() }); } } else { MonitoringService.log.warn("Unknow activity type marked for ungrouping: " + activity.getActivityId()); @@ -1481,8 +1481,8 @@ } flashMessage = new FlashMessage("getLessonLearners", lessonLearners); } else { - flashMessage = new FlashMessage("getLessonLearners", messageService.getMessage("NO.SUCH.LESSON", - new Object[] { lessonID }), FlashMessage.ERROR); + flashMessage = new FlashMessage("getLessonLearners", + messageService.getMessage("NO.SUCH.LESSON", new Object[] { lessonID }), FlashMessage.ERROR); } return flashMessage.serializeMessage(); } @@ -1502,8 +1502,8 @@ } flashMessage = new FlashMessage("getLessonStaff", lessonStaff); } else { - flashMessage = new FlashMessage("getLessonStaff", messageService.getMessage("NO.SUCH.LESSON", - new Object[] { lessonID }), FlashMessage.ERROR); + flashMessage = new FlashMessage("getLessonStaff", + messageService.getMessage("NO.SUCH.LESSON", new Object[] { lessonID }), FlashMessage.ERROR); } return flashMessage.serializeMessage(); } @@ -1622,8 +1622,8 @@ Set sortedUsers = new TreeSet(new Comparator() { @Override public int compare(User usr0, User usr1) { - return ((usr0.getFirstName() + usr0.getLastName() + usr0.getLogin()).compareTo(usr1.getFirstName() - + usr1.getLastName() + usr1.getLogin())); + return ((usr0.getFirstName() + usr0.getLastName() + usr0.getLogin()) + .compareTo(usr1.getFirstName() + usr1.getLastName() + usr1.getLogin())); } }); sortedUsers.addAll(users); @@ -1638,7 +1638,8 @@ * specified lesson * @return */ - private List getUsersCompletedLesson(Long lessonId) { + @Override + public List getUsersCompletedLesson(Long lessonId) { List usersCompletedLesson = new LinkedList(); List completedLearnerProgresses = learnerProgressDAO @@ -1730,8 +1731,8 @@ Activity activity = activityDAO.getActivityByActivityId(activityID); if (activity == null) { - MonitoringService.log.error("getActivityMonitorURL activity missing. Activity ID " + activityID - + " activity " + activity); + MonitoringService.log.error( + "getActivityMonitorURL activity missing. Activity ID " + activityID + " activity " + activity); } else if (activity.isToolActivity() || activity.isSystemToolActivity()) { return lamsCoreToolService.getToolMonitoringURL(lessonID, activity) + "&contentFolderID=" + contentFolderID; @@ -1759,8 +1760,8 @@ flashMessage = FlashMessage.getUserNotAuthorized("moveLesson", userID); } } else { - flashMessage = new FlashMessage("moveLesson", messageService.getMessage("NO.SUCH.LESSON", - new Object[] { lessonID }), FlashMessage.ERROR); + flashMessage = new FlashMessage("moveLesson", + messageService.getMessage("NO.SUCH.LESSON", new Object[] { lessonID }), FlashMessage.ERROR); } return flashMessage.serializeMessage(); @@ -1772,8 +1773,8 @@ GateActivity gate = (GateActivity) activityDAO.getActivityByActivityId(activityID); FlashMessage flashMessage; if (gate == null) { - flashMessage = new FlashMessage("releaseGate", messageService.getMessage("INVALID.ACTIVITYID", - new Object[] { activityID }), FlashMessage.ERROR); + flashMessage = new FlashMessage("releaseGate", + messageService.getMessage("INVALID.ACTIVITYID", new Object[] { activityID }), FlashMessage.ERROR); } else { // release gate gate = openGate(activityID); @@ -1790,10 +1791,10 @@ Grouping grouping = groupingActivity.getCreateGrouping(); if (!grouping.isChosenGrouping()) { - MonitoringService.log.error("GroupingActivity [" + groupingActivity.getActivityId() - + "] does not have chosen grouping."); - throw new MonitoringServiceException("GroupingActivity [" + groupingActivity.getActivityId() - + "] is not chosen grouping."); + MonitoringService.log.error( + "GroupingActivity [" + groupingActivity.getActivityId() + "] does not have chosen grouping."); + throw new MonitoringServiceException( + "GroupingActivity [" + groupingActivity.getActivityId() + "] is not chosen grouping."); } try { // try to sorted group list by orderID. @@ -1832,8 +1833,8 @@ MonitoringService.log.debug("Persist grouping for [" + grouping.getGroupingId() + "] success."); } catch (WDDXProcessorConversionException e) { - throw new MonitoringServiceException("Perform chosen grouping occurs error when parsing WDDX package:" - + e.getMessage()); + throw new MonitoringServiceException( + "Perform chosen grouping occurs error when parsing WDDX package:" + e.getMessage()); } } @@ -1862,8 +1863,8 @@ newLessonClass.setStaffGroup(Group.createStaffGroup(newLessonClass, staffGroupName, new HashSet(staffs))); // setup learner group // TODO:need confirm group name! - newLessonClass.getGroups().add( - Group.createLearnerGroup(newLessonClass, learnerGroupName, new HashSet(organizationUsers))); + newLessonClass.getGroups() + .add(Group.createLearnerGroup(newLessonClass, learnerGroupName, new HashSet(organizationUsers))); lessonClassDAO.updateLessonClass(newLessonClass); @@ -1894,10 +1895,10 @@ Boolean learnerExportAvailable, Boolean learnerPresenceAvailable, Boolean learnerImAvailable, Boolean liveEditEnabled, Boolean enableLessonNotifications, Boolean learnerRestart, Integer scheduledNumberDaysToLessonFinish, Lesson precedingLesson) { - Lesson newLesson = Lesson.createNewLessonWithoutClass(lessonName, lessonDescription, user, - copiedLearningDesign, enableLessonIntro, displayDesignImage, learnerExportAvailable, - learnerPresenceAvailable, learnerImAvailable, liveEditEnabled, enableLessonNotifications, - learnerRestart, scheduledNumberDaysToLessonFinish); + Lesson newLesson = Lesson.createNewLessonWithoutClass(lessonName, lessonDescription, user, copiedLearningDesign, + enableLessonIntro, displayDesignImage, learnerExportAvailable, learnerPresenceAvailable, + learnerImAvailable, liveEditEnabled, enableLessonNotifications, learnerRestart, + scheduledNumberDaysToLessonFinish); if (precedingLesson != null) { HashSet precedingLessons = new HashSet(); precedingLessons.add(precedingLesson); @@ -1919,7 +1920,7 @@ // make a copy of lazily initialized activities Set activities = new HashSet(copiedLearningDesign.getActivities()); LessonClass newLessonClass = new LessonClass(null, // grouping id - new HashSet(),// groups + new HashSet(), // groups activities, null, // staff group null);// lesson return newLessonClass; @@ -2002,8 +2003,8 @@ Set learners = lesson.getAllLearners(); if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("getClassMembersNotGrouped: Lesson " + lessonID + " has " + learners.size() - + " learners."); + MonitoringService.log + .debug("getClassMembersNotGrouped: Lesson " + lessonID + " has " + learners.size() + " learners."); } Iterator iter = grouping.getGroups().iterator(); @@ -2017,8 +2018,8 @@ } if (MonitoringService.log.isDebugEnabled()) { - MonitoringService.log.debug("getClassMembersNotGrouped: Lesson " + lessonID + " has " + learners.size() - + " learners."); + MonitoringService.log + .debug("getClassMembersNotGrouped: Lesson " + lessonID + " has " + learners.size() + " learners."); } SortedSet sortedUsers = new TreeSet(new LastNameAlphabeticComparator()); @@ -2075,10 +2076,8 @@ && (grouping.getGroups().size() >= grouping.getMaxNumberOfGroups())) { boolean usedForBranching = grouping.isUsedForBranching(); if (!usedForBranching) { - MonitoringService.log - .info("Setting max number of groups to null for grouping " - + grouping - + " we have been asked to add a group in excess of the max number of groups (probably via the Chosen Grouping screen)."); + MonitoringService.log.info("Setting max number of groups to null for grouping " + grouping + + " we have been asked to add a group in excess of the max number of groups (probably via the Chosen Grouping screen)."); grouping.setMaxNumberOfGroups(null); // must be null and not // 0 or the groups will // be lost via Live @@ -2361,6 +2360,31 @@ } @Override + public List getLearnerProgressLatest(Long activityId, Integer limit) { + return learnerProgressDAO.getLearnerProgressLatestByActivity(activityId, limit); + } + + @Override + public List getLearnerProgressByActivity(Long activityId, Integer limit, Integer offset) { + return learnerProgressDAO.getLearnerProgressByActivity(activityId, limit, offset); + } + + @Override + public List getCompletedLearnerProgressLatest(Long lessonId, Integer limit) { + return learnerProgressDAO.getCompletedLearnerProgressLatestForLesson(lessonId, limit); + } + + @Override + public Integer getCountLearnerProgressCurrentActivity(Activity activity) { + return learnerProgressDAO.getNumUsersCurrentActivity(activity); + } + + @Override + public Integer getCountLearnerProgressCompletedLesson(Long lessonId) { + return learnerProgressDAO.getNumUsersCompletedLesson(lessonId); + } + + @Override public void setGroupName(Long groupID, String name) { Group group = groupDAO.getGroupById(groupID); group.setGroupName(name); @@ -2396,26 +2420,26 @@ // init Lesson with user as creator Lesson newLesson = this.initializeLesson(lesson.getLessonName(), - lesson.getLessonDescription(), - lesson.getLearningDesign().getLearningDesignId(), group.getOrganisationId(), - userDto.getUserID(), null, lesson.isEnableLessonIntro(), - lesson.isDisplayDesignImage(), lesson.getLearnerExportAvailable(), - lesson.getLearnerPresenceAvailable(), lesson.getLearnerImAvailable(), - lesson.getLiveEditEnabled(), lesson.getEnableLessonNotifications(), - lesson.getLearnerRestart(), null, null); + lesson.getLessonDescription(), lesson.getLearningDesign().getLearningDesignId(), + group.getOrganisationId(), userDto.getUserID(), null, + lesson.isEnableLessonIntro(), lesson.isDisplayDesignImage(), + lesson.getLearnerExportAvailable(), lesson.getLearnerPresenceAvailable(), + lesson.getLearnerImAvailable(), lesson.getLiveEditEnabled(), + lesson.getEnableLessonNotifications(), lesson.getLearnerRestart(), null, null); // save LessonClasses - newLesson = this - .createLessonClassForLesson(newLesson.getLessonId(), group, learnerGroupName, - learnerUsers, staffGroupName, staffUsers, userDto.getUserID()); + newLesson = this.createLessonClassForLesson(newLesson.getLessonId(), group, + learnerGroupName, learnerUsers, staffGroupName, staffUsers, + userDto.getUserID()); // start Lessons // TODO user-specified creator; must be someone in staff group this.startLesson(newLesson.getLessonId(), staffUsers.get(0).getUserId()); result++; } else { - throw new MonitoringServiceException("No learners specified, can't create any Lessons."); + throw new MonitoringServiceException( + "No learners specified, can't create any Lessons."); } } else { throw new MonitoringServiceException("No staff specified, can't create any Lessons."); Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -r45604617ff03be0908ecfde13fdd12b795b520a2 -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 45604617ff03be0908ecfde13fdd12b795b520a2) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -59,6 +59,7 @@ import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.BranchingActivity; import org.lamsfoundation.lams.learningdesign.ChosenBranchingActivity; +import org.lamsfoundation.lams.learningdesign.ComplexActivity; import org.lamsfoundation.lams.learningdesign.ContributionTypes; import org.lamsfoundation.lams.learningdesign.Group; import org.lamsfoundation.lams.learningdesign.LearningDesign; @@ -88,7 +89,6 @@ import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CentralConstants; import org.lamsfoundation.lams.util.DateUtil; -import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.ValidationUtil; import org.lamsfoundation.lams.util.WebUtil; @@ -139,6 +139,9 @@ private static final String ERROR = "error"; private static final DateFormat LESSON_SCHEDULING_DATETIME_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm"); + private static final Integer LATEST_LEARNER_PROGRESS_LESSON_DISPLAY_LIMIT = 53; + private static final Integer LATEST_LEARNER_PROGRESS_ACTIVITY_DISPLAY_LIMIT = 7; + private static IAuditService auditService; private static ITimezoneService timezoneService; @@ -147,32 +150,34 @@ private static ISecurityService securityService; + private static IMonitoringService monitoringService; + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); return user != null ? user.getUserID() : null; } - private FlashMessage handleException(Exception e, String methodKey, IMonitoringService monitoringService) { + private FlashMessage handleException(Exception e, String methodKey) { LamsDispatchAction.log.error("Exception thrown " + methodKey, e); MonitoringAction.auditService = getAuditService(); MonitoringAction.auditService.log(MonitoringAction.class.getName() + ":" + methodKey, e.toString()); if (e instanceof UserAccessDeniedException) { return new FlashMessage(methodKey, - monitoringService.getMessageService().getMessage("error.user.noprivilege"), FlashMessage.ERROR); + getMonitoringService().getMessageService().getMessage("error.user.noprivilege"), + FlashMessage.ERROR); } else { String[] msg = new String[1]; msg[0] = e.getMessage(); return new FlashMessage(methodKey, - monitoringService.getMessageService().getMessage("error.system.error", msg), + getMonitoringService().getMessageService().getMessage("error.system.error", msg), FlashMessage.CRITICAL_ERROR); } } - private FlashMessage handleCriticalError(String methodKey, String messageKey, - IMonitoringService monitoringService) { - String message = monitoringService.getMessageService().getMessage(messageKey); + private FlashMessage handleCriticalError(String methodKey, String messageKey) { + String message = getMonitoringService().getMessageService().getMessage(messageKey); LamsDispatchAction.log.error("Error occured " + methodKey + " error "); MonitoringAction.auditService = getAuditService(); MonitoringAction.auditService.log(MonitoringAction.class.getName() + ":" + methodKey, message); @@ -200,9 +205,6 @@ public ActionForward initializeLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - String title = WebUtil.readStrParam(request, "lessonName"); if (title == null) { title = "lesson"; @@ -223,11 +225,11 @@ Lesson newLesson = null; if ((copyType != null) && copyType.equals(LearningDesign.COPY_TYPE_PREVIEW)) { - newLesson = monitoringService.initializeLessonForPreview(title, desc, ldId, getUserId(), customCSV, + newLesson = getMonitoringService().initializeLessonForPreview(title, desc, ldId, getUserId(), customCSV, learnerPresenceAvailable, learnerImAvailable, liveEditEnabled); } else { try { - newLesson = monitoringService.initializeLesson(title, desc, ldId, organisationId, getUserId(), + newLesson = getMonitoringService().initializeLesson(title, desc, ldId, organisationId, getUserId(), customCSV, false, false, learnerExportAvailable, learnerPresenceAvailable, learnerImAvailable, liveEditEnabled, false, learnerRestart, null, null); } catch (SecurityException e) { @@ -263,11 +265,9 @@ */ public ActionForward startLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); try { - monitoringService.startLesson(lessonId, getUserId()); + getMonitoringService().startLesson(lessonId, getUserId()); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); return null; @@ -284,8 +284,6 @@ Integer userID = WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); IUserManagementService userManagementService = MonitoringServiceProxy .getUserManagementService(getServlet().getServletContext()); @@ -297,7 +295,7 @@ List staff = parseUserList(request, "monitors", allUsers); try { - monitoringService.createLessonClassForLesson(lessonId, organisation, learnerGroupName, learners, + getMonitoringService().createLessonClassForLesson(lessonId, organisation, learnerGroupName, learners, staffGroupName, staff, userID); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "The user is not a monitor in the lesson"); @@ -342,9 +340,6 @@ Integer timeLimitIndividual = timeLimitEnable && timeLimitIndividualField ? timeLimitDays : null; Integer timeLimitLesson = timeLimitEnable && !timeLimitIndividualField ? timeLimitDays : null; - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - IUserManagementService userManagementService = MonitoringServiceProxy .getUserManagementService(getServlet().getServletContext()); @@ -393,11 +388,12 @@ Lesson lesson = null; try { - lesson = monitoringService.initializeLesson(lessonInstanceName, introDescription, ldId, organisationId, - userId, null, introEnable, introImage, portfolioEnable, presenceEnable, imEnable, - enableLiveEdit, notificationsEnable, learnerRestart, timeLimitIndividual, precedingLessonId); + lesson = getMonitoringService().initializeLesson(lessonInstanceName, introDescription, ldId, + organisationId, userId, null, introEnable, introImage, portfolioEnable, presenceEnable, + imEnable, enableLiveEdit, notificationsEnable, learnerRestart, timeLimitIndividual, + precedingLessonId); - monitoringService.createLessonClassForLesson(lesson.getLessonId(), organisation, + getMonitoringService().createLessonClassForLesson(lesson.getLessonId(), organisation, learnerGroupInstanceName, lessonInstanceLearners, staffGroupInstanceName, staff, userId); } catch (SecurityException e) { try { @@ -414,15 +410,15 @@ if (!startMonitor) { try { if (schedulingDatetime == null) { - monitoringService.startLesson(lesson.getLessonId(), userId); + getMonitoringService().startLesson(lesson.getLessonId(), userId); } else { // if lesson should start in few days, set it here - monitoringService.startLessonOnSchedule(lesson.getLessonId(), schedulingDatetime, userId); + getMonitoringService().startLessonOnSchedule(lesson.getLessonId(), schedulingDatetime, userId); } // if lesson should finish in few days, set it here if (timeLimitLesson != null) { - monitoringService.finishLessonOnSchedule(lesson.getLessonId(), timeLimitLesson, userId); + getMonitoringService().finishLessonOnSchedule(lesson.getLessonId(), timeLimitLesson, userId); } } catch (SecurityException e) { try { @@ -441,13 +437,11 @@ public ActionForward startOnScheduleLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws ParseException, IOException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); String dateStr = WebUtil.readStrParam(request, MonitoringConstants.PARAM_LESSON_START_DATE); Date startDate = MonitoringAction.LESSON_SCHEDULING_DATETIME_FORMAT.parse(dateStr); try { - monitoringService.startLessonOnSchedule(lessonId, startDate, getUserId()); + getMonitoringService().startLessonOnSchedule(lessonId, startDate, getUserId()); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -476,13 +470,11 @@ public ActionForward archiveLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); try { - monitoringService.unsuspendLesson(lessonId, getUserId()); + getMonitoringService().unsuspendLesson(lessonId, getUserId()); } catch (SecurityException e) { - monitoringService.archiveLesson(lessonId, getUserId()); + getMonitoringService().archiveLesson(lessonId, getUserId()); } return null; } @@ -508,11 +500,9 @@ */ public ActionForward unarchiveLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); try { - monitoringService.unarchiveLesson(lessonId, getUserId()); + getMonitoringService().unarchiveLesson(lessonId, getUserId()); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -534,11 +524,9 @@ */ public ActionForward suspendLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); try { - monitoringService.suspendLesson(lessonId, getUserId()); + getMonitoringService().suspendLesson(lessonId, getUserId()); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -559,11 +547,9 @@ */ public ActionForward unsuspendLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); try { - monitoringService.unsuspendLesson(lessonId, getUserId()); + getMonitoringService().unsuspendLesson(lessonId, getUserId()); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -592,21 +578,20 @@ */ public ActionForward removeLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, JSONException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); JSONObject jsonObject = new JSONObject(); try { // if this method throws an Exception, there will be no removeLesson=true in the JSON reply - monitoringService.removeLesson(lessonId, getUserId()); + getMonitoringService().removeLesson(lessonId, getUserId()); jsonObject.put("removeLesson", true); } catch (Exception e) { String[] msg = new String[1]; msg[0] = e.getMessage(); - jsonObject.put("removeLesson", monitoringService.getMessageService().getMessage("error.system.error", msg)); + jsonObject.put("removeLesson", + getMonitoringService().getMessageService().getMessage("error.system.error", msg)); } response.setContentType("application/json;charset=utf-8"); @@ -632,9 +617,6 @@ public ActionForward forceComplete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { getAuditService(); - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - // get parameters Long activityId = null; String actId = request.getParameter(AttributeNames.PARAM_ACTIVITY_ID); @@ -654,7 +636,7 @@ String message = null; try { - message = monitoringService.forceCompleteActivitiesByUser(learnerId, requesterId, lessonId, activityId, + message = getMonitoringService().forceCompleteActivitiesByUser(learnerId, requesterId, lessonId, activityId, removeLearnerContent); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -669,7 +651,7 @@ // audit log force completion attempt String messageKey = (activityId == null) ? "audit.force.complete.end.lesson" : "audit.force.complete"; Object[] args = new Object[] { learnerId, activityId, lessonId }; - String auditMessage = monitoringService.getMessageService().getMessage(messageKey, args); + String auditMessage = getMonitoringService().getMessageService().getMessage(messageKey, args); MonitoringAction.auditService.log(MonitoringConstants.MONITORING_MODULE_NAME, auditMessage + " " + message); PrintWriter writer = response.getWriter(); @@ -680,13 +662,11 @@ public ActionForward getLessonLearners(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { String wddxPacket; - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); try { Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); - wddxPacket = monitoringService.getLessonLearners(lessonID, getUserId()); + wddxPacket = getMonitoringService().getLessonLearners(lessonID, getUserId()); } catch (Exception e) { - wddxPacket = handleException(e, "getLessonLearners", monitoringService).serializeMessage(); + wddxPacket = handleException(e, "getLessonLearners").serializeMessage(); } PrintWriter writer = response.getWriter(); writer.println(wddxPacket); @@ -744,6 +724,47 @@ } /** + * Gets users in JSON format who are at the given activity at the moment or finished the given lesson. + */ + public ActionForward getCurrentLearners(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, JSONException { + JSONArray responseJSON = new JSONArray(); + // if activity ID is provided, lesson ID is ignored + Long activityId = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID, true); + if (activityId == null) { + long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + List learners = getMonitoringService().getUsersCompletedLesson(lessonId); + for (User learner : learners) { + responseJSON.put(WebUtil.userToJSON(learner)); + } + } else { + boolean flaFormat = WebUtil.readBooleanParam(request, "flaFormat", true); + Activity activity = getMonitoringService().getActivityById(activityId); + List learnerProgresses = getMonitoringService().getLearnerProgressByActivity(activityId, + null, null); + for (LearnerProgress learnerProgress : learnerProgresses) { + responseJSON.put(WebUtil.userToJSON(learnerProgress.getUser())); + } + + // for the Flas format of LD SVGs, children activities are hidden and the parent activity shows all learners + if (!flaFormat && (activity.isBranchingActivity() || activity.isOptionsWithSequencesActivity())) { + Set descendants = getDescendants((ComplexActivity) activity); + for (Activity descendat : descendants) { + learnerProgresses = getMonitoringService().getLearnerProgressByActivity(descendat.getActivityId(), + null, null); + for (LearnerProgress learnerProgress : learnerProgresses) { + responseJSON.put(WebUtil.userToJSON(learnerProgress.getUser())); + } + } + } + } + + response.setContentType("application/json;charset=utf-8"); + response.getWriter().write(responseJSON.toString()); + return null; + } + + /** * Adds/removes learners and monitors to/from lesson class. */ public ActionForward updateLessonClass(ActionMapping mapping, ActionForm form, HttpServletRequest request, @@ -777,13 +798,11 @@ public ActionForward getLessonStaff(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { String wddxPacket; - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); try { Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); - wddxPacket = monitoringService.getLessonStaff(lessonID, getUserId()); + wddxPacket = getMonitoringService().getLessonStaff(lessonID, getUserId()); } catch (Exception e) { - wddxPacket = handleException(e, "getLessonStaff", monitoringService).serializeMessage(); + wddxPacket = handleException(e, "getLessonStaff").serializeMessage(); } PrintWriter writer = response.getWriter(); writer.println(wddxPacket); @@ -793,14 +812,12 @@ public ActionForward getLearningDesignDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { String wddxPacket; - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); try { Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); getSecurityService().isLessonMonitor(lessonID, getUserId(), "get learning design details", true); - wddxPacket = monitoringService.getLearningDesignDetails(lessonID); + wddxPacket = getMonitoringService().getLearningDesignDetails(lessonID); } catch (Exception e) { - wddxPacket = handleException(e, "getLearningDesignDetails", monitoringService).serializeMessage(); + wddxPacket = handleException(e, "getLearningDesignDetails").serializeMessage(); } PrintWriter writer = response.getWriter(); writer.println(wddxPacket); @@ -810,9 +827,7 @@ public ActionForward getDictionaryXML(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - MessageService messageService = monitoringService.getMessageService(); + MessageService messageService = getMonitoringService().getMessageService(); String module = WebUtil.readStrParam(request, "module", false); @@ -866,13 +881,11 @@ public ActionForward getLearnerActivityURL(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, LamsToolServiceException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); Integer learnerUserID = new Integer(WebUtil.readIntParam(request, AttributeNames.PARAM_USER_ID)); Long activityID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID)); Long lessonID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID)); try { - String url = monitoringService.getLearnerActivityURL(lessonID, activityID, learnerUserID, getUserId()); + String url = getMonitoringService().getLearnerActivityURL(lessonID, activityID, learnerUserID, getUserId()); return redirectToURL(mapping, response, url); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -883,13 +896,12 @@ /** Calls the server to bring up the activity's monitoring page. Assumes destination is a new window */ public ActionForward getActivityMonitorURL(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, LamsToolServiceException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); Long activityID = new Long(WebUtil.readLongParam(request, "activityID")); Long lessonID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID)); String contentFolderID = WebUtil.readStrParam(request, "contentFolderID"); try { - String url = monitoringService.getActivityMonitorURL(lessonID, activityID, contentFolderID, getUserId()); + String url = getMonitoringService().getActivityMonitorURL(lessonID, activityID, contentFolderID, + getUserId()); return redirectToURL(mapping, response, url); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -899,16 +911,14 @@ public ActionForward moveLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); String wddxPacket = null; try { Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); Integer userID = getUserId(); Integer targetWorkspaceFolderID = new Integer(WebUtil.readIntParam(request, "folderID")); - wddxPacket = monitoringService.moveLesson(lessonID, targetWorkspaceFolderID, userID); + wddxPacket = getMonitoringService().moveLesson(lessonID, targetWorkspaceFolderID, userID); } catch (Exception e) { - FlashMessage flashMessage = handleException(e, "moveLesson", monitoringService); + FlashMessage flashMessage = handleException(e, "moveLesson"); wddxPacket = flashMessage.serializeMessage(); } PrintWriter writer = response.getWriter(); @@ -1084,101 +1094,173 @@ Long branchingActivityId = WebUtil.readLongParam(request, "branchingActivityID", true); Lesson lesson = getLessonService().getLesson(lessonId); - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - LessonDetailsDTO lessonDetails = lesson.getLessonDetails(); - String contentFolderId = lessonDetails.getContentFolderID(); - - // few details for each activity - Map activitiesMap = new TreeMap(); LearningDesign learningDesign = lesson.getLearningDesign(); + String contentFolderId = learningDesign.getContentFolderID(); + + // find out if the LD SVG is in new Flashless (exploded) format + JSONObject responseJSON = new JSONObject(); + boolean flaFormat = false; for (Activity activity : (Set) learningDesign.getActivities()) { - if ((branchingActivityId == null) || MonitoringAction.isBranchingChild(branchingActivityId, activity)) { - Long activityId = activity.getActivityId(); - JSONObject activityJSON = new JSONObject(); - activityJSON.put("id", activityId); - activityJSON.put("uiid", activity.getActivityUIID()); - activityJSON.put("title", activity.getTitle()); + if ((activity.isBranchingActivity() || activity.isOptionsWithSequencesActivity()) + && (((ComplexActivity) activity).getXcoord() == null)) { + // if a single activity is in FLA format, all of them are + flaFormat = true; + break; + } + } + responseJSON.put("flaFormat", flaFormat); - int activityType = activity.getActivityTypeId(); - activityJSON.put("type", activityType); - Activity parentActivity = activity.getParentActivity(); - if (activity.isBranchingActivity() && (((BranchingActivity) activity).getXcoord() == null)) { - // old branching is just a rectangle like Tool - // new branching has start and finish points, it's exploded - activityJSON.put("flaFormat", true); - activityJSON.put("x", - MonitoringAction.getActivityCoordinate(((BranchingActivity) activity).getStartXcoord())); - activityJSON.put("y", - MonitoringAction.getActivityCoordinate(((BranchingActivity) activity).getStartYcoord())); - } else if (activity.isOptionsWithSequencesActivity() - && (((OptionsWithSequencesActivity) activity).getXcoord() == null)) { - // old optional sequences is just a long rectangle - // new optional sequences has start and finish points, it's exploded - activityJSON.put("flaFormat", true); - activityJSON.put("x", MonitoringAction - .getActivityCoordinate(((OptionsWithSequencesActivity) activity).getStartXcoord())); - activityJSON.put("y", MonitoringAction - .getActivityCoordinate(((OptionsWithSequencesActivity) activity).getStartYcoord())); - } else if ((parentActivity != null) - && ((Activity.OPTIONS_ACTIVITY_TYPE == parentActivity.getActivityTypeId()) - || (Activity.PARALLEL_ACTIVITY_TYPE == parentActivity.getActivityTypeId()) - || (Activity.FLOATING_ACTIVITY_TYPE == parentActivity.getActivityTypeId()))) { - // Optional Activity children had coordinates relative to parent - activityJSON.put("x", MonitoringAction.getActivityCoordinate(parentActivity.getXcoord()) - + MonitoringAction.getActivityCoordinate(activity.getXcoord())); - activityJSON.put("y", MonitoringAction.getActivityCoordinate(parentActivity.getYcoord()) - + MonitoringAction.getActivityCoordinate(activity.getYcoord())); - } else { - activityJSON.put("x", MonitoringAction.getActivityCoordinate(activity.getXcoord())); - activityJSON.put("y", MonitoringAction.getActivityCoordinate(activity.getYcoord())); - } + Set activities = new HashSet(); + List contributeActivities = getContributeActivities(lessonId, true); + Map> parentToChildren = new TreeMap>(); + // filter activities that are interesting for further processing + for (Activity activity : (Set) learningDesign.getActivities()) { + if (activity.isSequenceActivity()) { + // skip sequence activities as they are just for grouping + continue; + } - String monitorUrl = monitoringService.getActivityMonitorURL(lessonId, activityId, contentFolderId, - monitorUserId); - if (monitorUrl != null) { - // whole activity monitor URL - activityJSON.put("url", monitorUrl); + if (flaFormat) { + // in FLA format everything is exploded so there are no hidden child activities + activities.add(activity); + continue; + } + + Activity parentActivity = activity.getParentActivity(); + Activity parentParentActivity = parentActivity == null ? null : parentActivity.getParentActivity(); + if (parentParentActivity == null) { + activities.add(activity); + continue; + } + + if (!parentParentActivity.isOptionsWithSequencesActivity() && (!parentParentActivity.isBranchingActivity() + || parentParentActivity.getActivityId().equals(branchingActivityId))) { + activities.add(activity); + } else { + // branching and options with sequences in Flash format have hidden activities + // map the children to their parent for further processing + Set children = parentToChildren.get(parentParentActivity.getActivityId()); + if (children == null) { + children = new HashSet(); + parentToChildren.put(parentParentActivity.getActivityId(), children); } + children.add(activity); - activitiesMap.put(activityId, activityJSON); + // skip hidden contribute activities + if (contributeActivities != null) { + Iterator contributeActivityIterator = contributeActivities.iterator(); + while (contributeActivityIterator.hasNext()) { + if (activity.getActivityId().equals(contributeActivityIterator.next().getActivityID())) { + contributeActivityIterator.remove(); + } + } + } } } - JSONObject responseJSON = new JSONObject(); - for (LearnerProgress learnerProgress : (Set) lesson.getLearnerProgresses()) { - User learner = learnerProgress.getUser(); - if (learnerProgress.isComplete()) { - JSONObject learnerJSON = WebUtil.userToJSON(learner); - // no more details are needed for learners who completed the lesson - responseJSON.append("completedLearners", learnerJSON); + if (contributeActivities != null) { + Gson gson = new GsonBuilder().create(); + responseJSON.put("contributeActivities", new JSONArray(gson.toJson(contributeActivities))); + } + + JSONArray activitiesJSON = new JSONArray(); + for (Activity activity : activities) { + Long activityId = activity.getActivityId(); + JSONObject activityJSON = new JSONObject(); + activityJSON.put("id", activityId); + activityJSON.put("uiid", activity.getActivityUIID()); + activityJSON.put("title", activity.getTitle()); + activityJSON.put("type", activity.getActivityTypeId()); + + Activity parentActivity = activity.getParentActivity(); + if (activity.isBranchingActivity() && (((BranchingActivity) activity).getXcoord() == null)) { + // old branching is just a rectangle like Tool + // new branching has start and finish points, it's exploded + activityJSON.put("x", + MonitoringAction.getActivityCoordinate(((BranchingActivity) activity).getStartXcoord())); + activityJSON.put("y", + MonitoringAction.getActivityCoordinate(((BranchingActivity) activity).getStartYcoord())); + } else if (activity.isOptionsWithSequencesActivity() + && (((OptionsWithSequencesActivity) activity).getXcoord() == null)) { + // old optional sequences is just a long rectangle + // new optional sequences has start and finish points, it's exploded + activityJSON.put("x", MonitoringAction + .getActivityCoordinate(((OptionsWithSequencesActivity) activity).getStartXcoord())); + activityJSON.put("y", MonitoringAction + .getActivityCoordinate(((OptionsWithSequencesActivity) activity).getStartYcoord())); + } else if ((parentActivity != null) && (parentActivity.isOptionsActivity() + || parentActivity.isParallelActivity() || parentActivity.isFloatingActivity())) { + // Optional Activity children had coordinates relative to parent + activityJSON.put("x", MonitoringAction.getActivityCoordinate(parentActivity.getXcoord()) + + MonitoringAction.getActivityCoordinate(activity.getXcoord())); + activityJSON.put("y", MonitoringAction.getActivityCoordinate(parentActivity.getYcoord()) + + MonitoringAction.getActivityCoordinate(activity.getYcoord())); } else { - Activity currentActivity = learnerProgress.getCurrentActivity(); - if ((currentActivity != null) && ((branchingActivityId == null) - || MonitoringAction.isBranchingChild(branchingActivityId, currentActivity))) { - JSONObject learnerJSON = WebUtil.userToJSON(learner); + activityJSON.put("x", MonitoringAction.getActivityCoordinate(activity.getXcoord())); + activityJSON.put("y", MonitoringAction.getActivityCoordinate(activity.getYcoord())); + } - // assign learners to child activity or parent branching/options with sequences? - Activity parentActivity = currentActivity.getParentActivity(); - Long targetActivityId = (branchingActivityId != null) || (parentActivity == null) - || (parentActivity.getParentActivity() == null) - || !(parentActivity.getParentActivity().isBranchingActivity() - || parentActivity.getParentActivity().isOptionsWithSequencesActivity()) - ? currentActivity.getActivityId() - : parentActivity.getParentActivity().getActivityId(); + String monitorUrl = getMonitoringService().getActivityMonitorURL(lessonId, activityId, contentFolderId, + monitorUserId); + if (monitorUrl != null) { + // whole activity monitor URL + activityJSON.put("url", monitorUrl); + } - JSONObject targetActivityJSON = activitiesMap.get(targetActivityId); - if (Boolean.TRUE.equals(JsonUtil.opt(targetActivityJSON, "flaFormat"))) { - // for new format, we always set learners to child activity, not parent - targetActivityJSON = activitiesMap.get(currentActivity.getActivityId()); + // find few latest users and count of all users for each activity + int learnerCount = 0; + if (activity.isBranchingActivity() || activity.isOptionsWithSequencesActivity()) { + // go through hidden children of complex activities and take them into account + learnerCount += getMonitoringService().getCountLearnerProgressCurrentActivity(activity); + Set children = parentToChildren.get(activityId); + if (children != null) { + for (Activity child : children) { + learnerCount += getMonitoringService().getCountLearnerProgressCurrentActivity(child); } - targetActivityJSON.append("learners", learnerJSON); } + } else { + List latestLearnerProgress = getMonitoringService().getLearnerProgressLatest( + activity.getActivityId(), MonitoringAction.LATEST_LEARNER_PROGRESS_ACTIVITY_DISPLAY_LIMIT); + if (latestLearnerProgress.size() < MonitoringAction.LATEST_LEARNER_PROGRESS_ACTIVITY_DISPLAY_LIMIT) { + // if there are less learners than the limit, we already know the size + learnerCount = latestLearnerProgress.size(); + } else { + learnerCount = getMonitoringService().getCountLearnerProgressCurrentActivity(activity); + } + + // parse learners into JSON format + if (!latestLearnerProgress.isEmpty()) { + JSONArray learnersJSON = new JSONArray(); + for (LearnerProgress learnerProgress : latestLearnerProgress) { + User learner = learnerProgress.getUser(); + learnersJSON.put(WebUtil.userToJSON(learner)); + } + + activityJSON.put("learners", learnersJSON); + } } + activityJSON.put("learnerCount", learnerCount); + + activitiesJSON.put(activityJSON); } + responseJSON.put("activities", activitiesJSON); - responseJSON.put("activities", new JSONArray(activitiesMap.values())); - responseJSON.put("numberPossibleLearners", lessonDetails.getNumberPossibleLearners()); + // find learners who completed the lesson + List completedLearners = getMonitoringService().getCompletedLearnerProgressLatest(lessonId, + MonitoringAction.LATEST_LEARNER_PROGRESS_LESSON_DISPLAY_LIMIT); + for (LearnerProgress learner : completedLearners) { + JSONObject learnerJSON = WebUtil.userToJSON(learner.getUser()); + // no more details are needed for learners who completed the lesson + responseJSON.append("completedLearners", learnerJSON); + } + Integer completedLearnerCount = null; + if (completedLearners.size() < MonitoringAction.LATEST_LEARNER_PROGRESS_LESSON_DISPLAY_LIMIT) { + completedLearnerCount = completedLearners.size(); + } else { + completedLearnerCount = getMonitoringService().getCountLearnerProgressCompletedLesson(lessonId); + } + responseJSON.put("completedLearnerCount", completedLearnerCount); + responseJSON.put("numberPossibleLearners", lesson.getAllLearners().size()); // on first fetch get transitions metadata so Monitoring can set their SVG elems IDs if (WebUtil.readBooleanParam(request, "getTransitions", false)) { @@ -1194,45 +1276,21 @@ responseJSON.put("transitions", transitions); } - List contributeActivities = getContributeActivities(lessonId, true); - // remove "attention required" marker for hidden activities in Flash Authoring - if (contributeActivities != null) { - Iterator activityIterator = contributeActivities.iterator(); - while (activityIterator.hasNext()) { - ContributeActivityDTO contributeActivityDTO = activityIterator.next(); - Activity contributeActivity = monitoringService.getActivityById(contributeActivityDTO.getActivityID()); - Activity topParentActivity = contributeActivity.getParentActivity() == null ? null - : contributeActivity.getParentActivity().getParentActivity(); - - if ((branchingActivityId == null) && (topParentActivity != null) - && (topParentActivity.isBranchingActivity() - || topParentActivity.isOptionsWithSequencesActivity())) { - JSONObject topContributeActivityJSON = activitiesMap.get(topParentActivity.getActivityId()); - if (!Boolean.TRUE.equals(JsonUtil.opt(topContributeActivityJSON, "flaFormat"))) { - activityIterator.remove(); - } - } - } - Gson gson = new GsonBuilder().create(); - responseJSON.put("contributeActivities", new JSONArray(gson.toJson(contributeActivities))); - } - response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); return null; + } public ActionForward releaseGate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); String wddxPacket = null; try { Long activityID = new Long(WebUtil.readLongParam(request, "activityID")); - wddxPacket = monitoringService.releaseGate(activityID); + wddxPacket = getMonitoringService().releaseGate(activityID); } catch (Exception e) { - FlashMessage flashMessage = handleException(e, "releaseGate", monitoringService); + FlashMessage flashMessage = handleException(e, "releaseGate"); wddxPacket = flashMessage.serializeMessage(); } PrintWriter writer = response.getWriter(); @@ -1242,8 +1300,6 @@ public ActionForward startPreviewLesson(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); FlashMessage flashMessage = null; try { @@ -1257,16 +1313,16 @@ */ try { - monitoringService.createPreviewClassForLesson(userID, lessonID); - monitoringService.startLesson(lessonID, getUserId()); + getMonitoringService().createPreviewClassForLesson(userID, lessonID); + getMonitoringService().startLesson(lessonID, getUserId()); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "The user is not a monitor in the lesson"); return null; } flashMessage = new FlashMessage("startPreviewSession", new Long(lessonID)); } catch (Exception e) { - flashMessage = handleException(e, "startPreviewSession", monitoringService); + flashMessage = handleException(e, "startPreviewSession"); } PrintWriter writer = response.getWriter(); @@ -1328,6 +1384,15 @@ return MonitoringAction.lessonService; } + private IMonitoringService getMonitoringService() { + if (MonitoringAction.monitoringService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + MonitoringAction.monitoringService = (IMonitoringService) ctx.getBean("monitoringService"); + } + return MonitoringAction.monitoringService; + } + private ISecurityService getSecurityService() { if (MonitoringAction.securityService == null) { WebApplicationContext ctx = WebApplicationContextUtils @@ -1343,13 +1408,11 @@ */ public ActionForward learnerExportPortfolioAvailable(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); Integer userID = getUserId(); Boolean learnerExportPortfolioAvailable = WebUtil.readBooleanParam(request, "learnerExportPortfolio", false); try { - monitoringService.setLearnerPortfolioAvailable(lessonID, userID, learnerExportPortfolioAvailable); + getMonitoringService().setLearnerPortfolioAvailable(lessonID, userID, learnerExportPortfolioAvailable); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -1362,18 +1425,16 @@ */ public ActionForward presenceAvailable(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); Integer userID = getUserId(); Boolean presenceAvailable = WebUtil.readBooleanParam(request, "presenceAvailable", false); try { - monitoringService.setPresenceAvailable(lessonID, userID, presenceAvailable); + getMonitoringService().setPresenceAvailable(lessonID, userID, presenceAvailable); if (!presenceAvailable) { - monitoringService.setPresenceImAvailable(lessonID, userID, false); + getMonitoringService().setPresenceImAvailable(lessonID, userID, false); } } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); @@ -1387,14 +1448,12 @@ */ public ActionForward presenceImAvailable(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); Long lessonID = new Long(WebUtil.readLongParam(request, "lessonID")); Integer userID = getUserId(); Boolean presenceImAvailable = WebUtil.readBooleanParam(request, "presenceImAvailable", false); try { - monitoringService.setPresenceImAvailable(lessonID, userID, presenceImAvailable); + getMonitoringService().setPresenceImAvailable(lessonID, userID, presenceImAvailable); } catch (SecurityException e) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); } @@ -1404,10 +1463,6 @@ /** Open Time Chart display */ public ActionForward viewTimeChart(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - try { long lessonID = WebUtil.readLongParam(request, "lessonID"); @@ -1454,26 +1509,9 @@ return result; } - private static boolean isBranchingChild(Long branchingActivityId, Activity activity) { - if ((branchingActivityId == null) || (activity == null)) { - return false; - } - - Activity parentActivity = activity.getParentActivity(); - while (parentActivity != null) { - if (parentActivity.isBranchingActivity()) { - return parentActivity.getActivityId().equals(branchingActivityId); - } - parentActivity = parentActivity.getParentActivity(); - } - return false; - } - @SuppressWarnings("unchecked") private List getContributeActivities(Long lessonId, boolean skipCompletedBranching) { - IMonitoringService monitoringService = MonitoringServiceProxy - .getMonitoringService(getServlet().getServletContext()); - List contributeActivities = monitoringService.getAllContributeActivityDTO(lessonId); + List contributeActivities = getMonitoringService().getAllContributeActivityDTO(lessonId); Lesson lesson = getLessonService().getLesson(lessonId); if (contributeActivities != null) { @@ -1489,7 +1527,7 @@ if (skipCompletedBranching && ContributionTypes.CHOSEN_BRANCHING.equals(contributeEntry.getContributionType())) { Set learners = new HashSet(lesson.getLessonClass().getLearners()); - ChosenBranchingActivity branching = (ChosenBranchingActivity) monitoringService + ChosenBranchingActivity branching = (ChosenBranchingActivity) getMonitoringService() .getActivityById(contributeActivity.getActivityID()); for (SequenceActivity branch : (Set) branching.getActivities()) { Group group = branch.getSoleGroupForBranch(); @@ -1518,4 +1556,21 @@ private static int getActivityCoordinate(Integer coord) { return (coord == null) || (coord < 0) ? ObjectExtractor.DEFAULT_COORD : coord; } + + /** + * Gets all children and their childre etc. of the given complex activity. + */ + @SuppressWarnings("unchecked") + private Set getDescendants(ComplexActivity complexActivity) { + Set result = new HashSet(); + for (Activity child : (Set) complexActivity.getActivities()) { + child = getMonitoringService().getActivityById(child.getActivityId()); + if (child.isComplexActivity()) { + result.addAll(getDescendants((ComplexActivity) child)); + } else { + result.add(child); + } + } + return result; + } } \ No newline at end of file Index: lams_monitoring/web/includes/javascript/monitorLesson.js =================================================================== diff -u -r6f82bfabdb07cfa40b1c3840e688362fe11e7271 -r9f419a19d1664fcd4a85c03c89e81d0137f60f5d --- lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 6f82bfabdb07cfa40b1c3840e688362fe11e7271) +++ lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 9f419a19d1664fcd4a85c03c89e81d0137f60f5d) @@ -2,6 +2,8 @@ // copy of lesson/branching SVG so it does no need to be fetched every time // HTML with SVG of the lesson var originalSequenceCanvas = null, +// is the LD SVG in Flashless format or the old, Flash format + flaFormat = false, // DIV container for lesson/branching SVG // it gets accessed so many times it's worth to cache it here sequenceCanvas = null, @@ -827,6 +829,9 @@ }, success : function(response) { if (sequenceCanvasFirstFetch) { + // once Flashless SVG format is detected, it applies for all activities + flaFormat = response.flaFormat; + // FLA activities have uiids but no ids, set it here $.each(response.activities, function(activityIndex, activity){ $('g[uiid="' + activity.uiid + '"]', sequenceCanvas).attr('id', activity.id); @@ -863,7 +868,7 @@ reloadSVG = false; $.each(response.activities, function(index, activity){ // are there any learners in this or any activity? - learnerCount += activity.learners ? activity.learners.length : 0; + learnerCount += activity.learnerCount; if (response.contributeActivities) { $.each(response.contributeActivities, function(){ if (activity.id == this.activityID) { @@ -883,16 +888,15 @@ sequenceCanvas.html(sequenceCanvas.html()); } - var completedLearners = response.completedLearners, - learnerTotalCount = learnerCount + (completedLearners ? completedLearners.length : 0 ); + var learnerTotalCount = learnerCount + response.completedLearnerCount; $('#learnersStartedPossibleCell').text(learnerTotalCount + ' / ' + response.numberPossibleLearners); - addCompletedLearnerIcons(completedLearners, learnerTotalCount); + addCompletedLearnerIcons(response.completedLearners, response.completedLearnerCount, learnerTotalCount); $.each(response.activities, function(activityIndex, activity){ addActivityIconsHandlers(activity); var isBranching = [10,11,12,13].indexOf(activity.type) > -1; - if (activity.url || (isBranching && !activity.flaFormat)) { + if (activity.url || (isBranching && !flaFormat)) { var activityGroup = $('g[id="' + activity.id + '"]'), dblClickFunction = // different behaviour for regular/branching activities @@ -1052,7 +1056,7 @@ * Draw user and attention icons on top of activities. */ function addActivityIcons(activity) { - if (!activity.learners && !activity.requiresAttention) { + if (activity.learnerCount == 0 && !activity.requiresAttention) { return; } @@ -1065,12 +1069,11 @@ // add group of users icon var appendTarget = $('svg', sequenceCanvas)[0], // branching and gates require extra adjustments - isNewBranching = [10,11,12,13].indexOf(activity.type) > -1 && activity.flaFormat, + isNewBranching = [10,11,12,13].indexOf(activity.type) > -1 && flaFormat, isGate = [3,4,5,14].indexOf(activity.type) > -1; - if (activity.learners){ - var groupTitle = activity.learners.length + ' ' + LABELS.LEARNER_GROUP_COUNT + ' ' + LABELS.LEARNER_GROUP_SHOW, - // if icons do not fit in shape anymore, show a group icon + if (activity.learnerCount > 0){ + var groupTitle = activity.learnerCount + ' ' + LABELS.LEARNER_GROUP_COUNT + ' ' + LABELS.LEARNER_GROUP_SHOW, element = appendXMLElement('image', { 'id' : 'act' + activity.id + 'learnerGroup', 'x' : isNewBranching ? coord.x + 2 : (isGate ? coord.x + 10 : coord.x2 - 18), @@ -1090,34 +1093,29 @@ 'font-family': 'Verdana', 'font-size' : 8, 'style' : 'cursor : pointer' - }, activity.learners.length, appendTarget); + }, activity.learnerCount, appendTarget); appendXMLElement('title', null, groupTitle, element); - var actTooltip = LABELS.LEARNER_GROUP_LIST_TITLE; - // draw single icons for the first few learners; - // don't do it for gate and optional activities, and new branching/optional sequences format - if ([3,4,5,7,13,14].indexOf(activity.type) == -1 && !activity.flaFormat) { - $.each(activity.learners, function(learnerIndex, learner){ - var learnerDisplayName = getLearnerDisplayName(learner); - actTooltip += '\n' + learnerDisplayName; - - if (learnerIndex < 7) { - element = appendXMLElement('image', { - 'id' : 'act' + activity.id + 'learner' + learner.id, - 'x' : coord.x + learnerIndex*15 + 1, - // a bit lower for Optional Activity - 'y' : coord.y, - 'height' : 16, - 'width' : 16, - 'xlink:href' : LAMS_URL + 'images/icons/user.png', - 'style' : 'cursor : pointer' - }, null, appendTarget); + if (activity.learners) { + // draw single icons for the first few learners; + // don't do it for gate and optional activities, and new branching/optional sequences format + if ([3,4,5,7,13,14].indexOf(activity.type) == -1 && !flaFormat) { + $.each(activity.learners, function(learnerIndex, learner){ + var learnerDisplayName = getLearnerDisplayName(learner); + element = appendXMLElement('image', { + 'id' : 'act' + activity.id + 'learner' + learner.id, + 'x' : coord.x + learnerIndex*15 + 1, + // a bit lower for Optional Activity + 'y' : coord.y, + 'height' : 16, + 'width' : 16, + 'xlink:href' : LAMS_URL + 'images/icons/user.png', + 'style' : 'cursor : pointer' + }, null, appendTarget); appendXMLElement('title', null, learnerDisplayName, element); - } - }); + }); + } } - - appendXMLElement('title', null, actTooltip, appendTarget); } if (activity.requiresAttention) { @@ -1139,7 +1137,7 @@ * After SVG refresh, add click/dblclick/drag handlers to icons. */ function addActivityIconsHandlers(activity) { - if (!activity.learners && !activity.requiresAttention) { + if (activity.learnerCount == 0 && !activity.requiresAttention) { return; } @@ -1181,12 +1179,14 @@ }); } }); - + } + + if (activity.learnerCount > 0){ var learnerGroup = $('*[id^="act' + activity.id + 'learnerGroup"]', sequenceCanvas); dblTap(learnerGroup, function(event){ // double click on learner group icon to see list of learners event.stopPropagation(); - showLearnerGroupDialog(activity.id, activity.title, activity.learners, true, usersViewable); + showLearnerGroupDialog(activity.id, activity.title, null, true, usersViewable, false); }); } @@ -1203,48 +1203,43 @@ /** * Add learner icons in "finished lesson" bar. */ -function addCompletedLearnerIcons(learners, learnerTotalCount) { +function addCompletedLearnerIcons(learners, learnerCount, learnerTotalCount) { var iconsContainer = $('#completedLearnersContainer'); - var completedLearnerCount = (learners ? learners.length : 0 ); // show (current/total) label $('').attr({ - 'title' : LABELS.LEARNER_FINISHED_COUNT - .replace('[0]', completedLearnerCount).replace('[1]', learnerTotalCount) - }).text('(' + completedLearnerCount + '/' + learnerTotalCount + ')') - .appendTo(iconsContainer); + 'title' : LABELS.LEARNER_FINISHED_COUNT.replace('[0]', learnerCount).replace('[1]', learnerTotalCount) + }).text('(' + learnerCount + '/' + learnerTotalCount + ')') + .appendTo(iconsContainer); if (learners) { // create learner icons, along with handlers $.each(learners, function(learnerIndex, learner){ - // maximum 55 icons in the bar - if (learnerIndex < 55) { - // make an icon for each learner - $('').attr({ - 'src' : LAMS_URL + 'images/icons/user.png', - 'title' : getLearnerDisplayName(learner) - }).css('cursor', 'pointer') - // drag learners to force complete activities - .draggable({ - 'appendTo' : '#tabSequence', - 'containment' : '#tabSequence', - 'distance' : 20, - 'scroll' : false, - 'cursorAt' : {'left' : 10, 'top' : 15}, - 'helper' : function(event){ - // copy of the icon for dragging - return $('').attr('src', LAMS_URL + 'images/icons/user.png'); - }, - 'start' : function(){ - autoRefreshBlocked = true; - }, - 'stop' : function(event, ui) { - // jQuery droppable does not work for SVG, so this is a workaround - forceComplete(null, learner.id, getLearnerDisplayName(learner, true), - ui.offset.left, ui.offset.top); - } - }) - .appendTo(iconsContainer); - } + // make an icon for each learner + $('').attr({ + 'src' : LAMS_URL + 'images/icons/user.png', + 'title' : getLearnerDisplayName(learner) + }).css('cursor', 'pointer') + // drag learners to force complete activities + .draggable({ + 'appendTo' : '#tabSequence', + 'containment' : '#tabSequence', + 'distance' : 20, + 'scroll' : false, + 'cursorAt' : {'left' : 10, 'top' : 15}, + 'helper' : function(event){ + // copy of the icon for dragging + return $('').attr('src', LAMS_URL + 'images/icons/user.png'); + }, + 'start' : function(){ + autoRefreshBlocked = true; + }, + 'stop' : function(event, ui) { + // jQuery droppable does not work for SVG, so this is a workaround + forceComplete(null, learner.id, getLearnerDisplayName(learner, true), + ui.offset.left, ui.offset.top); + } + }) + .appendTo(iconsContainer); }); // show a group icon @@ -1254,7 +1249,7 @@ }).css('cursor', 'pointer').appendTo(iconsContainer); dblTap(groupIcon, function(){ - showLearnerGroupDialog(null, LABELS.LEARNER_FINISHED_DIALOG_TITLE, learners, true, false); + showLearnerGroupDialog(null, LABELS.LEARNER_FINISHED_DIALOG_TITLE, null, true, false, false); }); } } @@ -1283,7 +1278,7 @@ } // special processing for new format of branching and optional sequences - if ([10,11,12,13].indexOf(activity.type) > -1 && activity.flaFormat) { + if ([10,11,12,13].indexOf(activity.type) > -1 && flaFormat) { return { 'x' : activity.x, 'y' : activity.y @@ -1783,41 +1778,58 @@ * Show a dialog with user list and optional Force Complete and View Learner buttons. */ function showLearnerGroupDialog(activityId, dialogTitle, learners, allowForceComplete, allowView, allowEmail) { - var learnerGroupList = $('#learnerGroupList').empty(); - var learnerGroupDialog = $('#learnerGroupDialog'); + var learnerGroupList = $('#learnerGroupList').empty(), + learnerGroupDialog = $('#learnerGroupDialog'); - if (learners) { - $.each(learners, function(learnerIndex, learner) { - var viewUrl = LAMS_URL + 'monitoring/monitoring.do?method=getLearnerActivityURL&userID=' - + learner.id + '&activityID=' + activityId + '&lessonID=' + lessonId, - learnerDiv = $('
    ').attr({ - 'userId' : learner.id, - 'viewUrl' : viewUrl - }) - .addClass('dialogListItem') - .html(getLearnerDisplayName(learner)) - .appendTo(learnerGroupList); - - if (allowForceComplete || allowView || allowEmail) { - learnerDiv.click(function(){ - // select a learner - $(this).addClass('dialogListItemSelected') - .siblings('div.dialogListItem') - .removeClass('dialogListItemSelected'); - // enable buttons - $('button.learnerGroupDialogSelectableButton') - .attr('disabled', null); - }); - if (allowView){ - dblTap(learnerDiv, function(){ - // same as clicking View Learner button - openPopUp(viewUrl, "LearnActivity", 600, 800, true); - }); - } + if (!learners) { + $.ajax({ + dataType : 'json', + url : LAMS_URL + 'monitoring/monitoring.do', + cache : false, + async : false, + data : { + 'method' : 'getCurrentLearners', + 'lessonID' : lessonId, + // activity ID can be null; if it is not, lesson ID is ignored + 'activityID' : activityId, + 'flaFormat' : flaFormat + }, + success : function(response) { + learners = response; } }); } + $.each(learners, function(learnerIndex, learner) { + var viewUrl = LAMS_URL + 'monitoring/monitoring.do?method=getLearnerActivityURL&userID=' + + learner.id + '&activityID=' + activityId + '&lessonID=' + lessonId, + learnerDiv = $('
    ').attr({ + 'userId' : learner.id, + 'viewUrl' : viewUrl + }) + .addClass('dialogListItem') + .html(getLearnerDisplayName(learner)) + .appendTo(learnerGroupList); + + if (allowForceComplete || allowView || allowEmail) { + learnerDiv.click(function(){ + // select a learner + $(this).addClass('dialogListItemSelected') + .siblings('div.dialogListItem') + .removeClass('dialogListItemSelected'); + // enable buttons + $('button.learnerGroupDialogSelectableButton') + .attr('disabled', null); + }); + if (allowView){ + dblTap(learnerDiv, function(){ + // same as clicking View Learner button + openPopUp(viewUrl, "LearnActivity", 600, 800, true); + }); + } + } + }); + // show buttons depending on parameters $('button#learnerGroupDialogForceCompleteButton') .css('display', allowForceComplete ? 'inline' : 'none');