Index: lams_build/lib/lams/lams-learning.jar =================================================================== diff -u -re023857e217082f46fd3235d5673129ffccf6ff4 -rfdca3605f0b782b19e214abbe94df6f4a457b88e Binary files differ Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r96b3b3ff3f62e1bca1d299f75f512995388e420b -rfdca3605f0b782b19e214abbe94df6f4a457b88e Binary files differ Index: lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/lesson/Lesson.hbm.xml =================================================================== diff -u -r89403052c08187d7d7c341b07b21529411e2cef6 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/lesson/Lesson.hbm.xml (.../Lesson.hbm.xml) (revision 89403052c08187d7d7c341b07b21529411e2cef6) +++ lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/lesson/Lesson.hbm.xml (.../Lesson.hbm.xml) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -188,6 +188,18 @@ AND (lams_learner_progress.lesson_id = :lessonId) + + + SELECT DISTINCT {learner.*} + FROM lams_user {learner}, + lams_learner_progress, + lams_user_group + WHERE ({learner}.user_id = lams_learner_progress.user_id) + AND (lams_learner_progress.lesson_id = :lessonId) + AND ({learner}.user_id = lams_user_group.user_id) + AND (lams_user_group.group_id = :groupId) + + Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/Activity.java =================================================================== diff -u -r870373d635bc769aee2dc271e6ff12818fcfcea6 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/Activity.java (.../Activity.java) (revision 870373d635bc769aee2dc271e6ff12818fcfcea6) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/Activity.java (.../Activity.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -1093,4 +1093,37 @@ return null; } + /** + * Is this activity inside a branch? If so, return turn branch activity (ie the sequence, not the + * branching activity. Returns null if not in a branch. + */ + public Activity getParentBranch() { + if ( isSequenceActivity() && getParentActivity() != null && getParentActivity().isBranchingActivity()) { + // I'm a branch, so start the process off with my parent! + return getParentBranch(getParentActivity(), new HashSet()); + } else { + return getParentBranch(this, new HashSet()); + } + } + + private Activity getParentBranch(Activity activity, Set processedActivityIds) { + + Activity parent = activity.getParentActivity(); + + if ( parent == null ) + return null; + + if ( parent.isBranchingActivity() ) + return activity; + + // double check that we haven't already processed this activity. Should never happen but if it does it + // would cause an infinite loop. + if ( processedActivityIds.contains(activity.getActivityId())) + return null; + + processedActivityIds.add(activity.getActivityId()); + + return getParentBranch(parent, processedActivityIds); + } + } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java =================================================================== diff -u -r4a347e27e76d051dfb231810330b42d0b7295ded -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java (.../ILessonDAO.java) (revision 4a347e27e76d051dfb231810330b42d0b7295ded) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILessonDAO.java (.../ILessonDAO.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -108,6 +108,16 @@ public List getActiveLearnerByLesson(final long lessonId); /** + * Returns the all the learners that have started the requested lesson and + * are in the given group. + * + * @param lessonId the id of the requested lesson. + * @param groupId the id of the requested group. + * @return the list of learners. + */ + public List getActiveLearnerByLessonAndGroup(final long lessonId, final long groupId); + + /** * Returns the count of all the learners that have started the requested lesson. * * @param lessonId the id of the requested lesson. Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java =================================================================== diff -u -r93b9fa85159d7fb8957de4f839273806a93a6df9 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java (.../LessonDAO.java) (revision 93b9fa85159d7fb8957de4f839273806a93a6df9) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LessonDAO.java (.../LessonDAO.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -176,6 +176,28 @@ } /** + * @see org.lamsfoundation.lams.lesson.dao.ILessonDAO#getActiveLearnerByLessonAndGroup(long, long) + */ + public List getActiveLearnerByLessonAndGroup(final long lessonId, final long groupId) + { + List learners = null; + + HibernateTemplate hibernateTemplate = new HibernateTemplate(this.getSessionFactory()); + learners = (List)hibernateTemplate.execute( + new HibernateCallback() { + public Object doInHibernate(Session session) throws HibernateException { + Query query = session.getNamedQuery("activeLearnersByGroup"); + query.setLong("lessonId", lessonId); + query.setLong("groupId", groupId); + List result = query.list(); + return result; + } + } + ); + return learners; + } + + /** * @see org.lamsfoundation.lams.lesson.dao.ILessonDAO#getActiveLearnerByLesson(long) * Note: Hibernate 3.1 query.uniqueResult() returns Integer, Hibernate 3.2 query.uniqueResult() returns Long */ Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java =================================================================== diff -u -r4a347e27e76d051dfb231810330b42d0b7295ded -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 4a347e27e76d051dfb231810330b42d0b7295ded) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -63,6 +63,9 @@ /** Get all the learners who have started the lesson. They may not be currently online.*/ public abstract List getActiveLessonLearners(Long lessonId); + /** Get all the learners who have started the lesson and are part of a given group. They may not be currently online.*/ + public abstract List getActiveLessonLearnersByGroup(Long lessonId, Long groupId); + /** * Get the count of all the learners who have started the lesson. They may not be currently online. */ Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java =================================================================== diff -u -r96b3b3ff3f62e1bca1d299f75f512995388e420b -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 96b3b3ff3f62e1bca1d299f75f512995388e420b) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -123,6 +123,14 @@ } /* (non-Javadoc) + * @see org.lamsfoundation.lams.lesson.service.ILessonService#getActiveLessonLearnersByGroup(java.lang.Long, java.lang.Long) + */ + public List getActiveLessonLearnersByGroup(Long lessonId, Long groupId) + { + return lessonDAO.getActiveLearnerByLessonAndGroup(lessonId, groupId); + } + + /* (non-Javadoc) * @see org.lamsfoundation.lams.lesson.service.ILessonService#getCountActiveLessonLearners(java.lang.Long) */ public Integer getCountActiveLessonLearners(Long lessonId) Index: lams_learning/conf/xdoclet/struts-forms.xml =================================================================== diff -u -r0d3e22cf043f3f9498e1aae50704cd5cb5449c63 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_learning/conf/xdoclet/struts-forms.xml (.../struts-forms.xml) (revision 0d3e22cf043f3f9498e1aae50704cd5cb5449c63) +++ lams_learning/conf/xdoclet/struts-forms.xml (.../struts-forms.xml) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -8,7 +8,7 @@ - + Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java =================================================================== diff -u -r0a50c865925ec0818895cbc9c4ce3b6e0beefa9c -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java (.../ICoreLearnerService.java) (revision 0a50c865925ec0818895cbc9c4ce3b6e0beefa9c) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java (.../ICoreLearnerService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -27,6 +27,7 @@ import java.util.List; import org.lamsfoundation.lams.learning.web.bean.ActivityURL; +import org.lamsfoundation.lams.learning.web.bean.GateActivityDTO; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.BranchingActivity; import org.lamsfoundation.lams.learningdesign.GateActivity; @@ -229,9 +230,9 @@ * synch gate, schedule gate or permission gate. * @param knocker the learner who wants to go through the gate. * @param forceGate if forceGate==true and the lesson is a preview lesson then the gate is opened straight away. - * @return true if the gate is now open + * @return Updated gate details */ - public boolean knockGate(Long gateActivityId, User knocker, boolean forceGate); + public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate); /** * Check up the gate status to go through the gate. This also updates the gate. @@ -243,10 +244,20 @@ * as it might be out of date or not attached to the session * @param knocker the learner who wants to go through the gate. * @param forceGate if forceGate==true and the lesson is a preview lesson then the gate is opened straight away. - * @return true if the gate is now open + * @return Updated gate details */ - public boolean knockGate(GateActivity gateActivity, User knocker, boolean forceGate); + public GateActivityDTO knockGate(GateActivity gateActivity, User knocker, boolean forceGate); + /** + * Get all the learners who may come through this gate. + * For a Group Based branch and the Teacher Grouped branch, it is the group of users in + * the Branch's group, but only the learners who have started the lesson. + * Otherwise we just get all learners who have started the lesson. + * @param gate activity + * @return List of User + */ + public List getLearnersForGate(GateActivity gate); + /** * Get the learner url for a particular activity. * Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -r4ce8d52796b8d19898bfc31ae6f9b00db78d2061 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 4ce8d52796b8d19898bfc31ae6f9b00db78d2061) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -39,6 +39,7 @@ import org.lamsfoundation.lams.learning.progress.ProgressEngine; import org.lamsfoundation.lams.learning.progress.ProgressException; import org.lamsfoundation.lams.learning.web.bean.ActivityURL; +import org.lamsfoundation.lams.learning.web.bean.GateActivityDTO; import org.lamsfoundation.lams.learning.web.util.ActivityMapping; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.BranchActivityEntry; @@ -620,7 +621,7 @@ /** * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#knockGate(java.lang.Long, org.lamsfoundation.lams.usermanagement.User) */ - public boolean knockGate(Long gateActivityId, User knocker, boolean forceGate) { + public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate) { GateActivity gate = (GateActivity) activityDAO.getActivityByActivityId(gateActivityId, GateActivity.class); if ( gate != null ) { return knockGate(gate,knocker, forceGate); @@ -633,13 +634,11 @@ /** * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#knockGate(org.lamsfoundation.lams.learningdesign.GateActivity, org.lamsfoundation.lams.usermanagement.User) */ - public boolean knockGate(GateActivity gate, User knocker, boolean forceGate) + public GateActivityDTO knockGate(GateActivity gate, User knocker, boolean forceGate) { Lesson lesson = getLessonByActivity(gate); + List lessonLearners = getLearnersForGate(gate, lesson); - //get all learners who have started the lesson - List lessonLearners = getActiveLearnersByLesson(lesson.getLessonId()); - boolean gateOpen = false; if ( forceGate ) { @@ -657,11 +656,60 @@ //update gate including updating the waiting list and gate status in //the database. activityDAO.update(gate); - return gateOpen; + return new GateActivityDTO(gate, lessonLearners); } + + /** + * Get all the learners who may come through this gate. + * For a Group Based branch and the Teacher Grouped branch, it is the group of users in + * the Branch's group, but only the learners who have started the lesson. + * Otherwise we just get all learners who have started the lesson. + * @param gate + * @param lesson + * @return List of User + */ + private List getLearnersForGate(GateActivity gate, Lesson lesson) { + + List lessonLearners = null; + Activity branchActivity = gate.getParentBranch(); + while ( branchActivity != null && + ! ( branchActivity.getParentActivity().isChosenBranchingActivity() || branchActivity.getParentActivity().isGroupBranchingActivity()) ) { + branchActivity = branchActivity.getParentBranch(); + } + + if ( branchActivity !=null ) { + // set up list based on branch - all members of a group attached to the branch are destined for the gate + SequenceActivity branchSequence = (SequenceActivity) activityDAO.getActivityByActivityId(branchActivity.getActivityId(), SequenceActivity.class); + Set branchEntries = branchSequence.getBranchEntries(); + Iterator entryIterator = branchEntries.iterator(); + while (entryIterator.hasNext()) { + BranchActivityEntry branchActivityEntry = (BranchActivityEntry) entryIterator.next(); + Group group = branchActivityEntry.getGroup(); + if ( group != null ) { + List groupLearners = lessonService.getActiveLessonLearnersByGroup(lesson.getLessonId(), group.getGroupId()); + if ( lessonLearners == null ) + lessonLearners = groupLearners; + else + lessonLearners.addAll(groupLearners); + } + } + + } else { + lessonLearners = getActiveLearnersByLesson(lesson.getLessonId()); + } + return lessonLearners; + } /** + * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getWaitingGateLearners(org.lamsfoundation.lams.learningdesign.GateActivity) + */ + public List getLearnersForGate(GateActivity gate) + { + return getLearnersForGate(gate, getLessonByActivity(gate)); + } + + /** * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getLearnerActivityURL(java.lang.Integer, java.lang.Long) */ public String getLearnerActivityURL(Integer learnerId, Long activityId) { Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java =================================================================== diff -u -r08ff1f97f8908470f7c049d4ac1622ab2d0c1f33 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java (.../GateAction.java) (revision 08ff1f97f8908470f7c049d4ac1622ab2d0c1f33) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java (.../GateAction.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -37,6 +37,7 @@ import org.lamsfoundation.lams.learning.service.ICoreLearnerService; import org.lamsfoundation.lams.learning.service.LearnerServiceException; import org.lamsfoundation.lams.learning.service.LearnerServiceProxy; +import org.lamsfoundation.lams.learning.web.bean.GateActivityDTO; import org.lamsfoundation.lams.learning.web.util.ActivityMapping; import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; import org.lamsfoundation.lams.learningdesign.Activity; @@ -139,14 +140,16 @@ } if ( activity != null ) { - - Integer totalNumActiveLearners = learnerService.getCountActiveLearnersByLesson(lesson.getLessonId()); //knock the gate - boolean gateOpen = learnerService.knockGate(activityId,learner,forceGate); + GateActivityDTO gate = learnerService.knockGate(activityId,learner,forceGate); + if ( gate == null ) { + throw new LearnerServiceException("Gate missing. gate id ["+activityId+"]"); + } + //if the gate is closed, ask the learner to wait ( updating the cached learner progress on the way ) - if ( ! gateOpen) { - ActionForward forward = findViewByGateType(mapping, (DynaActionForm)form, activity, totalNumActiveLearners, lesson); + if ( ! gate.getGateOpen() ) { + ActionForward forward = findViewByGateType(mapping, (DynaActionForm)form, gate, lesson); LearningWebUtil.setupProgressInRequest((DynaActionForm)form, request, learnerProgress); return forward; } @@ -169,101 +172,36 @@ * class to tell the ActionServlet where to send the end-user. * @param gateForm The ActionForm class that will contain any data submitted * by the end-user via a form. - * @param permissionGate the gate acitivty object + * @param permissionGate the gate activity object * @param totalNumActiveLearners total number of active learners in the lesson (may not all be logged in) * @return An ActionForward class that will be returned to the ActionServlet * indicating where the user is to go next. */ private ActionForward findViewByGateType(ActionMapping mapping, DynaActionForm gateForm, - Activity gate, - Integer totalNumActiveLearners, + GateActivityDTO gate, Lesson lesson) { - //dispatch the view according to the type of the gate. - if ( gate != null ) { - gateForm.set("totalLearners",totalNumActiveLearners); - gateForm.set("previewLesson",lesson.isPreviewLesson()); - gateForm.set(AttributeNames.PARAM_ACTIVITY_ID,gate.getActivityId()); - gateForm.set(AttributeNames.PARAM_LESSON_ID, lesson.getLessonId()); - if(gate.isSynchGate()) - return viewSynchGate(mapping,gateForm,(SynchGateActivity)gate); - else if(gate.isScheduleGate()) - return viewScheduleGate(mapping,gateForm,(ScheduleGateActivity)gate); - else if(gate.isPermissionGate() || gate.isSystemGate()) - return viewPermissionGate(mapping,gateForm,(PermissionGateActivity)gate); - else - throw new LearnerServiceException("Invalid gate activity. " + - "gate id ["+gate.getActivityId()+"] - the type ["+ - gate.getActivityTypeId()+"] is not a gate type"); - } else { - throw new LearnerServiceException("Gate activity missing. " + - "gate id ["+gate.getActivityId()+"]"); - } + gateForm.set("totalLearners",new Integer(gate.getExpectedLearners().size())); + gateForm.set("waitingLearners",new Integer(gate.getWaitingLearners().size())); + gateForm.set("previewLesson",lesson.isPreviewLesson()); + gateForm.set(AttributeNames.PARAM_ACTIVITY_ID,gate.getActivityId()); + gateForm.set(AttributeNames.PARAM_LESSON_ID, lesson.getLessonId()); + gateForm.set("gate",gate); + if(gate.isSynchGate()) { + return mapping.findForward(VIEW_SYNCH_GATE); + } else if(gate.isScheduleGate()) { + ScheduleGateActivity scheduleGate = (ScheduleGateActivity)gate.getGateActivity(); + gateForm.set("startingTime",scheduleGate.getGateStartDateTime()); + gateForm.set("endingTime",scheduleGate.getGateEndDateTime()); + return mapping.findForward(VIEW_SCHEDULE_GATE); + } else if(gate.isPermissionGate() || gate.isSystemGate()) { + return mapping.findForward(VIEW_PERMISSION_GATE); + } else { + throw new LearnerServiceException("Invalid gate activity. " + + "gate id ["+gate.getActivityId()+"] - the type ["+ + gate.getActivityTypeId()+"] is not a gate type"); + } } - /** - * Set up the form attributes specific to the permission gate and navigate - * to the permission gate view. - * @param mapping An ActionMapping class that will be used by the Action - * class to tell the ActionServlet where to send the end-user. - * @param gateForm The ActionForm class that will contain any data submitted - * by the end-user via a form. - * @param permissionGate the gate activity object - * @return An ActionForward class that will be returned to the ActionServlet - * indicating where the user is to go next. - */ - private ActionForward viewPermissionGate(ActionMapping mapping, - DynaActionForm gateForm, - PermissionGateActivity permissionGate) - { - gateForm.set("gate",permissionGate); - return mapping.findForward(VIEW_PERMISSION_GATE); - } - - /** - * Set up the form attributes specific to the schedule gate and navigate - * to the schedule gate view. - * - * @param mapping An ActionMapping class that will be used by the Action - * class to tell the ActionServlet where to send the end-user. - * @param gateForm The ActionForm class that will contain any data submitted - * by the end-user via a form. - * @param permissionGate the gate acitivty object - * @return An ActionForward class that will be returned to the ActionServlet - * indicating where the user is to go next. - */ - private ActionForward viewScheduleGate(ActionMapping mapping, - DynaActionForm gateForm, - ScheduleGateActivity scheduleGate) - { - gateForm.set("gate",scheduleGate); - gateForm.set("waitingLearners",new Integer(scheduleGate.getWaitingLearners().size())); - gateForm.set("startingTime",scheduleGate.getGateStartDateTime()); - gateForm.set("endingTime",scheduleGate.getGateEndDateTime()); - - return mapping.findForward(VIEW_SCHEDULE_GATE); - } - - /** - * Set up the form attributes specific to the synch gate and navigate - * to the synch gate view. - * - * @param mapping An ActionMapping class that will be used by the Action - * class to tell the ActionServlet where to send the end-user. - * @param gateForm The ActionForm class that will contain any data submitted - * by the end-user via a form. - * @param permissionGate the gate acitivty object - * @return An ActionForward class that will be returned to the ActionServlet - * indicating where the user is to go next. - */ - private ActionForward viewSynchGate(ActionMapping mapping, - DynaActionForm gateForm, - SynchGateActivity synchgate) - { - gateForm.set("gate",synchgate); - gateForm.set("waitingLearners",new Integer(synchgate.getWaitingLearners().size())); - return mapping.findForward(VIEW_SYNCH_GATE); - } - } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/bean/GateActivityDTO.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/bean/GateActivityDTO.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/bean/GateActivityDTO.java (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -0,0 +1,287 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id$ */ +package org.lamsfoundation.lams.learning.web.bean; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.lamsfoundation.lams.learningdesign.Activity; +import org.lamsfoundation.lams.learningdesign.GateActivity; +import org.lamsfoundation.lams.learningdesign.Group; +import org.lamsfoundation.lams.learningdesign.Grouping; +import org.lamsfoundation.lams.learningdesign.LearningDesign; +import org.lamsfoundation.lams.learningdesign.LearningLibrary; +import org.lamsfoundation.lams.learningdesign.Transition; +import org.lamsfoundation.lams.learningdesign.dto.AuthoringActivityDTO; +import org.lamsfoundation.lams.learningdesign.dto.BranchActivityEntryDTO; +import org.lamsfoundation.lams.learningdesign.dto.LibraryActivityDTO; +import org.lamsfoundation.lams.learningdesign.dto.ProgressActivityDTO; +import org.lamsfoundation.lams.learningdesign.strategy.SimpleActivityStrategy; +import org.lamsfoundation.lams.tool.SystemTool; +import org.lamsfoundation.lams.usermanagement.User; + +/** + * DTO wrapping a normal Gate Activity class, with an extra "calculated" field added for the learning module's gate screen. + * + */ +public class GateActivityDTO { + + private List expectedLearners; + private GateActivity gateActivity; + + public GateActivityDTO(GateActivity gateActivity, List lessonLearners) { + this.gateActivity = gateActivity; + this.expectedLearners = lessonLearners; + } + /** + * Temporary value of the expected number of learners. This may change every time + * the gate is knocked, and is NOT persisted to the database. It is calculated when this + * DTO is created by the knockGate() method in LearnerService. + */ + public List getExpectedLearners() { + return expectedLearners; + } + + public void setExpectedLearners(List tempExpectedLearnerCount) { + this.expectedLearners = tempExpectedLearnerCount; + } + + public boolean equals(Object other) { + return gateActivity.equals(other); + } + + public Integer getActivityCategoryID() { + return gateActivity.getActivityCategoryID(); + } + + public Long getActivityId() { + return gateActivity.getActivityId(); + } + + public Integer getActivityTypeId() { + return gateActivity.getActivityTypeId(); + } + + public Integer getActivityUIID() { + return gateActivity.getActivityUIID(); + } + + public Set getAllToolActivities() { + return gateActivity.getAllToolActivities(); + } + + public Boolean getApplyGrouping() { + return gateActivity.getApplyGrouping(); + } + + public Set getAuthoringActivityDTOSet( + ArrayList branchMappings, + String languageCode) { + return gateActivity.getAuthoringActivityDTOSet(branchMappings, + languageCode); + } + + public Date getCreateDateTime() { + return gateActivity.getCreateDateTime(); + } + + public Boolean getDefineLater() { + return gateActivity.getDefineLater(); + } + + public String getDescription() { + return gateActivity.getDescription(); + } + + public Integer getGateActivityLevelId() { + return gateActivity.getGateActivityLevelId(); + } + + public Boolean getGateOpen() { + return gateActivity.getGateOpen(); + } + + public Group getGroupFor(User learner) { + return gateActivity.getGroupFor(learner); + } + + public Grouping getGrouping() { + return gateActivity.getGrouping(); + } + + public Integer getGroupingSupportType() { + return gateActivity.getGroupingSupportType(); + } + + public Integer getGroupingUIID() { + return gateActivity.getGroupingUIID(); + } + + public String getHelpText() { + return gateActivity.getHelpText(); + } + + public Set getInputActivities() { + return gateActivity.getInputActivities(); + } + + public ArrayList getInputActivityUIIDs() { + return gateActivity.getInputActivityUIIDs(); + } + + public String getLanguageFile() { + return gateActivity.getLanguageFile(); + } + + public LearningDesign getLearningDesign() { + return gateActivity.getLearningDesign(); + } + + public LearningLibrary getLearningLibrary() { + return gateActivity.getLearningLibrary(); + } + + public Activity getLibraryActivity() { + return gateActivity.getLibraryActivity(); + } + + public LibraryActivityDTO getLibraryActivityDTO(String languageCode) { + return gateActivity.getLibraryActivityDTO(languageCode); + } + + public String getLibraryActivityUiImage() { + return gateActivity.getLibraryActivityUiImage(); + } + + public Integer getOrderId() { + return gateActivity.getOrderId(); + } + + public Activity getParentActivity() { + return gateActivity.getParentActivity(); + } + + public Activity getParentBranch() { + return gateActivity.getParentBranch(); + } + + public Integer getParentUIID() { + return gateActivity.getParentUIID(); + } + + public ProgressActivityDTO getProgressActivityData() { + return gateActivity.getProgressActivityData(); + } + + public Boolean getReadOnly() { + return gateActivity.getReadOnly(); + } + + public Boolean getRunOffline() { + return gateActivity.getRunOffline(); + } + + public SimpleActivityStrategy getSimpleActivityStrategy() { + return gateActivity.getSimpleActivityStrategy(); + } + + public SystemTool getSystemTool() { + return gateActivity.getSystemTool(); + } + + public String getTitle() { + return gateActivity.getTitle(); + } + + public Integer getToolInputActivityUIID() { + return gateActivity.getToolInputActivityUIID(); + } + + public Transition getTransitionFrom() { + return gateActivity.getTransitionFrom(); + } + + public Transition getTransitionTo() { + return gateActivity.getTransitionTo(); + } + + public Set getWaitingLearners() { + return gateActivity.getWaitingLearners(); + } + + public Integer getXcoord() { + return gateActivity.getXcoord(); + } + + public Integer getYcoord() { + return gateActivity.getYcoord(); + } + + public int hashCode() { + return gateActivity.hashCode(); + } + + public boolean isActivityReadOnly() { + return gateActivity.isActivityReadOnly(); + } + + public boolean isGateActivity() { + return gateActivity.isGateActivity(); + } + + public boolean isSystemToolActivity() { + return gateActivity.isSystemToolActivity(); + } + + public String toString() { + return gateActivity.toString(); + } + + /** Get the wrapped up gate activity - the web layer shouldn't use this call, it should use one of the other methods to get + * the gate's details. */ + public GateActivity getGateActivity() { + return gateActivity; + } + + /** Set the wrapped up gate activity */ + public void setGateActivity(GateActivity gateActivity) { + this.gateActivity = gateActivity; + } + public boolean isPermissionGate() { + return gateActivity.isPermissionGate(); + } + public boolean isScheduleGate() { + return gateActivity.isScheduleGate(); + } + public boolean isSynchGate() { + return gateActivity.isSynchGate(); + } + public boolean isSystemGate() { + return gateActivity.isSystemGate(); + } + + +} Index: lams_learning/test/java/org/lamsfoundation/lams/learning/service/TestLearnerService.java =================================================================== diff -u -r96b3b3ff3f62e1bca1d299f75f512995388e420b -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_learning/test/java/org/lamsfoundation/lams/learning/service/TestLearnerService.java (.../TestLearnerService.java) (revision 96b3b3ff3f62e1bca1d299f75f512995388e420b) +++ lams_learning/test/java/org/lamsfoundation/lams/learning/service/TestLearnerService.java (.../TestLearnerService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -25,6 +25,7 @@ package org.lamsfoundation.lams.learning.service; import org.lamsfoundation.lams.learning.progress.ProgressException; +import org.lamsfoundation.lams.learning.web.bean.GateActivityDTO; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.GateActivity; import org.lamsfoundation.lams.learningdesign.Grouping; @@ -348,9 +349,9 @@ //get sync gate GateActivity synchGate = (GateActivity)learnerService.getActivity(new Long(TEST_SYNCHGATE_ACTIVITY_ID)); - boolean gateOpen = learnerService.knockGate(synchGate.getActivityId(),testUser,false); + GateActivityDTO gateDTO = learnerService.knockGate(synchGate.getActivityId(),testUser,false); - assertTrue("gate is closed",!gateOpen); + assertTrue("gate is closed",!gateDTO.getGateOpen()); synchGate = (GateActivity)learnerService.getActivity(new Long(TEST_SYNCHGATE_ACTIVITY_ID)); assertEquals("one learner is waiting",1,synchGate.getWaitingLearners().size()); @@ -363,8 +364,8 @@ //get sync gate GateActivity synchGate = (GateActivity)learnerService.getActivity(new Long(TEST_SYNCHGATE_ACTIVITY_ID)); - boolean gateOpen = learnerService.knockGate(synchGate.getActivityId(),testUser2,false); - assertTrue("gate is closed",gateOpen); + GateActivityDTO gateDTO = learnerService.knockGate(synchGate.getActivityId(),testUser2,false); + assertTrue("gate is open",gateDTO.getGateOpen()); synchGate = (GateActivity)learnerService.getActivity(new Long(TEST_SYNCHGATE_ACTIVITY_ID)); Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== diff -u -r00f9d4e2b438651181a3e7ccb29e914b69a9dc2a -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 00f9d4e2b438651181a3e7ccb29e914b69a9dc2a) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -46,6 +46,7 @@ import org.lamsfoundation.lams.authoring.service.IAuthoringService; import org.lamsfoundation.lams.dao.IBaseDAO; import org.lamsfoundation.lams.learning.service.ICoreLearnerService; +import org.lamsfoundation.lams.learning.web.bean.GateActivityDTO; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.BranchingActivity; import org.lamsfoundation.lams.learningdesign.ChosenGrouping; @@ -1100,7 +1101,8 @@ }else if ( activity.isGateActivity() ) { GateActivity gate = (GateActivity) activity; - if(learnerService.knockGate(gate,learner,false)){ + GateActivityDTO dto = learnerService.knockGate(gate,learner,false); + if ( dto.getGateOpen() ){ //the gate is opened, continue to next activity to complete learnerService.completeActivity(learner.getUserId(),activity,lessonId); if ( log.isDebugEnabled()) { @@ -1711,33 +1713,7 @@ //--------------------------------------------------------------------- // Helper Methods - start lesson //--------------------------------------------------------------------- - /** - * Is this activity inside a branch? - */ - private boolean isInBranch(Activity activity, Set processedActivityIds) { - - Activity parent = activity.getParentActivity(); - - if ( parent == null ) - return false; - - if ( parent.isBranchingActivity() ) - return true; - - // double check that we haven't already processed this activity. Should never happen but if it does it - // would cause an infinite loop. - Set processedActivityIdsTemp = processedActivityIds; - if ( processedActivityIdsTemp == null ) { - processedActivityIdsTemp = new HashSet(); - } else { - if ( processedActivityIdsTemp.contains(activity.getActivityId())) - return false; - } - processedActivityIdsTemp.add(activity.getActivityId()); - - return isInBranch(parent, processedActivityIdsTemp); - } - + /** * If the activity is not grouped and not in a branch, then it create * lams tool session for all the learners in the lesson. After the creation @@ -1751,7 +1727,7 @@ */ private void initToolSessionIfSuitable(ToolActivity activity, Lesson lesson) { - if ( activity.getApplyGrouping().equals(Boolean.FALSE) && ! isInBranch(activity, null) ) { + if ( activity.getApplyGrouping().equals(Boolean.FALSE) && activity.getParentBranch() == null ) { activity.setToolSessions(new HashSet()); try { Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java =================================================================== diff -u -r5d3ddfc93be3ffa35d806a3890263e0630e860f6 -rfdca3605f0b782b19e214abbe94df6f4a457b88e --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java (.../GateAction.java) (revision 5d3ddfc93be3ffa35d806a3890263e0630e860f6) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java (.../GateAction.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) @@ -142,8 +142,6 @@ { DynaActionForm gateForm = (DynaActionForm)form; - long lessonId = WebUtil.readLongParam(request,AttributeNames.PARAM_LESSON_ID); - // if this is the initial call then activity id will be in the request, otherwise // get it from the form (if being called from openGate.jsp Long gateIdLong = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID, true); @@ -155,13 +153,18 @@ this.monitoringService = MonitoringServiceProxy.getMonitoringService(getServlet().getServletContext()); this.learnerService = MonitoringServiceProxy.getLearnerService(getServlet().getServletContext()); - Activity gate = monitoringService.getActivityById(gateId); + GateActivity gate = (GateActivity) monitoringService.getActivityById(gateId); + if ( gate == null ) { + throw new MonitoringServiceException("Gate activity missing. Activity id"+gateId); + } + //setup the total learners - int totalLearners = learnerService.getActiveLearnersByLesson(lessonId).size(); + int totalLearners = learnerService.getLearnersForGate(gate).size(); gateForm.set(TOTAL_LEARNERS_FORM_FIELD,new Integer(totalLearners)); gateForm.set(ACTIVITY_FORM_FIELD,gateIdLong); gateForm.set(LOCAL_FILES, Boolean.FALSE); + return findViewByGateType(mapping, gateForm, gate); } @@ -228,55 +231,33 @@ */ private ActionForward findViewByGateType(ActionMapping mapping, DynaActionForm gateForm, - Activity gate) + GateActivity gate) { // reset all the other fields, so that the following code only has to set up its own values (LDEV-1237) gateForm.set(READ_ONLY, Boolean.FALSE); gateForm.set("gate",null); gateForm.set("waitingLearners",null); gateForm.set("startingTime",null); gateForm.set("endingTime",null); + gateForm.set("gate",gate); + gateForm.set("waitingLearners",new Integer(gate.getWaitingLearners().size())); //dispatch the view according to the type of the gate. - if ( gate != null ) { - if(gate.isSynchGate()) - return viewSynchGate(mapping,gateForm,(SynchGateActivity)gate); - else if(gate.isScheduleGate()) - return viewScheduleGate(mapping,gateForm,(ScheduleGateActivity)gate); - else if(gate.isPermissionGate() || gate.isSystemGate()) - return viewPermissionGate(mapping,gateForm,(PermissionGateActivity)gate); - else - throw new MonitoringServiceException("Invalid gate activity. " + - "gate id ["+gate.getActivityId()+"] - the type ["+ - gate.getActivityTypeId()+"] is not a gate type"); - } else { - throw new MonitoringServiceException("Gate activity missing. "); - } + if(gate.isSynchGate()) + return mapping.findForward(VIEW_SYNCH_GATE); + else if(gate.isScheduleGate()) + return viewScheduleGate(mapping,gateForm,(ScheduleGateActivity)gate); + else if(gate.isPermissionGate() || gate.isSystemGate()) + return mapping.findForward(VIEW_PERMISSION_GATE); + else + throw new MonitoringServiceException("Invalid gate activity. " + + "gate id ["+gate.getActivityId()+"] - the type ["+ + gate.getActivityTypeId()+"] is not a gate type"); } /** - * Set up the form attributes specific to the permission gate and navigate - * to the permission gate view. - * @param mapping An ActionMapping class that will be used by the Action - * class to tell the ActionServlet where to send the end-user. - * @param gateForm The ActionForm class that will contain any data submitted - * by the end-user via a form. - * @param permissionGate the gate acitivty object - * @return An ActionForward class that will be returned to the ActionServlet - * indicating where the user is to go next. - */ - private ActionForward viewPermissionGate(ActionMapping mapping, - DynaActionForm gateForm, - PermissionGateActivity permissionGate) - { - gateForm.set("gate",permissionGate); - gateForm.set("waitingLearners",new Integer(permissionGate.getWaitingLearners().size())); - return mapping.findForward(VIEW_PERMISSION_GATE); - } - - /** * Set up the form attributes specific to the schedule gate and navigate * to the schedule gate view. * @@ -292,33 +273,9 @@ DynaActionForm gateForm, ScheduleGateActivity scheduleGate) { - gateForm.set("gate",scheduleGate); - gateForm.set("waitingLearners",new Integer(scheduleGate.getWaitingLearners().size())); gateForm.set("startingTime",scheduleGate.getGateStartDateTime()); gateForm.set("endingTime",scheduleGate.getGateEndDateTime()); - return mapping.findForward(VIEW_SCHEDULE_GATE); } - /** - * Set up the form attributes specific to the synch gate and navigate - * to the synch gate view. - * - * @param mapping An ActionMapping class that will be used by the Action - * class to tell the ActionServlet where to send the end-user. - * @param gateForm The ActionForm class that will contain any data submitted - * by the end-user via a form. - * @param permissionGate the gate acitivty object - * @return An ActionForward class that will be returned to the ActionServlet - * indicating where the user is to go next. - */ - private ActionForward viewSynchGate(ActionMapping mapping, - DynaActionForm gateForm, - SynchGateActivity synchgate) - { - gateForm.set("gate",synchgate); - gateForm.set("waitingLearners",new Integer(synchgate.getWaitingLearners().size())); - return mapping.findForward(VIEW_SYNCH_GATE); - } - }