Index: lams_central/web/WEB-INF/lams.tld =================================================================== diff -u -rc5b655c3c11fa9d9b1d76e0ef602acf6363e45f9 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_central/web/WEB-INF/lams.tld (.../lams.tld) (revision c5b655c3c11fa9d9b1d76e0ef602acf6363e45f9) +++ lams_central/web/WEB-INF/lams.tld (.../lams.tld) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -289,11 +289,6 @@ true - index - false - true - - indexed false true Index: lams_central/web/WEB-INF/struts/struts-config.xml =================================================================== diff -u -r472bcb813040efc160e074021be5c71c15455f00 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_central/web/WEB-INF/struts/struts-config.xml (.../struts-config.xml) (revision 472bcb813040efc160e074021be5c71c15455f00) +++ lams_central/web/WEB-INF/struts/struts-config.xml (.../struts-config.xml) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -14,13 +14,13 @@ - + @@ -72,96 +72,117 @@ - - + + + + + + + + - + - - + + + - - - - - - @@ -358,14 +356,6 @@ /> - - + + - + + + + + + + Index: lams_common/db/sql/create_lams_11_tables.sql =================================================================== diff -u -r6e4ed3724bd76354c2ee43c88979385c4a162a0e -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/db/sql/create_lams_11_tables.sql (.../create_lams_11_tables.sql) (revision 6e4ed3724bd76354c2ee43c88979385c4a162a0e) +++ lams_common/db/sql/create_lams_11_tables.sql (.../create_lams_11_tables.sql) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -395,6 +395,7 @@ , learners_per_group INT(11) , staff_group_id BIGINT(20) DEFAULT 0 , max_number_of_groups INT(3) + , equal_number_of_learners_per_group TINYINT DEFAULT 0 , PRIMARY KEY (grouping_id) , INDEX (grouping_type_id) , CONSTRAINT FK_lams_learning_grouping_1 FOREIGN KEY (grouping_type_id) Index: lams_common/db/sql/insert_types_data.sql =================================================================== diff -u -recb723e58ef77711cca841ce0477febd6647891e -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/db/sql/insert_types_data.sql (.../insert_types_data.sql) (revision ecb723e58ef77711cca841ce0477febd6647891e) +++ lams_common/db/sql/insert_types_data.sql (.../insert_types_data.sql) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -62,6 +62,7 @@ INSERT INTO lams_grouping_type VALUES (1, 'RANDOM_GROUPING'); INSERT INTO lams_grouping_type VALUES (2, 'CHOSEN_GROUPING'); INSERT INTO lams_grouping_type VALUES (3, 'CLASS_GROUPING'); +INSERT INTO lams_grouping_type VALUES (4, 'LEARNER_CHOICE_GROUPING'); INSERT INTO lams_tool_session_type VALUES (1, 'NON_GROUPED'); INSERT INTO lams_tool_session_type VALUES (2, 'GROUPED'); @@ -218,51 +219,51 @@ INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (1, 'en', 'AU', 'English (Australia)', 'LTR', 'en-au'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (2, 'es', 'ES', 'Español', 'LTR', 'es'); +VALUES (2, 'es', 'ES', 'Español', 'LTR', 'es'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (3, 'mi', 'NZ', 'Māori', 'LTR', 'en-au'); +VALUES (3, 'mi', 'NZ', 'MÄ�ori', 'LTR', 'en-au'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (4, 'de', 'DE', 'Deutsch', 'LTR', 'de'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (5, 'zh', 'CN', '简体中文', 'LTR', 'zh-cn'); +VALUES (5, 'zh', 'CN', '简体中文', 'LTR', 'zh-cn'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (6, 'fr', 'FR', 'Français', 'LTR', 'fr'); +VALUES (6, 'fr', 'FR', 'Français', 'LTR', 'fr'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (7, 'it', 'IT', 'Italiano', 'LTR', 'it'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (8, 'no', 'NO', 'Norsk', 'LTR', 'no'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (9, 'sv', 'SE', 'Svenska', 'LTR', 'sv'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (10, 'ko', 'KR', '한국어', 'LTR', 'ko'); +VALUES (10, 'ko', 'KR', '한국어', 'LTR', 'ko'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (11, 'pl', 'PL', 'Polski', 'LTR', 'pl'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (12, 'pt', 'BR', 'Português (Brasil)', 'LTR', 'pt-br'); +VALUES (12, 'pt', 'BR', 'Português (Brasil)', 'LTR', 'pt-br'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (13, 'hu', 'HU', 'Magyar', 'LTR', 'hu'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (14, 'bg', 'BG', 'Български', 'LTR', 'bg'); +VALUES (14, 'bg', 'BG', 'БългарÑ�ки', 'LTR', 'bg'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (15, 'cy', 'GB', 'Cymraeg (Cymru)', 'LTR', 'en-au'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (16, 'th', 'TH', 'Thai', 'LTR', 'th'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (17, 'el', 'GR', 'Ελληνικά', 'LTR', 'el'); +VALUES (17, 'el', 'GR', 'Ελληνικά', 'LTR', 'el'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (18, 'nl', 'BE', 'Nederlands (België)', 'LTR', 'nl'); +VALUES (18, 'nl', 'BE', 'Nederlands (België)', 'LTR', 'nl'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (19, 'ar', 'JO', 'عربي', 'RTL', 'ar'); +VALUES (19, 'ar', 'JO', 'عربي', 'RTL', 'ar'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (20, 'da', 'DK', 'Dansk', 'LTR', 'da'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (21, 'ru', 'RU', 'Русский', 'LTR', 'ru'); +VALUES (21, 'ru', 'RU', 'РуÑ�Ñ�кий', 'LTR', 'ru'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (22, 'vi', 'VN', 'Tiếng Việt', 'LTR', 'vi'); +VALUES (22, 'vi', 'VN', 'Tiếng Việt', 'LTR', 'vi'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (23, 'zh', 'TW', 'Chinese (Taiwan)', 'LTR', 'zh'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) -VALUES (24, 'ja', 'JP', '日本語', 'LTR', 'ja'); +VALUES (24, 'ja', 'JP', '日本語', 'LTR', 'ja'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) VALUES (25, 'ms', 'MY', 'Malay (Malaysia)', 'LTR', 'ms'); INSERT INTO lams_supported_locale (locale_id, language_iso_code, country_iso_code, description, direction, fckeditor_code) Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/Grouping.java =================================================================== diff -u -r571599819061ac30c1e5b146dd1f53edffc534dc -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/Grouping.java (.../Grouping.java) (revision 571599819061ac30c1e5b146dd1f53edffc534dc) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/Grouping.java (.../Grouping.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -55,7 +55,7 @@ /** Grouping type id for lesson class grouping */ public static final Integer CLASS_GROUPING_TYPE = new Integer(3); - /** Grouping type id for lesson class grouping */ + /** Grouping type id for learner's choice grouping */ public static final Integer LEARNER_CHOICE_GROUPING_TYPE = new Integer(4); /** identifier field */ @@ -351,7 +351,7 @@ return new ChosenGrouping(); } else if (groupingType.equals(Grouping.LEARNER_CHOICE_GROUPING_TYPE)) { - return new ChosenGrouping(); + return new LearnerChoiceGrouping(); } else { return new LessonClass(); Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearnerChoiceGrouper.java =================================================================== diff -u -rffe04ed6f14e87fe5069eb707b0e19b5f78f045a -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearnerChoiceGrouper.java (.../LearnerChoiceGrouper.java) (revision ffe04ed6f14e87fe5069eb707b0e19b5f78f045a) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearnerChoiceGrouper.java (.../LearnerChoiceGrouper.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -33,55 +33,54 @@ import org.lamsfoundation.lams.learningdesign.exception.GroupingException; import org.lamsfoundation.lams.usermanagement.User; - /** - * The chosen grouper algorithm implementation. It creates a new group for - * the learners that the teacher requested. + * The learner choice grouper algorithm implementation. It creates a new group for + * the learners that the learner requested. * * @author Jacky Fang * @since 2005-3-24 * @version 1.1 * */ -public class LearnerChoiceGrouper extends Grouper implements Serializable -{ +public class LearnerChoiceGrouper extends Grouper implements Serializable { private static final long serialVersionUID = -8498560084860150033L; private static Logger log = Logger.getLogger(LearnerChoiceGrouper.class); /** - * @see org.lamsfoundation.lams.learningdesign.Grouper#doGrouping(org.lamsfoundation.lams.learningdesign.Grouping,java.lang.String, org.lamsfoundation.lams.usermanagement.User) - */ - public void doGrouping(Grouping learnerChoiceGrouping, String groupName, User learner) - { - //convert the single user into a list. - List learners = new ArrayList(); - learners.add(learner); - //delegate to do grouping for a list of learners. - doGrouping(learnerChoiceGrouping,groupName,learners); - } - - /** - * @see org.lamsfoundation.lams.learningdesign.Grouper#doGrouping(org.lamsfoundation.lams.learningdesign.Grouping,java.lang.String, java.util.List) - */ - public void doGrouping(Grouping learnerChoiceGrouping,String groupName, List learners) - { - Group selectedGroup = null; + * @see org.lamsfoundation.lams.learningdesign.Grouper#doGrouping(org.lamsfoundation.lams.learningdesign.Grouping,java.lang.String, org.lamsfoundation.lams.usermanagement.User) + */ + @Override + public void doGrouping(Grouping learnerChoiceGrouping, String groupName, User learner) { + //convert the single user into a list. + List learners = new ArrayList(); + learners.add(learner); + //delegate to do grouping for a list of learners. + doGrouping(learnerChoiceGrouping, groupName, learners); + } - String trimmedName = groupName != null ? groupName.trim() : null; - if ( trimmedName == null || trimmedName.length() == 0 ) { - trimmedName = generateGroupName(learnerChoiceGrouping); - } else { - Iterator iter = learnerChoiceGrouping.getGroups().iterator(); - while (iter.hasNext() && selectedGroup==null) { + /** + * @see org.lamsfoundation.lams.learningdesign.Grouper#doGrouping(org.lamsfoundation.lams.learningdesign.Grouping,java.lang.String, java.util.List) + */ + @Override + public void doGrouping(Grouping learnerChoiceGrouping, String groupName, List learners) { + Group selectedGroup = null; + + String trimmedName = groupName != null ? groupName.trim() : null; + if (trimmedName == null || trimmedName.length() == 0) { + trimmedName = generateGroupName(learnerChoiceGrouping); + } + else { + Iterator iter = learnerChoiceGrouping.getGroups().iterator(); + while (iter.hasNext() && selectedGroup == null) { Group group = (Group) iter.next(); - if ( trimmedName.equals(group.getGroupName()) ) { + if (trimmedName.equals(group.getGroupName())) { selectedGroup = group; } } - } - doGrouping(learnerChoiceGrouping, selectedGroup, trimmedName, learners); - } + } + doGrouping(learnerChoiceGrouping, selectedGroup, trimmedName, learners); + } /** * @param learnerChoiceGrouping @@ -90,71 +89,94 @@ private String generateGroupName(Grouping learnerChoiceGrouping) { String trimmedName; String prefix = getPrefix(); - trimmedName = prefix+" "+System.currentTimeMillis(); - log.info("Chosen grouper for grouping "+learnerChoiceGrouping.toString()+" did not get a group name. Selecting default name of "+trimmedName); + trimmedName = prefix + " " + System.currentTimeMillis(); + LearnerChoiceGrouper.log.info("Chosen grouper for grouping " + learnerChoiceGrouping.toString() + + " did not get a group name. Selecting default name of " + trimmedName); return trimmedName; } - /** - * @throws GroupingException - * @see org.lamsfoundation.lams.learningdesign.Grouper#doGrouping(org.lamsfoundation.lams.learningdesign.Grouping,java.lang.Long, java.util.List) - */ - public void doGrouping(Grouping learnerChoiceGrouping,Long groupId, List learners) throws GroupingException - { - if ( groupId != null ) { - Iterator iter = learnerChoiceGrouping.getGroups().iterator(); - Group selectedGroup = null; - while (iter.hasNext() && selectedGroup==null) { + /** + * @throws GroupingException + * @see org.lamsfoundation.lams.learningdesign.Grouper#doGrouping(org.lamsfoundation.lams.learningdesign.Grouping,java.lang.Long, java.util.List) + */ + @Override + public void doGrouping(Grouping learnerChoiceGrouping, Long groupId, List learners) throws GroupingException { + if (groupId != null) { + Iterator iter = learnerChoiceGrouping.getGroups().iterator(); + Group selectedGroup = null; + while (iter.hasNext() && selectedGroup == null) { Group group = (Group) iter.next(); - if ( group.getGroupId().equals(groupId) ) { + if (group.getGroupId().equals(groupId)) { selectedGroup = group; } } - if ( selectedGroup == null ) { - String error = "Tried to add users to group "+groupId+" but group cannot be found."; - log.error(error); - throw new GroupingException(error); - } - doGrouping(learnerChoiceGrouping, selectedGroup, null, learners); - } else { - String groupName = generateGroupName(learnerChoiceGrouping); - doGrouping(learnerChoiceGrouping, null, groupName, learners); - } - } + if (selectedGroup == null) { + String error = "Tried to add users to group " + groupId + " but group cannot be found."; + LearnerChoiceGrouper.log.error(error); + throw new GroupingException(error); + } + doGrouping(learnerChoiceGrouping, selectedGroup, null, learners); + } + else { + String groupName = generateGroupName(learnerChoiceGrouping); + doGrouping(learnerChoiceGrouping, null, groupName, learners); + } + } - /** If the group exists add them to the group, otherwise creates a new group. If group is not supplied, then groupName must - * be supplied. - * @param learnerChoiceGrouping (Mandatory) - * @param group (Optional) - * @param groupName (Optional) - * @param learners (Mandatory) - */ - private void doGrouping(Grouping learnerChoiceGrouping, Group group, String groupName, List learners) - { - if ( group != null ) { - group.getUsers().addAll(learners); - } else { - learnerChoiceGrouping.getGroups().add(Group.createLearnerGroup(learnerChoiceGrouping,groupName, - new HashSet(learners))); - } - } - - /** Create an empty group for the given grouping. If the current number of groups = max number of - * groups then a grouping exception is thrown. - * - * @param grouping (mandatory) - * @param groupName (mandatory) - */ - public Group createGroup(Grouping grouping, String name) throws GroupingException - { - int currentSize = grouping.getGroups().size(); - if ( grouping.getMaxNumberOfGroups()!=null && currentSize == grouping.getMaxNumberOfGroups() ) { - String error = "Tried to add group "+name+" to grouping "+grouping+". Exceeded max number of groups - current size is "+currentSize; - log.error(error); - throw new GroupingException(error); - } - return super.createGroup(grouping, name); + /** If the group exists add them to the group, otherwise creates a new group. If group is not supplied, then groupName must + * be supplied. + * @param learnerChoiceGrouping (Mandatory) + * @param group (Optional) + * @param groupName (Optional) + * @param learners (Mandatory) + */ + private void doGrouping(Grouping learnerChoiceGrouping, Group group, String groupName, List learners) { + if (group != null) { + group.getUsers().addAll(learners); + } + else { + learnerChoiceGrouping.getGroups().add( + Group.createLearnerGroup(learnerChoiceGrouping, groupName, new HashSet(learners))); + } + } + /** Create an empty group for the given grouping. If the current number of groups = max number of + * groups then a grouping exception is thrown. + * + * @param grouping (mandatory) + * @param groupName (mandatory) + */ + @Override + public Group createGroup(Grouping grouping, String name) throws GroupingException { + int currentSize = grouping.getGroups().size(); + if (grouping.getMaxNumberOfGroups() != null && currentSize == grouping.getMaxNumberOfGroups()) { + String error = "Tried to add group " + name + " to grouping " + grouping + + ". Exceeded max number of groups - current size is " + currentSize; + LearnerChoiceGrouper.log.error(error); + throw new GroupingException(error); + } + return super.createGroup(grouping, name); + } -} + /** + * Create new groups and insert them into the grouping. Group names + * are Group 1, Group 2, etc. + * @param learnerChoiceGrouping the requested grouping. + * @param numOfGroupsTobeCreated the number new groups need to be created. + */ + public void createGroups(LearnerChoiceGrouping learnerChoiceGrouping, int numOfGroupsTobeCreated) { + String prefix = getPrefix(); + int size = learnerChoiceGrouping.getGroups().size(); + for (int numCreated = 0, groupIndex = size + 1; numCreated < numOfGroupsTobeCreated; groupIndex++) { + String groupName = prefix + " " + new Integer(groupIndex).toString(); + // if the name of the group already exists, then createLearnerGroup will return null + // the name may exist if people have been creating and then removing groups in authoring. + Group newGroup = Group.createLearnerGroup(learnerChoiceGrouping, groupName, new HashSet()); + if (newGroup != null) { + learnerChoiceGrouping.getGroups().add(newGroup); + numCreated++; + } + } + } +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearnerChoiceGrouping.java =================================================================== diff -u -rffe04ed6f14e87fe5069eb707b0e19b5f78f045a -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearnerChoiceGrouping.java (.../LearnerChoiceGrouping.java) (revision ffe04ed6f14e87fe5069eb707b0e19b5f78f045a) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearnerChoiceGrouping.java (.../LearnerChoiceGrouping.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -26,11 +26,19 @@ import java.util.Set; /** - * Grouping formed by learners' choice - * @author chris + * Grouping formed by learner's choice + * @author Marcin Cieslak */ public class LearnerChoiceGrouping extends Grouping { + /** nullable persistent field */ + private Boolean equalNumberOfLearners; + /** nullable persistent field */ + private Integer numberOfGroups; + + /** nullable persistent field */ + private Integer learnersPerGroup; + /** Creates a new instance of ChosenGrouping */ public LearnerChoiceGrouping() { super.grouper = new LearnerChoiceGrouper(); @@ -43,12 +51,15 @@ /** * This method creates a deep copy of the Grouping - * @return ChosenGrouping The deep copied Grouping object + * @return LearnerChoiceGrouping The deep copied Grouping object */ @Override public Grouping createCopy(int uiidOffset) { LearnerChoiceGrouping learnerChoiceGrouping = new LearnerChoiceGrouping(); copyGroupingFields(learnerChoiceGrouping, uiidOffset); + learnerChoiceGrouping.setEqualNumberOfLearners(getEqualNumberOfLearners()); + learnerChoiceGrouping.setLearnersPerGroup(getLearnersPerGroup()); + learnerChoiceGrouping.setNumberOfGroups(getNumberOfGroups()); return learnerChoiceGrouping; } @@ -62,4 +73,28 @@ return true; } + public Boolean getEqualNumberOfLearners() { + return equalNumberOfLearners; + } + + public void setEqualNumberOfLearners(Boolean equalNumberOfLearners) { + this.equalNumberOfLearners = equalNumberOfLearners; + } + + public Integer getLearnersPerGroup() { + return learnersPerGroup; + } + + public void setLearnersPerGroup(Integer learnersPerGroup) { + this.learnersPerGroup = learnersPerGroup; + } + + public Integer getNumberOfGroups() { + return numberOfGroups; + } + + public void setNumberOfGroups(Integer numberOfGroups) { + this.numberOfGroups = numberOfGroups; + } + } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dao/hibernate/GroupingDAO.java =================================================================== diff -u -rb25a6d2d1cebe3c69d4af018aa14198533a0d4c5 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dao/hibernate/GroupingDAO.java (.../GroupingDAO.java) (revision b25a6d2d1cebe3c69d4af018aa14198533a0d4c5) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dao/hibernate/GroupingDAO.java (.../GroupingDAO.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -33,6 +33,7 @@ import org.lamsfoundation.lams.learningdesign.ChosenGrouping; import org.lamsfoundation.lams.learningdesign.Grouping; import org.lamsfoundation.lams.learningdesign.GroupingActivity; +import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouping; import org.lamsfoundation.lams.learningdesign.RandomGrouping; import org.lamsfoundation.lams.learningdesign.dao.IGroupingDAO; import org.springframework.dao.DataRetrievalFailureException; @@ -41,61 +42,66 @@ * @author Manpreet Minhas */ public class GroupingDAO extends BaseDAO implements IGroupingDAO { - - private final static String GROUPINGS_FOR_LEARNING_DESIGN_VIA_CREATE = "select grouping from " - + Grouping.class.getName() + " grouping, " + GroupingActivity.class.getName() + " grouping_activity " - + " where grouping_activity.learningDesign.id = ? " - + " and grouping_activity.createGrouping = grouping"; - private final static String GROUPINGS_FOR_LEARNING_DESIGN_VIA_GROUPING = "select grouping from " - + Grouping.class.getName() + " grouping, " + Activity.class.getName() + " activity " - + " where activity.learningDesign.id = ? " - + " and activity.grouping = grouping"; + private final static String GROUPINGS_FOR_LEARNING_DESIGN_VIA_CREATE = "select grouping from " + Grouping.class.getName() + + " grouping, " + GroupingActivity.class.getName() + " grouping_activity " + + " where grouping_activity.learningDesign.id = ? " + " and grouping_activity.createGrouping = grouping"; + private final static String GROUPINGS_FOR_LEARNING_DESIGN_VIA_GROUPING = "select grouping from " + Grouping.class.getName() + + " grouping, " + Activity.class.getName() + " activity " + " where activity.learningDesign.id = ? " + + " and activity.grouping = grouping"; + /** * @see org.lamsfoundation.lams.learningdesign.dao.interfaces.IGroupingDAO#getGroupingById(java.lang.Long) */ public Grouping getGroupingById(Long groupingID) { - Grouping grouping = (Grouping)super.find(Grouping.class,groupingID); + Grouping grouping = (Grouping) super.find(Grouping.class, groupingID); return getNonCGLibGrouping(grouping); } - /** - * Returns the list of groupings applicable for the given learning design. This is a combination of the groupings defined - * via a GroupingActivity.createGrouping (which may or may not be applied to any other activities in the design) and groupings - * related to branches and which are not attached to a GroupingActivity. - */ - public List getGroupingsByLearningDesign(Long learningDesignId){ - List groupingsA = this.getHibernateTemplate().find(GROUPINGS_FOR_LEARNING_DESIGN_VIA_CREATE,learningDesignId); - List groupingsB = this.getHibernateTemplate().find(GROUPINGS_FOR_LEARNING_DESIGN_VIA_GROUPING,learningDesignId); - HashMap realGroupings = new HashMap(); - Iterator iter = groupingsA.iterator(); - while (iter.hasNext()) { + /** + * Returns the list of groupings applicable for the given learning design. This is a combination of the groupings defined + * via a GroupingActivity.createGrouping (which may or may not be applied to any other activities in the design) and groupings + * related to branches and which are not attached to a GroupingActivity. + */ + public List getGroupingsByLearningDesign(Long learningDesignId) { + List groupingsA = this.getHibernateTemplate() + .find(GroupingDAO.GROUPINGS_FOR_LEARNING_DESIGN_VIA_CREATE, learningDesignId); + List groupingsB = this.getHibernateTemplate().find(GroupingDAO.GROUPINGS_FOR_LEARNING_DESIGN_VIA_GROUPING, + learningDesignId); + HashMap realGroupings = new HashMap(); + Iterator iter = groupingsA.iterator(); + while (iter.hasNext()) { Grouping element = (Grouping) iter.next(); realGroupings.put(element.getGroupingId(), getNonCGLibGrouping(element)); } - iter = groupingsB.iterator(); - while (iter.hasNext()) { + iter = groupingsB.iterator(); + while (iter.hasNext()) { Grouping element = (Grouping) iter.next(); - if ( ! realGroupings.containsKey(element.getGroupingId()) ) + if (!realGroupings.containsKey(element.getGroupingId())) { realGroupings.put(element.getGroupingId(), getNonCGLibGrouping(element)); + } } - return new ArrayList(realGroupings.values()); - } + return new ArrayList(realGroupings.values()); + } /** we must return the real grouping, not a Hibernate proxy. So relook * it up. This should be quick as it should be in the cache. */ private Grouping getNonCGLibGrouping(Grouping grouping) { - if ( grouping != null ) { - if ( grouping.isRandomGrouping() ) { - return (Grouping)super.find(RandomGrouping.class,grouping.getGroupingId()); - } else if ( grouping.isChosenGrouping() ) { - return (Grouping)super.find(ChosenGrouping.class,grouping.getGroupingId()); + if (grouping != null) { + if (grouping.isRandomGrouping()) { + return (Grouping) super.find(RandomGrouping.class, grouping.getGroupingId()); } - throw new DataRetrievalFailureException("Unable to get grouping as the grouping type is unknown or missing. Grouping object is "+grouping); + else if (grouping.isChosenGrouping()) { + return (Grouping) super.find(ChosenGrouping.class, grouping.getGroupingId()); + } + else if (grouping.isLearnerChoiceGrouping()) { + return (Grouping) super.find(LearnerChoiceGrouping.class, grouping.getGroupingId()); + } + throw new DataRetrievalFailureException( + "Unable to get grouping as the grouping type is unknown or missing. Grouping object is " + grouping); } return null; } - } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/GroupingDTO.java =================================================================== diff -u -r19a9225d5d9ba59e2600b57c3c8e968ffc9ee351 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/GroupingDTO.java (.../GroupingDTO.java) (revision 19a9225d5d9ba59e2600b57c3c8e968ffc9ee351) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/GroupingDTO.java (.../GroupingDTO.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -31,50 +31,50 @@ import org.lamsfoundation.lams.learningdesign.ChosenGrouping; import org.lamsfoundation.lams.learningdesign.Group; import org.lamsfoundation.lams.learningdesign.Grouping; +import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouping; import org.lamsfoundation.lams.learningdesign.RandomGrouping; import org.lamsfoundation.lams.lesson.LessonClass; import org.lamsfoundation.lams.util.wddx.WDDXTAGS; /** * @author Manpreet Minhas */ -public class GroupingDTO extends BaseDTO{ - +public class GroupingDTO extends BaseDTO { + private Long groupingID; private Integer groupingUIID; private Integer groupingTypeID; private Integer numberOfGroups; private Integer learnersPerGroup; private Long staffGroupID; private Integer maxNumberOfGroups; + private Boolean equalNumberOfLearners; //list of GroupDTO private List groups; - - public GroupingDTO(Long groupingID, Integer groupingUIID, - Integer groupingType, Integer numberOfGroups, - Integer learnersPerGroup, Long staffGroupID, - Integer maxNumberOfGroups,List groupDTOs) { + public GroupingDTO(Long groupingID, Integer groupingUIID, Integer groupingType, Integer numberOfGroups, + Integer learnersPerGroup, Long staffGroupID, Integer maxNumberOfGroups, List groupDTOs) { this.groupingID = groupingID; this.groupingUIID = groupingUIID; - this.groupingTypeID = groupingType; + groupingTypeID = groupingType; this.numberOfGroups = numberOfGroups; this.learnersPerGroup = learnersPerGroup; this.staffGroupID = staffGroupID; this.maxNumberOfGroups = maxNumberOfGroups; - this.groups = groupDTOs; + groups = groupDTOs; } - public GroupingDTO(Grouping grouping, boolean setupUserList){ - this.groupingID = grouping.getGroupingId(); - this.groupingUIID = grouping.getGroupingUIID(); - this.maxNumberOfGroups = grouping.getMaxNumberOfGroups(); - this.groupingTypeID = grouping.getGroupingTypeId(); + + public GroupingDTO(Grouping grouping, boolean setupUserList) { + groupingID = grouping.getGroupingId(); + groupingUIID = grouping.getGroupingUIID(); + maxNumberOfGroups = grouping.getMaxNumberOfGroups(); + groupingTypeID = grouping.getGroupingTypeId(); Set groupSet = grouping.getGroups(); groups = new ArrayList(); - if(groupSet != null){ + if (groupSet != null) { Iterator iter = groupSet.iterator(); - while(iter.hasNext()){ - groups.add(((Group)iter.next()).getGroupDTO(setupUserList)); + while (iter.hasNext()) { + groups.add(((Group) iter.next()).getGroupDTO(setupUserList)); } } /*The two lines of code below are commented out, because it creates a new grouping instance and then tries to @@ -84,123 +84,170 @@ //processGroupingActivity(object); processGroupingActivity(grouping); } - public void processGroupingActivity(Object object){ - if(object instanceof RandomGrouping) - addRandomGroupingAttributes((RandomGrouping)object); - else if (object instanceof ChosenGrouping) - addChosenGroupingAttributes((ChosenGrouping)object); - else - addLessonClassAttributes((LessonClass)object); + + public void processGroupingActivity(Object object) { + if (object instanceof RandomGrouping) { + addRandomGroupingAttributes((RandomGrouping) object); + } + else if (object instanceof ChosenGrouping) { + addChosenGroupingAttributes((ChosenGrouping) object); + } + else if (object instanceof LearnerChoiceGrouping) { + addLearnerChoiceGroupingAttributes((LearnerChoiceGrouping) object); + } + else { + addLessonClassAttributes((LessonClass) object); + } } - private void addRandomGroupingAttributes(RandomGrouping grouping){ - this.learnersPerGroup = grouping.getLearnersPerGroup(); - this.numberOfGroups = grouping.getNumberOfGroups(); + + private void addRandomGroupingAttributes(RandomGrouping grouping) { + learnersPerGroup = grouping.getLearnersPerGroup(); + numberOfGroups = grouping.getNumberOfGroups(); } - private void addChosenGroupingAttributes(ChosenGrouping grouping){ - + + private void addChosenGroupingAttributes(ChosenGrouping grouping) { + } - private void addLessonClassAttributes(LessonClass grouping){ - this.staffGroupID = grouping.getStaffGroup().getGroupId(); + + private void addLearnerChoiceGroupingAttributes(LearnerChoiceGrouping grouping) { + learnersPerGroup = grouping.getLearnersPerGroup(); + numberOfGroups = grouping.getNumberOfGroups(); + equalNumberOfLearners = grouping.getEqualNumberOfLearners(); } + + private void addLessonClassAttributes(LessonClass grouping) { + staffGroupID = grouping.getStaffGroup().getGroupId(); + } + /** * @return Returns the groupingID. */ public Long getGroupingID() { return groupingID; } + /** * @param groupingID The groupingID to set. */ public void setGroupingID(Long groupingID) { - if(!groupingID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) + if (!groupingID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { this.groupingID = groupingID; + } } + /** * @return Returns the groupingType. */ public Integer getGroupingTypeID() { return groupingTypeID; } + /** * @param groupingType The groupingType to set. */ public void setGroupingTypeID(Integer groupingType) { - if(!groupingType.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) - this.groupingTypeID = groupingType; + if (!groupingType.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { + groupingTypeID = groupingType; + } } + /** * @return Returns the groupingUIID. */ public Integer getGroupingUIID() { return groupingUIID; } + /** * @param groupingUIID The groupingUIID to set. */ public void setGroupingUIID(Integer groupingUIID) { - if(!groupingUIID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) + if (!groupingUIID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { this.groupingUIID = groupingUIID; + } } + /** * @return Returns the learnersPerGroup. */ public Integer getLearnersPerGroup() { return learnersPerGroup; } + /** * @param learnersPerGroup The learnersPerGroup to set. */ public void setLearnersPerGroup(Integer learnersPerGroup) { - if(!learnersPerGroup.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) + if (!learnersPerGroup.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { this.learnersPerGroup = learnersPerGroup; + } } + /** * @return Returns the maxNumberOfGroups. */ public Integer getMaxNumberOfGroups() { return maxNumberOfGroups; } + /** * @param maxNumberOfGroups The maxNumberOfGroups to set. */ public void setMaxNumberOfGroups(Integer maxNumberOfGroups) { - if(!maxNumberOfGroups.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) + if (!maxNumberOfGroups.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { this.maxNumberOfGroups = maxNumberOfGroups; + } } + /** * @return Returns the numberOfGroups. */ public Integer getNumberOfGroups() { return numberOfGroups; } + /** * @param numberOfGroups The numberOfGroups to set. */ public void setNumberOfGroups(Integer numberOfGroups) { - if(!numberOfGroups.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) + if (!numberOfGroups.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { this.numberOfGroups = numberOfGroups; + } } + /** * @return Returns the staffGroupID. */ public Long getStaffGroupID() { return staffGroupID; } + /** * @param staffGroupID The staffGroupID to set. */ public void setStaffGroupID(Long staffGroupID) { - if(!staffGroupID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) + if (!staffGroupID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { this.staffGroupID = staffGroupID; + } } + /** * * @return group list belongs to this grouping. */ public List getGroups() { return groups; } + public void setGroups(List groups) { this.groups = groups; } + + public Boolean getEqualNumberOfLearners() { + return equalNumberOfLearners; + } + + public void setEqualNumberOfLearners(Boolean equalNumberOfLearners) { + this.equalNumberOfLearners = equalNumberOfLearners; + } } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/ValidationErrorDTO.java =================================================================== diff -u -rdff974ef2462e40cacf7f8c737fc6ec4bb501806 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/ValidationErrorDTO.java (.../ValidationErrorDTO.java) (revision dff974ef2462e40cacf7f8c737fc6ec4bb501806) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/ValidationErrorDTO.java (.../ValidationErrorDTO.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -26,36 +26,36 @@ import org.apache.struts.util.MessageResources; import org.lamsfoundation.lams.learningdesign.LearningDesign; - public class ValidationErrorDTO { - + /** Struts Message Resource related variables */ - public static final String CONFIG_PARAM = "org.lamsfoundation.lams.applicationResources"; // Code: - public static final String OTHER_ERROR_KEY = "validation.error.other"; // O - public static final String TRANSITION_ERROR_KEY = "validation.error.transitionNoActivityBeforeOrAfter"; // T - public static final String ACTIVITY_TRANSITION_ERROR_KEY= "validation.error.activityWithNoTransition"; // AT - public static final String INPUT_TRANSITION_ERROR_TYPE1_KEY = "validation.error.inputTransitionType1"; // IT - public static final String INPUT_TRANSITION_ERROR_TYPE2_KEY = "validation.error.inputTransitionType2"; - public static final String OUTPUT_TRANSITION_ERROR_TYPE1_KEY = "validation.error.outputTransitionType1"; // OT - public static final String OUTPUT_TRANSITION_ERROR_TYPE2_KEY = "validation.error.outputTransitionType2"; - public static final String GROUPING_REQUIRED_ERROR_KEY = "validation.error.GroupingRequired"; // GR - public static final String GROUPING_NOT_REQUIRED_ERROR_KEY = "validation.error.GroupingNotRequired"; // GNR - public static final String GROUPING_SELECTED_ERROR_KEY = "validation.error.GroupingSelected"; // GS - public static final String OPTIONAL_ACTIVITY_ERROR_KEY = "validation.error.OptionalActivity"; // OA - public static final String OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY = "validation.error.OptionalActivityOrderId"; // OAOI - public static final String SCHEDULE_GATE_ERROR_TYPE1_KEY = "validation.error.illegalScheduleGateOffsetsType1"; // SG - public static final String SCHEDULE_GATE_ERROR_TYPE2_KEY = "validation.error.illegalScheduleGateOffsetsType2"; - public static final String GROUPING_ACTIVITY_MISSING_GROUPING_KEY = "validation.error.grouping.missing"; // GM - public static final String GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY = "validation.error.group.count.mismatch"; // GC - public static final String BRANCHING_ACTIVITY_MUST_HAVE_A_BRANCH = "validation.error.branching.must.have.a.branch"; // BB - public static final String BRANCHING_ACTIVITY_MUST_HAVE_DEFAULT_BRANCH = "validation.error.toolBranchingMustHaveDefaultBranch"; // BDB - public static final String SEQUENCE_ACTIVITY_MUST_HAVE_FIRST_ACTIVITY = "validation.error.sequenceActivityMustHaveFirstActivity"; // SFA - public static final String BRANCHING_ACTVITY_GROUPING = "validation.error.groupedBranchingMustHaveAGrouping"; //BGG + public static final String CONFIG_PARAM = "org.lamsfoundation.lams.applicationResources"; // Code: + public static final String OTHER_ERROR_KEY = "validation.error.other"; // O + public static final String TRANSITION_ERROR_KEY = "validation.error.transitionNoActivityBeforeOrAfter"; // T + public static final String ACTIVITY_TRANSITION_ERROR_KEY = "validation.error.activityWithNoTransition"; // AT + public static final String INPUT_TRANSITION_ERROR_TYPE1_KEY = "validation.error.inputTransitionType1"; // IT + public static final String INPUT_TRANSITION_ERROR_TYPE2_KEY = "validation.error.inputTransitionType2"; + public static final String OUTPUT_TRANSITION_ERROR_TYPE1_KEY = "validation.error.outputTransitionType1"; // OT + public static final String OUTPUT_TRANSITION_ERROR_TYPE2_KEY = "validation.error.outputTransitionType2"; + public static final String GROUPING_REQUIRED_ERROR_KEY = "validation.error.GroupingRequired"; // GR + public static final String GROUPING_NOT_REQUIRED_ERROR_KEY = "validation.error.GroupingNotRequired"; // GNR + public static final String GROUPING_SELECTED_ERROR_KEY = "validation.error.GroupingSelected"; // GS + public static final String OPTIONAL_ACTIVITY_ERROR_KEY = "validation.error.OptionalActivity"; // OA + public static final String OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY = "validation.error.OptionalActivityOrderId"; // OAOI + public static final String SCHEDULE_GATE_ERROR_TYPE1_KEY = "validation.error.illegalScheduleGateOffsetsType1"; // SG + public static final String SCHEDULE_GATE_ERROR_TYPE2_KEY = "validation.error.illegalScheduleGateOffsetsType2"; + public static final String GROUPING_ACTIVITY_MISSING_GROUPING_KEY = "validation.error.grouping.missing"; // GM + public static final String GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY = "validation.error.group.count.mismatch"; // GC + + public static final String BRANCHING_ACTIVITY_MUST_HAVE_A_BRANCH = "validation.error.branching.must.have.a.branch"; // BB + public static final String BRANCHING_ACTIVITY_MUST_HAVE_DEFAULT_BRANCH = "validation.error.toolBranchingMustHaveDefaultBranch"; // BDB + public static final String SEQUENCE_ACTIVITY_MUST_HAVE_FIRST_ACTIVITY = "validation.error.sequenceActivityMustHaveFirstActivity"; // SFA + public static final String BRANCHING_ACTVITY_GROUPING = "validation.error.groupedBranchingMustHaveAGrouping"; //BGG public static final String BRANCHING_ACTVITY_MUST_HAVE_ALL_GROUPS_ALLOCATED = "validation.error.groupedBranchingMustHaveBranchForGroup"; //BGM - public static final String BRANCH_CONDITION_INVALID = "validation.error.toolBranchingConditionInvalid"; // BCOND - public static final String BRANCHING_ACTVITY_TOOLINPUT = "validation.error.toolBranchingMustHaveAnInputToolActivity"; // BTI - public static final String BRANCHING_ACTVITY_TOOLCONDITION = "validation.error.toolBranchingMustHaveACondition"; // BTC - + public static final String BRANCH_CONDITION_INVALID = "validation.error.toolBranchingConditionInvalid"; // BCOND + public static final String BRANCHING_ACTVITY_TOOLINPUT = "validation.error.toolBranchingMustHaveAnInputToolActivity"; // BTI + public static final String BRANCHING_ACTVITY_TOOLCONDITION = "validation.error.toolBranchingMustHaveACondition"; // BTC + public static final String OTHER_ERROR_CODE = "O"; public static final String TRANSITION_ERROR_CODE = "T"; public static final String ACTIVITY_TRANSITION_ERROR_CODE = "AT"; @@ -77,135 +77,143 @@ public static final String BRANCH_CONDITION_INVALID_ERROR_CODE = "BCOND"; public static final String BRANCHING_ACTVITY_TOOLINPUT_ERROR_CODE = "BTI"; public static final String BRANCHING_ACTVITY_TOOLCONDITION_ERROR_CODE = "BTC"; - - - private static MessageResources resources = MessageResources.getMessageResources(CONFIG_PARAM); + + private static MessageResources resources = MessageResources.getMessageResources(ValidationErrorDTO.CONFIG_PARAM); /** * Rule: Other (Covers any cases that are not covered by another code) */ - public static final String OTHER_ERROR = resources.getMessage(OTHER_ERROR_KEY); - + public static final String OTHER_ERROR = ValidationErrorDTO.resources.getMessage(ValidationErrorDTO.OTHER_ERROR_KEY); + /** * Rule: Each transition must have an activity before and after the transition */ - public static final String TRANSITION_ERROR = resources.getMessage(TRANSITION_ERROR_KEY); - + public static final String TRANSITION_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.TRANSITION_ERROR_KEY); + /** * Rule: Exactly one top level activity will have no input transition * If more than one activity is missing an input transition */ - public static final String INPUT_TRANSITION_ERROR_TYPE1 = resources.getMessage(INPUT_TRANSITION_ERROR_TYPE1_KEY); - + public static final String INPUT_TRANSITION_ERROR_TYPE1 = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.INPUT_TRANSITION_ERROR_TYPE1_KEY); + /** * Rule: Exactly one top level activity will have no input transition * If no activities are missing their input transitions */ - public static final String INPUT_TRANSITION_ERROR_TYPE2= resources.getMessage(INPUT_TRANSITION_ERROR_TYPE2_KEY); - + public static final String INPUT_TRANSITION_ERROR_TYPE2 = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.INPUT_TRANSITION_ERROR_TYPE2_KEY); + /** * Rule: Exactly one top level activity will have no output transition * If more than one activity is missing the output transition. */ - public static final String OUTPUT_TRANSITION_ERROR_TYPE1 = resources.getMessage(OUTPUT_TRANSITION_ERROR_TYPE1_KEY); - + public static final String OUTPUT_TRANSITION_ERROR_TYPE1 = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_TYPE1_KEY); + /** * Rule: Exactly one top level activity will have no output transition * If no activities are missing their output transitions. */ - public static final String OUTPUT_TRANSITION_ERROR_TYPE2 = resources.getMessage(OUTPUT_TRANSITION_ERROR_TYPE2_KEY); - + public static final String OUTPUT_TRANSITION_ERROR_TYPE2 = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_TYPE2_KEY); + /** * Rule: If grouping is required then a grouping must have been applied to the activity */ - public static final String GROUPING_REQUIRED_ERROR = resources.getMessage(GROUPING_REQUIRED_ERROR_KEY); - + public static final String GROUPING_REQUIRED_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.GROUPING_REQUIRED_ERROR_KEY); + /** * Rule: If grouping is not supported/required, then a grouping has not been applied to the activity. */ - public static final String GROUPING_NOT_REQUIRED_ERROR = resources.getMessage(GROUPING_NOT_REQUIRED_ERROR_KEY); - + public static final String GROUPING_NOT_REQUIRED_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.GROUPING_NOT_REQUIRED_ERROR_KEY); + /** * Rule: If grouping is selected, then grouping exists */ - public static final String GROUPING_SELECTED_ERROR = resources.getMessage(GROUPING_SELECTED_ERROR_KEY); - + public static final String GROUPING_SELECTED_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.GROUPING_SELECTED_ERROR_KEY); + /** * Rule: An optional activity must contain one or more activities */ - public static final String OPTIONAL_ACTIVITY_ERROR = resources.getMessage(OPTIONAL_ACTIVITY_ERROR_KEY); - + public static final String OPTIONAL_ACTIVITY_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.OPTIONAL_ACTIVITY_ERROR_KEY); + /** * Rule: An optional activity must have valid order ids - the order ids should be * sequential starting at 1 and must have no duplicates. */ - public static final String OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR = resources.getMessage(OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY); - + public static final String OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY); + /** * Rule: For any learning design that has more than one activity then each activity should * have at least one input or one output transition. */ - public static final String ACTIVITY_TRANSITION_ERROR = resources.getMessage(ACTIVITY_TRANSITION_ERROR_KEY); + public static final String ACTIVITY_TRANSITION_ERROR = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_KEY); /** * Rule: For Schedule Gates (Activity) if start and end time offsets are set they should not be equal. */ - public static final String SCHEDULE_GATE_ERROR_TYPE1 = resources.getMessage(SCHEDULE_GATE_ERROR_TYPE1_KEY); - - + public static final String SCHEDULE_GATE_ERROR_TYPE1 = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.SCHEDULE_GATE_ERROR_TYPE1_KEY); + /** * Rule: For Schedule Gates (Activity) if start and end time offsets are set then the start time offset should be * greater than the end time offset. */ - public static final String SCHEDULE_GATE_ERROR_TYPE2 = resources.getMessage(SCHEDULE_GATE_ERROR_TYPE2_KEY); - + public static final String SCHEDULE_GATE_ERROR_TYPE2 = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.SCHEDULE_GATE_ERROR_TYPE2_KEY); + /** * Rule: For Grouping Activities there must be a grouping. */ - public static final String GROUPING_ACTIVITY_MISSING_GROUPING = resources.getMessage(GROUPING_ACTIVITY_MISSING_GROUPING_KEY); // GM + public static final String GROUPING_ACTIVITY_MISSING_GROUPING = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_MISSING_GROUPING_KEY); // GM /** * Rule: For Grouping Activities the number of groups must be less than or equal to the desired number. */ - public static final String GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH = resources.getMessage(GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY); // GC + public static final String GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH = ValidationErrorDTO.resources + .getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY); // GC private Integer UIID; private String message; //the validation message explaining what the problem is - private String code; // unique code representing the validation error message - - public ValidationErrorDTO(String code, String message, Integer UIID) - { + private String code; // unique code representing the validation error message + + public ValidationErrorDTO(String code, String message, Integer UIID) { this.code = code; - this.message = message; + this.message = message; this.UIID = UIID; - - + } - - public ValidationErrorDTO(String code, String message) - { + + public ValidationErrorDTO(String code, String message) { this.code = code; this.message = message; } - public ValidationErrorDTO(LearningDesign learningDesign) - { - + public ValidationErrorDTO(LearningDesign learningDesign) { + } - - public ValidationErrorDTO() - { + + public ValidationErrorDTO() { } - + public String getCode() { return code; } + public String getMessage() { return message; } + public Integer getUIID() { return UIID; } - - } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r8def510853894da340f0420ade8dd145a81d55df -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 8def510853894da340f0420ade8dd145a81d55df) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -87,6 +87,7 @@ import org.lamsfoundation.lams.learningdesign.Group; import org.lamsfoundation.lams.learningdesign.Grouping; import org.lamsfoundation.lams.learningdesign.GroupingActivity; +import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouping; import org.lamsfoundation.lams.learningdesign.LearningDesign; import org.lamsfoundation.lams.learningdesign.License; import org.lamsfoundation.lams.learningdesign.OptionsActivity; @@ -139,6 +140,7 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; + /** * Export tool content service bean. * @author Steve.Ni @@ -147,11 +149,11 @@ */ public class ExportToolContentService implements IExportToolContentService, ApplicationContextAware { private static final int PACKAGE_FORMAT_IMS = 2; - + public static final String LEARNING_DESIGN_SERVICE_BEAN_NAME = "learningDesignService"; public static final String MESSAGE_SERVICE_BEAN_NAME = "commonMessageService"; public static final String LD102IMPORTER_BEAN_NAME = "ld102Importer"; - + //export tool content zip file prefix public static final String EXPORT_TOOLCONTNET_ZIP_PREFIX = "lams_toolcontent_"; public static final String EXPORT_LDCONTENT_ZIP_PREFIX = "lams_ldcontent_"; @@ -162,19 +164,19 @@ private static final String LEARNING_DESIGN_IMS_FILE_NAME = "imsmanifest.xml"; public static final String TOOL_FILE_NAME = "tool.xml"; public static final String TOOL_FAILED_FILE_NAME = "export_failed.xml"; - + private static final String ERROR_TOOL_NOT_FOUND = "error.import.matching.tool.not.found"; private static final String ERROR_SERVICE_ERROR = "error.import.tool.service.fail"; private static final String ERROR_NO_VALID_TOOL = "error.no.valid.tool"; private static final String ERROR_INCOMPATIBLE_VERSION = "error.possibly.incompatible.version"; private static final String FILTER_METHOD_PREFIX_DOWN = "down"; private static final String FILTER_METHOD_PREFIX_UP = "up"; private static final String FILTER_METHOD_MIDDLE = "To"; - + // LAMS export format tag names private static final String LAMS_VERSION = "version"; private static final String LAMS_TITLE = "title"; - + //IMS format some tag name private static final String IMS_FILE_NAME_EXT = "_imsld"; private static final String IMS_TAG_RESOURCES = "resources"; @@ -209,12 +211,12 @@ // this is not IMS standard tag, term used to ref grouping/gate activities private static final String IMS_TAG_GROUPING = "group"; private static final String IMS_TAG_GATE = "gate"; - + private static final String IMS_TAG_OPTIONAL = "SELECTION"; private static final String IMS_TAG_PARALLEL = "PARALLEL"; private static final String IMS_TAG_SEQUENCE = "SEQUENCE"; private static final String IMS_TAG_BRANCHING = "BRANCHING"; - + //temporarily file for IMS XSLT file private static final String XSLT_PARAM_RESOURCE_FILE = "resourcesFile"; private static final String IMS_RESOURCES_FILE_NAME = "resources.xml"; @@ -224,7 +226,7 @@ private static final String IMS_PROPERTIES_FILE_NAME = "properties.xml"; private static final String XSLT_PARAM_CONDITIONS_FILE = "conditionsFile"; private static final String IMS_CONDITIONS_FILE_NAME = "conditions.xml"; - + private static final String IMS_TOOL_NS_PREFIX = "http://www.lamsfoundation/xsd/lams_tool_"; private static final String IMS_TAG_LEARING_ACTIVITY_REF = "learning-activity-ref"; @@ -240,18 +242,18 @@ private static final String SCHEMA_FILE_IMS_LD_LEVEL_A = "IMS_LD_Level_A.xsd"; private static final String SCHEMA_FILE_IMS_LD_LEVEL_B = "IMS_LD_Level_B.xsd"; private static final String SCHEMA_FILE_IMS_LD_LEVEL_C = "IMS_LD_Level_C.xsd"; - + //Other fields private Logger log = Logger.getLogger(ExportToolContentService.class); - + private static MessageService messageService; private ApplicationContext applicationContext; - + //save list of all tool file node class information. One tool may have over one file node, such as //in share resource tool, it has contnent attachment and shared resource item attachement. private List fileHandleClassList; - private Class filterClass; - + private Class filterClass; + //spring injection properties private IActivityDAO activityDAO; private IToolDAO toolDAO; @@ -260,22 +262,18 @@ private IBaseDAO baseDAO; private ILicenseDAO licenseDAO; private IGroupingDAO groupingDAO; - private ITransitionDAO transitionDAO; + private ITransitionDAO transitionDAO; private ILearningDesignDAO learningDesignDAO; private ILearningLibraryDAO learningLibraryDAO; private IToolImportSupportDAO toolImportSupportDAO; + private static final String KEY_MSG_IMPORT_FILE_FORMAT = "msg.import.file.format"; - private static final String KEY_MSG_IMPORT_FILE_FORMAT = "msg.import.file.format"; - - - /** * Class of tool attachment file handler class and relative fields information container. */ - private class NameInfo{ - - + private class NameInfo { + //the Class instance according to className. public String className; public String uuidFieldName; @@ -284,15 +282,15 @@ public String mimeTypeFieldName; public String filePropertyFieldName; public String initalItemFieldName; - - public NameInfo(String className, String uuidFieldName, String versionFieldName){ + + public NameInfo(String className, String uuidFieldName, String versionFieldName) { this.className = className; this.uuidFieldName = uuidFieldName; this.versionFieldName = versionFieldName; } - public NameInfo(String className, String uuidFieldName, String versionFieldName, - String fileNameFieldName, String filePropertyFieldName,String mimeTypeFieldName, - String initalItemFieldName) { + + public NameInfo(String className, String uuidFieldName, String versionFieldName, String fileNameFieldName, + String filePropertyFieldName, String mimeTypeFieldName, String initalItemFieldName) { this.className = className; this.uuidFieldName = uuidFieldName; this.versionFieldName = versionFieldName; @@ -302,103 +300,111 @@ this.initalItemFieldName = initalItemFieldName; } } - + /** * File node value information container. */ - private class ValueInfo{ + private class ValueInfo { //for unmarshal public NameInfo name; public Object instance; - + //for marshal public Long fileUuid; public Long fileVersionId; - - public ValueInfo(NameInfo name, Object instance){ + + public ValueInfo(NameInfo name, Object instance) { this.name = name; this.instance = instance; } - - public ValueInfo(Long uuid, Long versionId){ - this.fileUuid = uuid; - this.fileVersionId = versionId; + + public ValueInfo(Long uuid, Long versionId) { + fileUuid = uuid; + fileVersionId = versionId; } } + /** * Proxy class for Default XStream converter. * */ - private class FileInvocationHandler implements InvocationHandler{ - + private class FileInvocationHandler implements InvocationHandler { + private Object obj; private List fileNodes; private List fileHandleClassList; - public FileInvocationHandler(Object obj){ + + public FileInvocationHandler(Object obj) { this.obj = obj; - this.fileNodes = new ArrayList(); + fileNodes = new ArrayList(); } + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result; try { - //for export : marshal object to xml - if(StringUtils.equals(method.getName(),"marshal")){ - for(NameInfo name:fileHandleClassList){ - if(args[0] != null && name.className.equals((args[0].getClass().getName()))){ - Long uuid = NumberUtils.createLong(BeanUtils.getProperty(args[0],name.uuidFieldName)); - if(uuid != null){ + //for export : marshal object to xml + if (StringUtils.equals(method.getName(), "marshal")) { + for (NameInfo name : fileHandleClassList) { + if (args[0] != null && name.className.equals(args[0].getClass().getName())) { + Long uuid = NumberUtils.createLong(BeanUtils.getProperty(args[0], name.uuidFieldName)); + if (uuid != null) { //version id is optional Long version = null; - if(name.versionFieldName != null) - version = NumberUtils.createLong(BeanUtils.getProperty(args[0],name.versionFieldName)); - log.debug("XStream get file node ["+uuid +"," + version +"]."); - fileNodes.add(ExportToolContentService.this.new ValueInfo(uuid,version)); + if (name.versionFieldName != null) { + version = NumberUtils.createLong(BeanUtils.getProperty(args[0], name.versionFieldName)); + } + log.debug("XStream get file node [" + uuid + "," + version + "]."); + fileNodes.add(ExportToolContentService.this.new ValueInfo(uuid, version)); } - } - } - } + } + } + } - if(StringUtils.equals(method.getName(),"canConvert")){ - boolean canConvert = false; - for(NameInfo info:fileHandleClassList){ - if(args[0] != null && info.className.equals(((Class)args[0]).getName())){ - log.debug("XStream will handle ["+info.className+"] as file node class."); - canConvert = true; - break; - } - } - return canConvert; - } - - result = method.invoke(obj, args); - -// for import : unmarshal xml to object - if(StringUtils.equals(method.getName(),"unmarshal") && result != null){ - //During deserialize XML file into object, it will save file node into fileNodes - for(NameInfo name:fileHandleClassList){ - if(name.className.equals(result.getClass().getName())){ - fileNodes.add(ExportToolContentService.this.new ValueInfo(name,result)); - break; - } - } - } - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - + if (StringUtils.equals(method.getName(), "canConvert")) { + boolean canConvert = false; + for (NameInfo info : fileHandleClassList) { + if (args[0] != null && info.className.equals(((Class) args[0]).getName())) { + log.debug("XStream will handle [" + info.className + "] as file node class."); + canConvert = true; + break; + } + } + return canConvert; + } + + result = method.invoke(obj, args); + + // for import : unmarshal xml to object + if (StringUtils.equals(method.getName(), "unmarshal") && result != null) { + //During deserialize XML file into object, it will save file node into fileNodes + for (NameInfo name : fileHandleClassList) { + if (name.className.equals(result.getClass().getName())) { + fileNodes.add(ExportToolContentService.this.new ValueInfo(name, result)); + break; + } + } + } + } + catch (InvocationTargetException e) { + throw e.getTargetException(); + } + return result; } public List getFileNodes() { return fileNodes; } + public List getFileHandleClassList() { return fileHandleClassList; } + public void setFileHandleClassList(List fileHandleClassList) { this.fileHandleClassList = fileHandleClassList; } } + /** * This class is just for later system extent tool compaiblity strategy use. Currently, it just * simple to get tool by same signature. @@ -407,136 +413,155 @@ * * @version $Revision$ */ - public class ToolCompatibleStrategy{ - public Tool getTool(String toolSignature){ + public class ToolCompatibleStrategy { + public Tool getTool(String toolSignature) { return toolDAO.getToolBySignature(toolSignature); } } + /** * Default contructor method. */ - public ExportToolContentService(){ + public ExportToolContentService() { fileHandleClassList = new ArrayList(); } + /** * @see org.lamsfoundation.lams.authoring.service.IExportToolContentService.exportLearningDesign(Long) */ - public String exportLearningDesign(Long learningDesignId, List toolsErrorMsgs,int format,File xslt) throws ExportToolContentException{ + public String exportLearningDesign(Long learningDesignId, List toolsErrorMsgs, int format, File xslt) + throws ExportToolContentException { try { //root temp directory, put target zip file String targetZipFileName = null; - String rootDir = FileUtil.createTempDirectory(EXPORT_TOOLCONTNET_FOLDER_SUFFIX); - String contentDir = FileUtil.getFullPath(rootDir,DIR_CONTENT); + String rootDir = FileUtil.createTempDirectory(ExportToolContentService.EXPORT_TOOLCONTNET_FOLDER_SUFFIX); + String contentDir = FileUtil.getFullPath(rootDir, ExportToolContentService.DIR_CONTENT); FileUtil.createDirectory(contentDir); - + //this folder put all IMS XSLT transform temporary files, so try to keep content is clean for final package! //The reason use temporary folder instead of delete temporary files from content folder is, sometimes, delete file does not work well //this makes the final zip file should contain some rubbish files. - String xsltTempDir = FileUtil.getFullPath(rootDir, DIR_XSLT_TEMP); - if(format == PACKAGE_FORMAT_IMS){ + String xsltTempDir = FileUtil.getFullPath(rootDir, ExportToolContentService.DIR_XSLT_TEMP); + if (format == ExportToolContentService.PACKAGE_FORMAT_IMS) { FileUtil.createDirectory(xsltTempDir); } //learing design file name with full path String ldFileName; - if(format == PACKAGE_FORMAT_IMS) - ldFileName = FileUtil.getFullPath(xsltTempDir,LEARNING_DESIGN_FILE_NAME); - else - ldFileName = FileUtil.getFullPath(contentDir,LEARNING_DESIGN_FILE_NAME); - Writer ldFile = new OutputStreamWriter(new FileOutputStream(ldFileName),"UTF-8"); - + if (format == ExportToolContentService.PACKAGE_FORMAT_IMS) { + ldFileName = FileUtil.getFullPath(xsltTempDir, ExportToolContentService.LEARNING_DESIGN_FILE_NAME); + } + else { + ldFileName = FileUtil.getFullPath(contentDir, ExportToolContentService.LEARNING_DESIGN_FILE_NAME); + } + Writer ldFile = new OutputStreamWriter(new FileOutputStream(ldFileName), "UTF-8"); + // get learning desing and serialize it to XML file. Update the version to reflect the // version now, rather than the version when it was saved. - ILearningDesignService service = getLearningDesignService(); + ILearningDesignService service = getLearningDesignService(); LearningDesignDTO ldDto = service.getLearningDesignDTO(learningDesignId, ""); ldDto.setVersion(Configuration.get(ConfigurationKeys.SERVER_VERSION_NUMBER)); - - if(format == PACKAGE_FORMAT_IMS) - ldDto.setTitle(ldDto.getTitle().concat(IMS_FILE_NAME_EXT)); - + + if (format == ExportToolContentService.PACKAGE_FORMAT_IMS) { + ldDto.setTitle(ldDto.getTitle().concat(ExportToolContentService.IMS_FILE_NAME_EXT)); + } + XStream designXml = new XStream(); - designXml.toXML(ldDto,ldFile); + designXml.toXML(ldDto, ldFile); ldFile.close(); - + log.debug("Learning design xml export success"); - + //iterator all activities in this learning design and export their content to given folder. //The content will contain tool.xml and attachment files of tools from LAMS repository. List activities = ldDto.getActivities(); - + //create resources Dom node list for IMS package. List resChildren = new ArrayList(); - + //iterator all activities and export tool.xml and its attachments - for(AuthoringActivityDTO activity : activities){ - + for (AuthoringActivityDTO activity : activities) { + //skip non-tool activities - if(activity.getActivityTypeID().intValue() != Activity.TOOL_ACTIVITY_TYPE) + if (activity.getActivityTypeID().intValue() != Activity.TOOL_ACTIVITY_TYPE) { continue; - + } + //find out current acitivites toolContentMananger and export tool content. - ToolContentManager contentManager = (ToolContentManager) findToolService(toolDAO.getToolByID(activity.getToolID())); - log.debug("Tool export content : " + activity.getActivityTitle() +" by contentID :" + activity.getToolContentID()); - try{ - contentManager.exportToolContent(activity.getToolContentID(),contentDir); - }catch (Exception e) { + ToolContentManager contentManager = (ToolContentManager) findToolService(toolDAO + .getToolByID(activity.getToolID())); + log.debug("Tool export content : " + activity.getActivityTitle() + " by contentID :" + + activity.getToolContentID()); + try { + contentManager.exportToolContent(activity.getToolContentID(), contentDir); + } + catch (Exception e) { String msg = activity.getToolDisplayName() + " export tool content failed:" + e.toString(); - log.error(msg,e); + log.error(msg, e); //Try to delete tool.xml. This makes export_failed and tool.xml does not exist simultaneously. - String toolPath = FileUtil.getFullPath(contentDir,activity.getToolContentID().toString()); - String toolFileName = FileUtil.getFullPath(toolPath,TOOL_FILE_NAME); + String toolPath = FileUtil.getFullPath(contentDir, activity.getToolContentID().toString()); + String toolFileName = FileUtil.getFullPath(toolPath, ExportToolContentService.TOOL_FILE_NAME); File toolFile = new File(toolFileName); - if(toolFile.exists()) + if (toolFile.exists()) { toolFile.delete(); - writeErrorToToolFile(contentDir,activity.getToolContentID(),msg); + } + writeErrorToToolFile(contentDir, activity.getToolContentID(), msg); toolsErrorMsgs.add(msg); - } - + } + //create resource node list for this activity - if(format == PACKAGE_FORMAT_IMS){ - handleIMS(rootDir, activity,resChildren); + if (format == ExportToolContentService.PACKAGE_FORMAT_IMS) { + handleIMS(rootDir, activity, resChildren); } } //end all activities export - + try { //handle IMS format - if(format == PACKAGE_FORMAT_IMS){ - transformIMS(resChildren,rootDir,ldDto,xslt); + if (format == ExportToolContentService.PACKAGE_FORMAT_IMS) { + transformIMS(resChildren, rootDir, ldDto, xslt); } //create zip file for fckeditor unique content folder - String targetContentZipFileName = EXPORT_LDCONTENT_ZIP_PREFIX + ldDto.getContentFolderID() + EXPORT_LDCONTENT_ZIP_SUFFIX; - String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR + File.separator + FileUtil.LAMS_WWW_SECURE_DIR; - String ldContentDir = FileUtil.getFullPath(secureDir,ldDto.getContentFolderID()); - - if(!FileUtil.isEmptyDirectory(ldContentDir, true)) { - log.debug("Create export Learning Design content target zip file. File name is " + targetContentZipFileName); - ZipFileUtil.createZipFile(targetContentZipFileName, ldContentDir, contentDir); - } else { + String targetContentZipFileName = ExportToolContentService.EXPORT_LDCONTENT_ZIP_PREFIX + + ldDto.getContentFolderID() + ExportToolContentService.EXPORT_LDCONTENT_ZIP_SUFFIX; + String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR + + File.separator + FileUtil.LAMS_WWW_SECURE_DIR; + String ldContentDir = FileUtil.getFullPath(secureDir, ldDto.getContentFolderID()); + + if (!FileUtil.isEmptyDirectory(ldContentDir, true)) { + log.debug("Create export Learning Design content target zip file. File name is " + targetContentZipFileName); + ZipFileUtil.createZipFile(targetContentZipFileName, ldContentDir, contentDir); + } + else { log.debug("No such directory (or empty directory):" + ldContentDir); } - - } catch (Exception e) { + + } + catch (Exception e) { log.error("Error thrown while creating IMS LD XML", e); throw new ExportToolContentException(e); } - + // zip file name with full path - targetZipFileName = ldDto.getTitle() + EXPORT_TOOLCONTNET_ZIP_SUFFIX; - + targetZipFileName = ldDto.getTitle() + ExportToolContentService.EXPORT_TOOLCONTNET_ZIP_SUFFIX; + log.debug("Create export content target zip file. File name is " + targetZipFileName); //create zip file and return zip full file name - return ZipFileUtil.createZipFile(targetZipFileName, contentDir,rootDir); - } catch (FileUtilException e) { - log.error("FileUtilException:",e); + return ZipFileUtil.createZipFile(targetZipFileName, contentDir, rootDir); + } + catch (FileUtilException e) { + log.error("FileUtilException:", e); throw new ExportToolContentException(e); - } catch (ZipFileUtilException e) { - log.error("ZipFileUtilException:",e); + } + catch (ZipFileUtilException e) { + log.error("ZipFileUtilException:", e); throw new ExportToolContentException(e); - } catch (IOException e) { - log.error("IOException:",e); + } + catch (IOException e) { + log.error("IOException:", e); throw new ExportToolContentException(e); } } + /** * Generate temporary files: resources.xml and transitions.xml.
* Transform LAMS format learning_design.xml with resources.xml and transitions.xml into ims_learning_design.xml file. @@ -545,44 +570,44 @@ * @param ldDto * @throws Exception */ - private void transformIMS(List resChildren, String rootDir,LearningDesignDTO ldDto,File xsltIn) throws Exception { - String contentDir = FileUtil.getFullPath(rootDir, DIR_CONTENT); - String xsltDir = FileUtil.getFullPath(rootDir, DIR_XSLT_TEMP); - - String ldFileName = FileUtil.getFullPath(xsltDir,LEARNING_DESIGN_FILE_NAME); + private void transformIMS(List resChildren, String rootDir, LearningDesignDTO ldDto, File xsltIn) throws Exception { + String contentDir = FileUtil.getFullPath(rootDir, ExportToolContentService.DIR_CONTENT); + String xsltDir = FileUtil.getFullPath(rootDir, ExportToolContentService.DIR_XSLT_TEMP); + + String ldFileName = FileUtil.getFullPath(xsltDir, ExportToolContentService.LEARNING_DESIGN_FILE_NAME); //copy XSLT file to contentDir, so that the XSLT document() function does not need absolute path file. File xslt = new File(FileUtil.getFullPath(xsltDir, "ims.xslt")); FileUtil.copyFile(xsltIn, xslt); - + //copy schema files to content folder String path = FileUtil.getFileDirectory(xsltIn.getCanonicalPath()); - File imscpSrc = new File(FileUtil.getFullPath(path,SCHEMA_FILE_IMSCP)); - File imsldaSrc = new File(FileUtil.getFullPath(path,SCHEMA_FILE_IMS_LD_LEVEL_A)); - File imsldbSrc = new File(FileUtil.getFullPath(path,SCHEMA_FILE_IMS_LD_LEVEL_B)); - File imsldcSrc = new File(FileUtil.getFullPath(path,SCHEMA_FILE_IMS_LD_LEVEL_C)); - File imscpTar = new File(FileUtil.getFullPath(contentDir,SCHEMA_FILE_IMSCP)); - File imsldaTar = new File(FileUtil.getFullPath(contentDir,SCHEMA_FILE_IMS_LD_LEVEL_A)); - File imsldbTar = new File(FileUtil.getFullPath(contentDir,SCHEMA_FILE_IMS_LD_LEVEL_B)); - File imsldcTar = new File(FileUtil.getFullPath(contentDir,SCHEMA_FILE_IMS_LD_LEVEL_C)); + File imscpSrc = new File(FileUtil.getFullPath(path, ExportToolContentService.SCHEMA_FILE_IMSCP)); + File imsldaSrc = new File(FileUtil.getFullPath(path, ExportToolContentService.SCHEMA_FILE_IMS_LD_LEVEL_A)); + File imsldbSrc = new File(FileUtil.getFullPath(path, ExportToolContentService.SCHEMA_FILE_IMS_LD_LEVEL_B)); + File imsldcSrc = new File(FileUtil.getFullPath(path, ExportToolContentService.SCHEMA_FILE_IMS_LD_LEVEL_C)); + File imscpTar = new File(FileUtil.getFullPath(contentDir, ExportToolContentService.SCHEMA_FILE_IMSCP)); + File imsldaTar = new File(FileUtil.getFullPath(contentDir, ExportToolContentService.SCHEMA_FILE_IMS_LD_LEVEL_A)); + File imsldbTar = new File(FileUtil.getFullPath(contentDir, ExportToolContentService.SCHEMA_FILE_IMS_LD_LEVEL_B)); + File imsldcTar = new File(FileUtil.getFullPath(contentDir, ExportToolContentService.SCHEMA_FILE_IMS_LD_LEVEL_C)); FileUtil.copyFile(imscpSrc, imscpTar); FileUtil.copyFile(imsldaSrc, imsldaTar); FileUtil.copyFile(imsldbSrc, imsldbTar); FileUtil.copyFile(imsldcSrc, imsldcTar); - + //create resources.xml file Document resourcesDom = new Document(); - Element resRoot = new Element(IMS_TAG_RESOURCES); + Element resRoot = new Element(ExportToolContentService.IMS_TAG_RESOURCES); resRoot.setChildren(resChildren); resourcesDom.setRootElement(resRoot); - File resFile = new File(FileUtil.getFullPath(xsltDir,IMS_RESOURCES_FILE_NAME)); + File resFile = new File(FileUtil.getFullPath(xsltDir, ExportToolContentService.IMS_RESOURCES_FILE_NAME)); XMLOutputter resOutput = new XMLOutputter(); resOutput.output(resourcesDom, new FileOutputStream(resFile)); - + log.debug("Export IMS: Resources file generated sucessfully:" + resFile.getAbsolutePath()); - + //create transitions Dom node list for IMS package Document transDom = new Document(); - Element transRoot = new Element(IMS_TAG_TRANSITIONS); + Element transRoot = new Element(ExportToolContentService.IMS_TAG_TRANSITIONS); List transChildren = new ArrayList(); //create transitions DOM file List sortedActList = getSortedActivities(ldDto); @@ -591,102 +616,121 @@ // Can't just do it for all sequences as the sequence could be in an optional activity Set branchingActivityIds = new HashSet(); for (AuthoringActivityDTO actDto : sortedActList) { - if ( actDto.getActivityTypeID().equals(Activity.CHOSEN_BRANCHING_ACTIVITY_TYPE) || actDto.getActivityTypeID().equals(Activity.GROUP_BRANCHING_ACTIVITY_TYPE) - || actDto.getActivityTypeID().equals(Activity.TOOL_BRANCHING_ACTIVITY_TYPE) ) + if (actDto.getActivityTypeID().equals(Activity.CHOSEN_BRANCHING_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.GROUP_BRANCHING_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.TOOL_BRANCHING_ACTIVITY_TYPE)) { branchingActivityIds.add(actDto.getActivityID()); + } } - + Document propertiesDom = new Document(); - Element propertiesRoot = new Element(IMS_TAG_PROPERTIES); + Element propertiesRoot = new Element(ExportToolContentService.IMS_TAG_PROPERTIES); List propertiesChildren = new ArrayList(); Document conditionsDom = new Document(); - Element conditionsRoot = new Element(IMS_TAG_CONDITIONS); + Element conditionsRoot = new Element(ExportToolContentService.IMS_TAG_CONDITIONS); List conditionsChildren = new ArrayList(); for (AuthoringActivityDTO actDto : sortedActList) { - log.debug("Export IMS: Put actitivies " + actDto.getActivityTitle() + "[" +actDto.getToolContentID()+"] into Transition tag."); - + log.debug("Export IMS: Put actitivies " + actDto.getActivityTitle() + "[" + actDto.getToolContentID() + + "] into Transition tag."); + // All sequence activities are within braching or an optional sequence, so they don't go into the transition list. - if(actDto.getActivityTypeID().equals(Activity.SEQUENCE_ACTIVITY_TYPE)) { - String attributeValue = IMS_PREFIX_COMPLEX_REF + IMS_TAG_SEQUENCE + "-" + actDto.getActivityID(); - if ( actDto.getParentActivityID() != null && branchingActivityIds.contains(actDto.getParentActivityID()) ) { - Element[] propertyConditions = generatePropertyCondition(actDto.getActivityID(),attributeValue); + if (actDto.getActivityTypeID().equals(Activity.SEQUENCE_ACTIVITY_TYPE)) { + String attributeValue = ExportToolContentService.IMS_PREFIX_COMPLEX_REF + + ExportToolContentService.IMS_TAG_SEQUENCE + "-" + actDto.getActivityID(); + if (actDto.getParentActivityID() != null && branchingActivityIds.contains(actDto.getParentActivityID())) { + Element[] propertyConditions = generatePropertyCondition(actDto.getActivityID(), attributeValue); propertiesChildren.add(propertyConditions[0]); conditionsChildren.add(propertyConditions[1]); conditionsChildren.add(propertyConditions[2]); conditionsChildren.add(propertyConditions[3]); - } + } - } else if ( actDto.getParentActivityID() == null ) { + } + else if (actDto.getParentActivityID() == null) { // Only want to add it to the list of transition activities if it is the top level, as this generates the initial sequence. Attribute att = null; - if(actDto.getActivityTypeID().equals(Activity.GROUPING_ACTIVITY_TYPE)) - att = new Attribute(IMS_ATTR_REF,IMS_PREFIX_ACTIVITY_REF + IMS_TAG_GROUPING + "-" + actDto.getActivityID()); - else if(actDto.getActivityTypeID().equals(Activity.SCHEDULE_GATE_ACTIVITY_TYPE) || actDto.getActivityTypeID().equals(Activity.PERMISSION_GATE_ACTIVITY_TYPE) - || actDto.getActivityTypeID().equals(Activity.SYNCH_GATE_ACTIVITY_TYPE) || actDto.getActivityTypeID().equals(Activity.SYSTEM_GATE_ACTIVITY_TYPE)) - att = new Attribute(IMS_ATTR_REF,IMS_PREFIX_ACTIVITY_REF + IMS_TAG_GATE + "-" + actDto.getActivityID()); + if (actDto.getActivityTypeID().equals(Activity.GROUPING_ACTIVITY_TYPE)) { + att = new Attribute(ExportToolContentService.IMS_ATTR_REF, ExportToolContentService.IMS_PREFIX_ACTIVITY_REF + + ExportToolContentService.IMS_TAG_GROUPING + "-" + actDto.getActivityID()); + } + else if (actDto.getActivityTypeID().equals(Activity.SCHEDULE_GATE_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.PERMISSION_GATE_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.SYNCH_GATE_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.SYSTEM_GATE_ACTIVITY_TYPE)) { + att = new Attribute(ExportToolContentService.IMS_ATTR_REF, ExportToolContentService.IMS_PREFIX_ACTIVITY_REF + + ExportToolContentService.IMS_TAG_GATE + "-" + actDto.getActivityID()); + } else if (actDto.getActivityTypeID().equals(Activity.OPTIONS_ACTIVITY_TYPE) - || actDto.getActivityTypeID().equals(Activity.OPTIONS_WITH_SEQUENCES_TYPE)) - att = new Attribute(IMS_ATTR_REF, IMS_PREFIX_COMPLEX_REF + IMS_TAG_OPTIONAL + "-" + actDto.getActivityID()); - else if(actDto.getActivityTypeID().equals(Activity.PARALLEL_ACTIVITY_TYPE)) - att = new Attribute(IMS_ATTR_REF, IMS_PREFIX_COMPLEX_REF + IMS_TAG_PARALLEL + "-" + actDto.getActivityID()); - else if(actDto.getActivityTypeID().equals(Activity.CHOSEN_BRANCHING_ACTIVITY_TYPE) || actDto.getActivityTypeID().equals(Activity.GROUP_BRANCHING_ACTIVITY_TYPE) - || actDto.getActivityTypeID().equals(Activity.TOOL_BRANCHING_ACTIVITY_TYPE) ) - att = new Attribute(IMS_ATTR_REF, IMS_PREFIX_COMPLEX_REF + IMS_TAG_BRANCHING + "-" + actDto.getActivityID()); - else - att = new Attribute(IMS_ATTR_REF,IMS_PREFIX_ACTIVITY_REF + actDto.getToolSignature() + "-" + actDto.getToolContentID()); + || actDto.getActivityTypeID().equals(Activity.OPTIONS_WITH_SEQUENCES_TYPE)) { + att = new Attribute(ExportToolContentService.IMS_ATTR_REF, ExportToolContentService.IMS_PREFIX_COMPLEX_REF + + ExportToolContentService.IMS_TAG_OPTIONAL + "-" + actDto.getActivityID()); + } + else if (actDto.getActivityTypeID().equals(Activity.PARALLEL_ACTIVITY_TYPE)) { + att = new Attribute(ExportToolContentService.IMS_ATTR_REF, ExportToolContentService.IMS_PREFIX_COMPLEX_REF + + ExportToolContentService.IMS_TAG_PARALLEL + "-" + actDto.getActivityID()); + } + else if (actDto.getActivityTypeID().equals(Activity.CHOSEN_BRANCHING_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.GROUP_BRANCHING_ACTIVITY_TYPE) + || actDto.getActivityTypeID().equals(Activity.TOOL_BRANCHING_ACTIVITY_TYPE)) { + att = new Attribute(ExportToolContentService.IMS_ATTR_REF, ExportToolContentService.IMS_PREFIX_COMPLEX_REF + + ExportToolContentService.IMS_TAG_BRANCHING + "-" + actDto.getActivityID()); + } + else { + att = new Attribute(ExportToolContentService.IMS_ATTR_REF, ExportToolContentService.IMS_PREFIX_ACTIVITY_REF + + actDto.getToolSignature() + "-" + actDto.getToolContentID()); + } - Element ref = new Element(IMS_TAG_LEARING_ACTIVITY_REF); + Element ref = new Element(ExportToolContentService.IMS_TAG_LEARING_ACTIVITY_REF); ref.setAttribute(att); transChildren.add(ref); } } transRoot.setChildren(transChildren); transDom.setRootElement(transRoot); - File transFile = new File(FileUtil.getFullPath(xsltDir,IMS_TRANSITION_FILE_NAME)); + File transFile = new File(FileUtil.getFullPath(xsltDir, ExportToolContentService.IMS_TRANSITION_FILE_NAME)); XMLOutputter transOutput = new XMLOutputter(); transOutput.output(transDom, new FileOutputStream(transFile)); log.debug("Export IMS: Transtion() file generated sucess: " + transFile.getAbsolutePath()); // create the properties file and conditions file - needed for gate showing gates when open and branches when determined propertiesRoot.setChildren(propertiesChildren); propertiesDom.setRootElement(propertiesRoot); - File propertiesFile = new File(FileUtil.getFullPath(xsltDir,IMS_PROPERTIES_FILE_NAME)); + File propertiesFile = new File(FileUtil.getFullPath(xsltDir, ExportToolContentService.IMS_PROPERTIES_FILE_NAME)); XMLOutputter propertiesOutput = new XMLOutputter(); propertiesOutput.output(propertiesDom, new FileOutputStream(propertiesFile)); log.debug("Export IMS: Properties file generated sucess: " + propertiesFile.getAbsolutePath()); conditionsRoot.setChildren(conditionsChildren); conditionsDom.setRootElement(conditionsRoot); - File conditionsFile = new File(FileUtil.getFullPath(xsltDir,IMS_CONDITIONS_FILE_NAME)); + File conditionsFile = new File(FileUtil.getFullPath(xsltDir, ExportToolContentService.IMS_CONDITIONS_FILE_NAME)); XMLOutputter conditionsOutput = new XMLOutputter(); conditionsOutput.output(conditionsDom, new FileOutputStream(conditionsFile)); log.debug("Export IMS: Conditions file generated sucess: " + conditionsFile.getAbsolutePath()); //call XSLT to create ims XML file //put parameters: transitions and resources file name Map params = new HashMap(); - params.put(XSLT_PARAM_RESOURCE_FILE, IMS_RESOURCES_FILE_NAME); - params.put(XSLT_PARAM_TRANSITION_FILE, IMS_TRANSITION_FILE_NAME); - params.put(XSLT_PARAM_PROPERTIES_FILE, IMS_PROPERTIES_FILE_NAME); - params.put(XSLT_PARAM_CONDITIONS_FILE, IMS_CONDITIONS_FILE_NAME); - + params.put(ExportToolContentService.XSLT_PARAM_RESOURCE_FILE, ExportToolContentService.IMS_RESOURCES_FILE_NAME); + params.put(ExportToolContentService.XSLT_PARAM_TRANSITION_FILE, ExportToolContentService.IMS_TRANSITION_FILE_NAME); + params.put(ExportToolContentService.XSLT_PARAM_PROPERTIES_FILE, ExportToolContentService.IMS_PROPERTIES_FILE_NAME); + params.put(ExportToolContentService.XSLT_PARAM_CONDITIONS_FILE, ExportToolContentService.IMS_CONDITIONS_FILE_NAME); + //transform log.debug("Export IMS: Starting transform IMS XML by XSLT..."); - Document odoc = transform(new FileInputStream(new File(ldFileName)), xslt,params); - + Document odoc = transform(new FileInputStream(new File(ldFileName)), xslt, params); + log.debug("Export IMS: Transform IMS XML by XSLT sucess."); //output IMS format LD XML - String imsLdFileName = FileUtil.getFullPath(contentDir,LEARNING_DESIGN_IMS_FILE_NAME); + String imsLdFileName = FileUtil.getFullPath(contentDir, ExportToolContentService.LEARNING_DESIGN_IMS_FILE_NAME); XMLOutputter output = new XMLOutputter(); output.output(odoc, new FileOutputStream(new File(imsLdFileName))); - + log.debug("Export IMS: IMS XML is saved sucessfully."); - } /** Generate the nodes for a property and the related conditions. The first element is the property, which goes @@ -698,53 +742,53 @@ private Element[] generatePropertyCondition(Long activityId, String learningActivityRefName) { Element[] returnArray = new Element[4]; - String propertyName = IMS_PREFIX_PROPERTY_REF + "VISIBLE-"+activityId; - + String propertyName = ExportToolContentService.IMS_PREFIX_PROPERTY_REF + "VISIBLE-" + activityId; + // Setup the property first - Element locpersProperty = new Element(IMS_TAG_LOCPERS_PROPERTY); - locpersProperty.setAttribute(new Attribute(IMS_ATTR_IDENTIFIER, propertyName)); + Element locpersProperty = new Element(ExportToolContentService.IMS_TAG_LOCPERS_PROPERTY); + locpersProperty.setAttribute(new Attribute(ExportToolContentService.IMS_ATTR_IDENTIFIER, propertyName)); locpersProperty.setChildren(new ArrayList()); - Element el = new Element(IMS_TAG_DATATYPE); - el.setAttribute(new Attribute(IMS_ATTR_DATATYPE, "boolean")); + Element el = new Element(ExportToolContentService.IMS_TAG_DATATYPE); + el.setAttribute(new Attribute(ExportToolContentService.IMS_ATTR_DATATYPE, "boolean")); locpersProperty.getChildren().add(el); - el = new Element(IMS_TAG_INITIAL_VALUE); + el = new Element(ExportToolContentService.IMS_TAG_INITIAL_VALUE); el.setText("false"); locpersProperty.getChildren().add(el); returnArray[0] = locpersProperty; // set up the if - Element ifthenelseElement = new Element(IMS_TAG_IF); - Element is = new Element(IMS_TAG_IS); - el = new Element(IMS_TAG_PROPERTY_REF); - el.setAttribute(new Attribute(IMS_ATTR_REF, propertyName)); + Element ifthenelseElement = new Element(ExportToolContentService.IMS_TAG_IF); + Element is = new Element(ExportToolContentService.IMS_TAG_IS); + el = new Element(ExportToolContentService.IMS_TAG_PROPERTY_REF); + el.setAttribute(new Attribute(ExportToolContentService.IMS_ATTR_REF, propertyName)); is.getChildren().add(el); - el = new Element(IMS_TAG_PROPERTY_VALUE); + el = new Element(ExportToolContentService.IMS_TAG_PROPERTY_VALUE); el.setText("true"); is.getChildren().add(el); ifthenelseElement.getChildren().add(is); returnArray[1] = ifthenelseElement; // set up the then - show activity - ifthenelseElement = new Element(IMS_TAG_THEN); - Element showHideElement = new Element(IMS_TAG_SHOW); - Element activityRef = new Element(IMS_TAG_LEARING_ACTIVITY_REF); - activityRef.setAttribute(new Attribute(IMS_ATTR_REF, learningActivityRefName)); + ifthenelseElement = new Element(ExportToolContentService.IMS_TAG_THEN); + Element showHideElement = new Element(ExportToolContentService.IMS_TAG_SHOW); + Element activityRef = new Element(ExportToolContentService.IMS_TAG_LEARING_ACTIVITY_REF); + activityRef.setAttribute(new Attribute(ExportToolContentService.IMS_ATTR_REF, learningActivityRefName)); showHideElement.getChildren().add(activityRef); ifthenelseElement.getChildren().add(showHideElement); returnArray[2] = ifthenelseElement; // set up the else - hide activity - ifthenelseElement = new Element(IMS_TAG_ELSE); - showHideElement = new Element(IMS_TAG_HIDE); - activityRef = new Element(IMS_TAG_LEARING_ACTIVITY_REF); - activityRef.setAttribute(new Attribute(IMS_ATTR_REF, learningActivityRefName)); + ifthenelseElement = new Element(ExportToolContentService.IMS_TAG_ELSE); + showHideElement = new Element(ExportToolContentService.IMS_TAG_HIDE); + activityRef = new Element(ExportToolContentService.IMS_TAG_LEARING_ACTIVITY_REF); + activityRef.setAttribute(new Attribute(ExportToolContentService.IMS_ATTR_REF, learningActivityRefName)); showHideElement.getChildren().add(activityRef); ifthenelseElement.getChildren().add(showHideElement); returnArray[3] = ifthenelseElement; return returnArray; } - + /** * This quite complex method will return a sorted acitivityDTO list according to current LD DTO. *
@@ -760,87 +804,90 @@ List sortedList = new ArrayList(); List sortedActList = new ArrayList(); List transList = ldDto.getTransitions(); - + Long firstActId = ldDto.getFirstActivityID(); - HashMap activities = new HashMap(); + HashMap activities = new HashMap(); // Put first activity into sorted list and copy the rest of the activities into a working map so we can find them easily. // They can be removed from the map as we go so we don't reprocess them. Iterator iter = ldDto.getActivities().iterator(); while (iter.hasNext()) { AuthoringActivityDTO activityDTO = (AuthoringActivityDTO) iter.next(); - if(activityDTO.getActivityID().equals(firstActId)){ + if (activityDTO.getActivityID().equals(firstActId)) { sortedActList.add(activityDTO); - }else{ + } + else { activities.put(activityDTO.getActivityID(), activityDTO); } } List firstActList = new ArrayList(); - + //try find a sorted transition list. - if(transList != null){ + if (transList != null) { Long actId = firstActId; firstActList.add(actId); - - for(int idx=0;idx< 5000;idx++){ + + for (int idx = 0; idx < 5000; idx++) { boolean find = false; //iterator all transition to find next activity for (TransitionDTO transitionDTO : transList) { - if(transitionDTO.getFromActivityID().equals(actId)){ + if (transitionDTO.getFromActivityID().equals(actId)) { //achieve this sequence end sortedList.add(transitionDTO); actId = transitionDTO.getToActivityID(); - + //put next activity into sorted list AuthoringActivityDTO activityDTO = activities.get(actId); - if ( activityDTO != null ) { + if (activityDTO != null) { sortedActList.add(activityDTO); activities.remove(actId); - } + } find = true; break; } } - - if(actId == null || transList.size() == sortedList.size()) + + if (actId == null || transList.size() == sortedList.size()) { break; - + } + //already achieve one sequence end, but it still exist unsorted transition, it means //this ld is broken one, there are at least two "first act" (there is no "transition to") - if(!find){ - for (AuthoringActivityDTO act: activities.values()) { + if (!find) { + for (AuthoringActivityDTO act : activities.values()) { boolean isFirst = true; for (TransitionDTO tranDto : transList) { //there is some transition to this act, it is not "head activity" then skip this act. - if(tranDto.getToActivityID().equals(act.getActivityID())){ + if (tranDto.getToActivityID().equals(act.getActivityID())) { isFirst = false; break; } } //if it is "head activity" and it has not been used - if(isFirst && !firstActList.contains(act.getActivityID())){ + if (isFirst && !firstActList.contains(act.getActivityID())) { actId = act.getActivityID(); firstActList.add(actId); //put next activity into sorted list AuthoringActivityDTO activityDTO = activities.get(actId); - if ( activityDTO != null ) { + if (activityDTO != null) { sortedActList.add(activityDTO); activities.remove(actId); - } + } break; } } } //end find another "head activity" - } + } } //there are some sole activities exist in this LD,append them into sorted list end. - if(activities.size()>0){ + if (activities.size() > 0) { sortedActList.addAll(activities.values()); } return sortedActList; } + /** * Move LAMS tool.xml from tool folder to export content root folder and modify it to {toolContentID}.xml file. Cache all attachement files * from this tool into ArrayList, which will be save into a temporary file (resources.xml) and used by XSLT. @@ -851,152 +898,172 @@ * @throws IOException * @throws FileNotFoundException */ - private void handleIMS(String rootDir, AuthoringActivityDTO activity, List resChildren) throws IOException, FileNotFoundException { - String contentDir = FileUtil.getFullPath(rootDir, DIR_CONTENT); - String xsltDir = FileUtil.getFullPath(rootDir, DIR_XSLT_TEMP); - - String toolPath = FileUtil.getFullPath(contentDir,activity.getToolContentID().toString()); + private void handleIMS(String rootDir, AuthoringActivityDTO activity, List resChildren) throws IOException, + FileNotFoundException { + String contentDir = FileUtil.getFullPath(rootDir, ExportToolContentService.DIR_CONTENT); + String xsltDir = FileUtil.getFullPath(rootDir, ExportToolContentService.DIR_XSLT_TEMP); + + String toolPath = FileUtil.getFullPath(contentDir, activity.getToolContentID().toString()); File toolDir = new File(toolPath); - if(toolDir != null){ + if (toolDir != null) { String[] allfiles = toolDir.list(); - for (String filename: allfiles) { + for (String filename : allfiles) { //handle tool.xml file if it is - if(StringUtils.equals(filename, TOOL_FILE_NAME)){ - String toolFileName = FileUtil.getFullPath(toolPath,TOOL_FILE_NAME); + if (StringUtils.equals(filename, ExportToolContentService.TOOL_FILE_NAME)) { + String toolFileName = FileUtil.getFullPath(toolPath, ExportToolContentService.TOOL_FILE_NAME); File toolFile = new File(toolFileName); SAXBuilder sax = new SAXBuilder(); try { - log.debug("Export IMS: Start transforming tool.xml in " + activity.getActivityTitle() + "[" +activity.getToolContentID()+"]"); - + log.debug("Export IMS: Start transforming tool.xml in " + activity.getActivityTitle() + "[" + + activity.getToolContentID() + "]"); + Document doc = sax.build(new FileInputStream(toolFile)); Element root = doc.getRootElement(); //cache DTO object class and transform it into a tag : for later import use by XStream. String mainObject = root.getName(); root.setName(activity.getToolSignature()); - Namespace ns = Namespace.getNamespace(IMS_TOOL_NS_PREFIX+activity.getToolSignature()+"_ims.xsd"); + Namespace ns = Namespace.getNamespace(ExportToolContentService.IMS_TOOL_NS_PREFIX + + activity.getToolSignature() + "_ims.xsd"); root.setNamespace(ns); - + //add mainObject tag: it save the Tool DTO class name. It is useful when importing by XStream (perhaps a future function) - Element mainObjectEle = new Element(IMS_TOOL_MAIN_OBJECT); + Element mainObjectEle = new Element(ExportToolContentService.IMS_TOOL_MAIN_OBJECT); mainObjectEle.setText(mainObject); root.addContent(mainObjectEle); - + updateNamespaceForChildren(root, ns); - + //create a new tools.xml file with toolContentID.xml as name. - File imsToolFile = new File(FileUtil.getFullPath(xsltDir,activity.getToolContentID().toString()+".xml")); + File imsToolFile = new File(FileUtil + .getFullPath(xsltDir, activity.getToolContentID().toString() + ".xml")); XMLOutputter toolOutput = new XMLOutputter(); toolOutput.output(doc, new FileOutputStream(imsToolFile)); - - log.debug("Export IMS: Tool.xml in " + activity.getActivityTitle() + "[" +activity.getToolContentID()+"] transform success."); - } catch (JDOMException e) { + + log.debug("Export IMS: Tool.xml in " + activity.getActivityTitle() + "[" + activity.getToolContentID() + + "] transform success."); + } + catch (JDOMException e) { log.error("IMS export occurs error when reading tool xml for " + toolFileName + "."); } //tool node already gather into LD root folder imstools.xml file, delete old tool.xml from tool folder toolFile.delete(); continue; } - + //handle other attachment files from tools, treat them as resource of IMS package List fileChildren = new ArrayList(); //resource TAG - Element resEle = new Element(IMS_TAG_RESOURCE); + Element resEle = new Element(ExportToolContentService.IMS_TAG_RESOURCE); //the resource identifier should be "R_toolSignature_toolContentId" - Attribute resAtt = new Attribute(IMS_ATTR_IDENTIFIER,IMS_PREFIX_RESOURCE_IDENTIFIER+ activity.getToolSignature()+"-" + activity.getToolContentID().toString()); + Attribute resAtt = new Attribute(ExportToolContentService.IMS_ATTR_IDENTIFIER, + ExportToolContentService.IMS_PREFIX_RESOURCE_IDENTIFIER + activity.getToolSignature() + "-" + + activity.getToolContentID().toString()); resEle.setAttribute(resAtt); - + //file TAG - Element fileEle = new Element(IMS_TAG_FILE); - Attribute fileAtt = new Attribute(IMS_ATTR_HREF,activity.getToolContentID()+"/" + filename); + Element fileEle = new Element(ExportToolContentService.IMS_TAG_FILE); + Attribute fileAtt = new Attribute(ExportToolContentService.IMS_ATTR_HREF, activity.getToolContentID() + "/" + + filename); fileEle.setAttribute(fileAtt); - - log.debug("Export IMS: Cache resource file "+ filename + " under " + activity.getActivityTitle() + "[" +activity.getToolContentID()+"] into resources XML node"); + + log.debug("Export IMS: Cache resource file " + filename + " under " + activity.getActivityTitle() + "[" + + activity.getToolContentID() + "] into resources XML node"); //build relations of TAGS fileChildren.add(fileEle); resEle.setChildren(fileChildren); resChildren.add(resEle); - + } } } private void updateNamespaceForChildren(Element element, Namespace ns) { List children = element.getChildren(); Iterator iter = children.iterator(); - while ( iter.hasNext() ) { + while (iter.hasNext()) { Element child = (Element) iter.next(); child.setNamespace(ns); - if ( child.hasChildren() ) + if (child.hasChildren()) { updateNamespaceForChildren(child, ns); + } } } + /** * @throws ExportToolContentException * */ - public void exportToolContent(Long toolContentId, Object toolContentObj, IToolContentHandler toolContentHandler, String rootPath) - throws ExportToolContentException { + public void exportToolContent(Long toolContentId, Object toolContentObj, IToolContentHandler toolContentHandler, + String rootPath) throws ExportToolContentException { try { //create tool's save path - String toolPath = FileUtil.getFullPath(rootPath,toolContentId.toString()); + String toolPath = FileUtil.getFullPath(rootPath, toolContentId.toString()); FileUtil.createDirectory(toolPath); - + //create tool xml file name : tool.xml - String toolFileName = FileUtil.getFullPath(toolPath,TOOL_FILE_NAME); - Writer toolFile = new OutputStreamWriter(new FileOutputStream(toolFileName),"UTF-8"); - + String toolFileName = FileUtil.getFullPath(toolPath, ExportToolContentService.TOOL_FILE_NAME); + Writer toolFile = new OutputStreamWriter(new FileOutputStream(toolFileName), "UTF-8"); + //serialize tool xml into local file. XStream toolXml = new XStream(); //get back Xstream default convert, create proxy then register it to XStream parser. Converter c = toolXml.getConverterLookup().defaultConverter(); - FileInvocationHandler handler =null; - if(!fileHandleClassList.isEmpty()){ + FileInvocationHandler handler = null; + if (!fileHandleClassList.isEmpty()) { handler = new FileInvocationHandler(c); handler.setFileHandleClassList(fileHandleClassList); - Converter myc = (Converter) Proxy.newProxyInstance(c.getClass().getClassLoader(),new Class[]{Converter.class},handler); + Converter myc = (Converter) Proxy.newProxyInstance(c.getClass().getClassLoader(), + new Class[] { Converter.class }, handler); toolXml.registerConverter(myc); } //XML to Object - toolXml.toXML(toolContentObj,toolFile); + toolXml.toXML(toolContentObj, toolFile); toolFile.flush(); toolFile.close(); - + //get out the fileNodes - if(handler != null){ + if (handler != null) { List list = handler.getFileNodes(); - for(ValueInfo fileNode:list){ + for (ValueInfo fileNode : list) { log.debug("Tool attachement file is going to save : " + fileNode.fileUuid); - toolContentHandler.saveFile(fileNode.fileUuid,FileUtil.getFullPath(toolPath,fileNode.fileUuid.toString())); + toolContentHandler.saveFile(fileNode.fileUuid, FileUtil.getFullPath(toolPath, fileNode.fileUuid.toString())); } list.clear(); } - } catch (ItemNotFoundException e) { + } + catch (ItemNotFoundException e) { throw new ExportToolContentException(e); - } catch (RepositoryCheckedException e) { + } + catch (RepositoryCheckedException e) { throw new ExportToolContentException(e); - } catch (IOException e) { + } + catch (IOException e) { throw new ExportToolContentException(e); - } catch (FileUtilException e) { + } + catch (FileUtilException e) { throw new ExportToolContentException(e); - } finally{ - if(fileHandleClassList != null) + } + finally { + if (fileHandleClassList != null) { fileHandleClassList.clear(); + } } - + } - + /** * @see org.lamsfoundation.lams.authoring.service.IExportToolContentService.registerFileHandleClass(String,String,String) */ - public void registerFileClassForExport(String fileNodeClassName,String fileUuidFieldName, String fileVersionFieldName){ - fileHandleClassList.add(this.new NameInfo(fileNodeClassName,fileUuidFieldName,fileVersionFieldName)); + public void registerFileClassForExport(String fileNodeClassName, String fileUuidFieldName, String fileVersionFieldName) { + fileHandleClassList.add(this.new NameInfo(fileNodeClassName, fileUuidFieldName, fileVersionFieldName)); } - public void registerFileClassForImport(String fileNodeClassName, String fileUuidFieldName, - String fileVersionFieldName, String fileNameFieldName, String filePropertyFieldName, String mimeTypeFieldName, - String initialItemFieldName) { - fileHandleClassList.add(this.new NameInfo(fileNodeClassName, fileUuidFieldName, fileVersionFieldName, - fileNameFieldName, filePropertyFieldName, mimeTypeFieldName, initialItemFieldName)); + + public void registerFileClassForImport(String fileNodeClassName, String fileUuidFieldName, String fileVersionFieldName, + String fileNameFieldName, String filePropertyFieldName, String mimeTypeFieldName, String initialItemFieldName) { + fileHandleClassList.add(this.new NameInfo(fileNodeClassName, fileUuidFieldName, fileVersionFieldName, fileNameFieldName, + filePropertyFieldName, mimeTypeFieldName, initialItemFieldName)); } + public void registerImportVersionFilterClass(Class filterClass) { this.filterClass = filterClass; } @@ -1016,43 +1083,47 @@ * * @throws ImportToolContentException */ - public Object[] importLearningDesign(File designFile, User importer, Integer workspaceFolderUid, - List toolsErrorMsgs, String customCSV) throws ImportToolContentException { - + public Object[] importLearningDesign(File designFile, User importer, Integer workspaceFolderUid, List toolsErrorMsgs, + String customCSV) throws ImportToolContentException { + Object[] ldResults = new Object[3]; Long ldId = null; List ldErrorMsgs = new ArrayList(); String filename = designFile.getName(); - String extension = filename != null && filename.length() >= 4 ? filename.substring(filename.length()-4) : ""; - + String extension = filename != null && filename.length() >= 4 ? filename.substring(filename.length() - 4) : ""; + try { - if ( extension.equalsIgnoreCase(".las") ) { - // process 1.0.x file. - String wddxPacket = getPacket(new FileInputStream(designFile)); - if ( wddxPacket == null || ! ( wddxPacket.startsWith(" toolsErrorMsgs) throws ImportToolContentException { + public Long importLearningDesignV102(String ldWddxPacket, User importer, Integer workspaceFolderUid, + List toolsErrorMsgs) throws ImportToolContentException { WorkspaceFolder folder = getWorkspaceFolderForDesign(importer, workspaceFolderUid); - LD102Importer oldImporter = getLD102Importer(); - return oldImporter.storeLDDataWDDX(ldWddxPacket, importer, folder, toolsErrorMsgs); + LD102Importer oldImporter = getLD102Importer(); + return oldImporter.storeLDDataWDDX(ldWddxPacket, importer, folder, toolsErrorMsgs); } - /** * @return learningDesingID * @throws ExportToolContentException * @see org.lamsfoundation.lams.authoring.service.IExportToolContentService.importLearningDesign(String) */ - public Long importLearningDesignV2(String learningDesignPath, User importer, Integer workspaceFolderUid - , List toolsErrorMsgs, String customCSV) throws ImportToolContentException { - + public Long importLearningDesignV2(String learningDesignPath, User importer, Integer workspaceFolderUid, + List toolsErrorMsgs, String customCSV) throws ImportToolContentException { + try { //import learning design - String fullFilePath = FileUtil.getFullPath(learningDesignPath,LEARNING_DESIGN_FILE_NAME); + String fullFilePath = FileUtil.getFullPath(learningDesignPath, ExportToolContentService.LEARNING_DESIGN_FILE_NAME); checkImportVersion(fullFilePath, toolsErrorMsgs); LearningDesignDTO ldDto = (LearningDesignDTO) getObjectFromXML(null, fullFilePath); log.debug("Learning design xml deserialize to LearingDesignDTO success."); - + //begin tool import - Map toolMapper = new HashMap(); - Map removedActMap = new HashMap(); + Map toolMapper = new HashMap(); + Map removedActMap = new HashMap(); List activities = ldDto.getActivities(); - for(AuthoringActivityDTO activity : activities){ + for (AuthoringActivityDTO activity : activities) { //skip non-tool activities - if(activity.getActivityTypeID().intValue() != Activity.TOOL_ACTIVITY_TYPE) + if (activity.getActivityTypeID().intValue() != Activity.TOOL_ACTIVITY_TYPE) { continue; - - String toolPath = FileUtil.getFullPath(learningDesignPath,activity.getToolContentID().toString()); - + } + + String toolPath = FileUtil.getFullPath(learningDesignPath, activity.getToolContentID().toString()); + //To create a new toolContent according to imported tool signature name. //get tool by signature Tool newTool = new ToolCompatibleStrategy().getTool(activity.getToolSignature()); - + //can not find a matching tool - if(newTool == null){ - log.warn("An activity can not found matching tool [" + activity.getToolSignature()+"]."); - toolsErrorMsgs.add(getMessageService().getMessage(ERROR_TOOL_NOT_FOUND,new Object[]{activity.getToolSignature()})); - + if (newTool == null) { + log.warn("An activity can not found matching tool [" + activity.getToolSignature() + "]."); + toolsErrorMsgs.add(getMessageService().getMessage(ExportToolContentService.ERROR_TOOL_NOT_FOUND, + new Object[] { activity.getToolSignature() })); + //remove this activity from LD removedActMap.put(activity.getActivityID(), activity); continue; } //save Tool into lams_tool table. ToolContent newContent = new ToolContent(newTool); - toolContentDAO.saveToolContent(newContent); - + toolContentDAO.saveToolContent(newContent); + //put new toolContent and it is old toolContentID into - toolMapper.put(activity.getToolContentID(),newContent); - + toolMapper.put(activity.getToolContentID(), newContent); + //Invoke tool's importToolContent() method. - try{ + try { //begin to import - log.debug("Tool begin to import content : " + activity.getActivityTitle() +" by contentID :" + activity.getToolContentID()); + log.debug("Tool begin to import content : " + activity.getActivityTitle() + " by contentID :" + + activity.getToolContentID()); //tool's importToolContent() method //get from and to version String toVersion = newTool.getToolVersion(); String fromVersion = activity.getToolVersion(); - + ToolContentManager contentManager = (ToolContentManager) findToolService(newTool); - + // If this is a tool adapter tool, pass the customCSV to the special importToolContent method // Otherwise invoke the normal tool importToolContentMethod - if (contentManager instanceof ToolAdapterContentManager) - { - ToolAdapterContentManager toolAdapterContentManager = (ToolAdapterContentManager)contentManager; - toolAdapterContentManager.importToolContent(newContent.getToolContentId(),importer.getUserId(),toolPath,fromVersion,toVersion, customCSV); + if (contentManager instanceof ToolAdapterContentManager) { + ToolAdapterContentManager toolAdapterContentManager = (ToolAdapterContentManager) contentManager; + toolAdapterContentManager.importToolContent(newContent.getToolContentId(), importer.getUserId(), + toolPath, fromVersion, toVersion, customCSV); } - else - { - contentManager.importToolContent(newContent.getToolContentId(),importer.getUserId(),toolPath,fromVersion,toVersion); + else { + contentManager.importToolContent(newContent.getToolContentId(), importer.getUserId(), toolPath, + fromVersion, toVersion); } log.debug("Tool content import success."); - }catch (Exception e) { - String error = getMessageService().getMessage(ERROR_SERVICE_ERROR,new Object[]{newTool.getToolDisplayName(),e.toString()}); - log.error(error,e); + } + catch (Exception e) { + String error = getMessageService().getMessage(ExportToolContentService.ERROR_SERVICE_ERROR, + new Object[] { newTool.getToolDisplayName(), e.toString() }); + log.error(error, e); toolsErrorMsgs.add(error); //remove any unsucessed activities from new Learning design. removedActMap.put(activity.getActivityID(), activity); } } //end all activities import - + //all activities can not imported, ignore this LD - if(removedActMap.size() == activities.size() ){ - toolsErrorMsgs.add(getMessageService().getMessage(ERROR_NO_VALID_TOOL)); + if (removedActMap.size() == activities.size()) { + toolsErrorMsgs.add(getMessageService().getMessage(ExportToolContentService.ERROR_NO_VALID_TOOL)); return -1L; } - + // begin fckeditor content folder import try { - String contentZipFileName = EXPORT_LDCONTENT_ZIP_PREFIX + ldDto.getContentFolderID() + EXPORT_LDCONTENT_ZIP_SUFFIX; - String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR + String contentZipFileName = ExportToolContentService.EXPORT_LDCONTENT_ZIP_PREFIX + ldDto.getContentFolderID() + + ExportToolContentService.EXPORT_LDCONTENT_ZIP_SUFFIX; + String secureDir = Configuration.get(ConfigurationKeys.LAMS_EAR_DIR) + File.separator + FileUtil.LAMS_WWW_DIR + File.separator + FileUtil.LAMS_WWW_SECURE_DIR + File.separator + ldDto.getContentFolderID(); File contentZipFile = new File(FileUtil.getFullPath(learningDesignPath, contentZipFileName)); - + // unzip file to target secure dir if exists - if(contentZipFile.exists()) { + if (contentZipFile.exists()) { InputStream is = new FileInputStream(contentZipFile); ZipFileUtil.expandZipToFolder(is, secureDir); } - - } catch (Exception e) { + + } + catch (Exception e) { throw new ImportToolContentException(e); } - + // if the design was read only (e.g. exported a runtime sequence), clear the read only flag ldDto.setDateReadOnly(null); ldDto.setReadOnly(false); - + //save learning design WorkspaceFolder folder = getWorkspaceFolderForDesign(importer, workspaceFolderUid); - return saveLearningDesign(ldDto,importer,folder,toolMapper,removedActMap); - - }catch (Exception e) { - log.error("Exception occured during import.",e); + return saveLearningDesign(ldDto, importer, folder, toolMapper, removedActMap); + + } + catch (Exception e) { + log.error("Exception occured during import.", e); throw new ImportToolContentException(e); - } - + } + } + /** * Call xstream to get the POJOs from the XML file. To make it backwardly compatible we catch any exceptions * due to added fields, remove the field using the ToolContentVersionFilter functionality and try to reparse. We can't @@ -1239,57 +1314,63 @@ String lastFieldRemoved = ""; ToolContentVersionFilter contentFilter = null; // cap the maximum number of retries to 30 - if we add more than 30 new fields then we need to rethink our strategy - int maxRetries = 30; + int maxRetries = 30; int numTries = 0; - + while (true) { try { - - if ( numTries > maxRetries) + + if (numTries > maxRetries) { break; + } numTries++; - - file = new InputStreamReader(new FileInputStream(fullFilePath),"UTF-8"); + + file = new InputStreamReader(new FileInputStream(fullFilePath), "UTF-8"); return conversionXml.fromXML(file); - } catch ( ConversionException ce) { - log.debug("Failed import",ce); + } + catch (ConversionException ce) { + log.debug("Failed import", ce); finalException = ce; file.close(); - if ( ce.getMessage() == null ) { + if (ce.getMessage() == null) { // can't retry, so get out of here! break; - } else { + } + else { // try removing the field from our XML and retry String message = ce.getMessage(); String classname = extractValue(message, "required-type"); String fieldname = extractValue(message, "message"); - if ( fieldname == null || fieldname.equals("") || lastFieldRemoved.equals(classname+"."+fieldname) ) { + if (fieldname == null || fieldname.equals("") || lastFieldRemoved.equals(classname + "." + fieldname)) { // can't retry, so get out of here! break; - } else { - if ( contentFilter == null ) { + } + else { + if (contentFilter == null) { contentFilter = new ToolContentVersionFilter(); } - + Class problemClass = getClass(classname); - if ( problemClass == null ) { + if (problemClass == null) { // can't retry, so get out of here! break; } contentFilter.removeField(problemClass, fieldname); contentFilter.transformXML(fullFilePath); - lastFieldRemoved = classname+"."+fieldname; - log.debug("Retrying import after removing field "+fieldname); + lastFieldRemoved = classname + "." + fieldname; + log.debug("Retrying import after removing field " + fieldname); continue; } - } - } finally { - if ( file != null ) + } + } + finally { + if (file != null) { file.close(); + } } } throw finalException; @@ -1298,199 +1379,225 @@ private void checkImportVersion(String fullFilePath, List toolsErrorMsgs) throws FileNotFoundException, JDOMException { SAXBuilder sax = new SAXBuilder(); - Document doc = sax.build(new FileInputStream(fullFilePath),"UTF-8"); + Document doc = sax.build(new FileInputStream(fullFilePath), "UTF-8"); Element root = doc.getRootElement(); - String title = root.getChildTextTrim(LAMS_TITLE); - String versionString = root.getChildTextTrim(LAMS_VERSION); - + String title = root.getChildTextTrim(ExportToolContentService.LAMS_TITLE); + String versionString = root.getChildTextTrim(ExportToolContentService.LAMS_VERSION); + String currentVersionString = Configuration.get(ConfigurationKeys.SERVER_VERSION_NUMBER); - try { - boolean isLaterVersion = VersionUtil.isSameOrLaterVersionAsServer(versionString,true); - if ( ! isLaterVersion ) { - log.warn("Importing a design from a later version of LAMS. There may be parts of the design that will fail to import. Design name \'"+title+"\'. Version in import file "+versionString); - toolsErrorMsgs.add(getMessageService().getMessage(ERROR_INCOMPATIBLE_VERSION,new Object[]{versionString,currentVersionString})); + try { + boolean isLaterVersion = VersionUtil.isSameOrLaterVersionAsServer(versionString, true); + if (!isLaterVersion) { + log + .warn("Importing a design from a later version of LAMS. There may be parts of the design that will fail to import. Design name \'" + + title + "\'. Version in import file " + versionString); + toolsErrorMsgs.add(getMessageService().getMessage(ExportToolContentService.ERROR_INCOMPATIBLE_VERSION, + new Object[] { versionString, currentVersionString })); } - } catch ( Exception e) { - log.warn("Unable to properly determine current version from an import file. Design name \'"+title+"\'. Version in import file "+versionString); - toolsErrorMsgs.add(getMessageService().getMessage(ERROR_INCOMPATIBLE_VERSION,new Object[]{versionString,currentVersionString})); } + catch (Exception e) { + log.warn("Unable to properly determine current version from an import file. Design name \'" + title + + "\'. Version in import file " + versionString); + toolsErrorMsgs.add(getMessageService().getMessage(ExportToolContentService.ERROR_INCOMPATIBLE_VERSION, + new Object[] { versionString, currentVersionString })); + } } private Class getClass(String classname) { try { return Class.forName(classname); - } catch (ClassNotFoundException e) { - log.error("Trying to remove unwanted fields from import but we can't find the matching class "+classname+". Aborting retry.", e); + } + catch (ClassNotFoundException e) { + log.error("Trying to remove unwanted fields from import but we can't find the matching class " + classname + + ". Aborting retry.", e); return null; } } + /** * Extract the class name or field name from a ConversionException message */ private String extractValue(String message, String fieldToLookFor) { try { int startIndex = message.indexOf(fieldToLookFor); - if ( startIndex > -1) { - startIndex = message.indexOf(":", startIndex+1); - if ( startIndex > -1 && startIndex+2 < message.length() ) { - startIndex = startIndex+2; + if (startIndex > -1) { + startIndex = message.indexOf(":", startIndex + 1); + if (startIndex > -1 && startIndex + 2 < message.length()) { + startIndex = startIndex + 2; int endIndex = message.indexOf(" ", startIndex); String value = message.substring(startIndex, endIndex); return value.trim(); } } - } catch ( ArrayIndexOutOfBoundsException e ) { } + catch (ArrayIndexOutOfBoundsException e) { + } return ""; } - - private WorkspaceFolder getWorkspaceFolderForDesign(User importer, Integer workspaceFolderUid) throws ImportToolContentException { + + private WorkspaceFolder getWorkspaceFolderForDesign(User importer, Integer workspaceFolderUid) + throws ImportToolContentException { // if workspaceFolderUid == null use the user's default folder WorkspaceFolder folder = null; - if ( workspaceFolderUid != null ) { - folder = (WorkspaceFolder)baseDAO.find(WorkspaceFolder.class,workspaceFolderUid); - } - if ( folder == null && importer.getWorkspace() != null) { + if (workspaceFolderUid != null) { + folder = (WorkspaceFolder) baseDAO.find(WorkspaceFolder.class, workspaceFolderUid); + } + if (folder == null && importer.getWorkspace() != null) { folder = importer.getWorkspace().getDefaultFolder(); } - if ( folder == null ) { - String error = "Unable to save design in a folder - folder not found. Input folder uid="+workspaceFolderUid+ - " user's default folder "+importer.getWorkspace(); + if (folder == null) { + String error = "Unable to save design in a folder - folder not found. Input folder uid=" + workspaceFolderUid + + " user's default folder " + importer.getWorkspace(); log.error(error); throw new ImportToolContentException(error); } return folder; } - + private void badFileType(List ldErrorMsgs, String filename, String errDescription) { - log.error("Uploaded file not an expected type. Filename was "+filename+" "+errDescription); - MessageService msgService = getMessageService(); - String msg = msgService.getMessage(KEY_MSG_IMPORT_FILE_FORMAT); + log.error("Uploaded file not an expected type. Filename was " + filename + " " + errDescription); + MessageService msgService = getMessageService(); + String msg = msgService.getMessage(ExportToolContentService.KEY_MSG_IMPORT_FILE_FORMAT); ldErrorMsgs.add(msg != null ? msg : "Uploaded file not an expected type."); } - /** * Import tool content */ - public Object importToolContent(String toolContentPath, IToolContentHandler toolContentHandler,String fromVersion,String toVersion) throws ImportToolContentException{ + public Object importToolContent(String toolContentPath, IToolContentHandler toolContentHandler, String fromVersion, + String toVersion) throws ImportToolContentException { Object toolPOJO = null; -// change xml to Tool POJO + // change xml to Tool POJO XStream toolXml = new XStream(); - + Converter c = toolXml.getConverterLookup().defaultConverter(); FileInvocationHandler handler = null; - if(!fileHandleClassList.isEmpty()){ + if (!fileHandleClassList.isEmpty()) { //create proxy class handler = new FileInvocationHandler(c); handler.setFileHandleClassList(fileHandleClassList); - Converter myc = (Converter) Proxy.newProxyInstance(c.getClass().getClassLoader(),new Class[]{Converter.class},handler); + Converter myc = (Converter) Proxy.newProxyInstance(c.getClass().getClassLoader(), new Class[] { Converter.class }, + handler); //registry to new proxy convert to XStream - toolXml.registerConverter(myc); + toolXml.registerConverter(myc); } - + List valueList = null; try { - + //tool.xml full path - String toolFilePath = FileUtil.getFullPath(toolContentPath,TOOL_FILE_NAME); - if(filterClass != null && !StringUtils.equals(fromVersion,toVersion)){ - filterVersion(toolFilePath,fromVersion,toVersion); + String toolFilePath = FileUtil.getFullPath(toolContentPath, ExportToolContentService.TOOL_FILE_NAME); + if (filterClass != null && !StringUtils.equals(fromVersion, toVersion)) { + filterVersion(toolFilePath, fromVersion, toVersion); } //clear and ensure next activity can get correct filter thru registerImportVersionFilterClass(). filterClass = null; - + //read tool file after transform. toolPOJO = getObjectFromXML(toolXml, toolFilePath); - + //upload file node if has - if(handler != null){ + if (handler != null) { valueList = handler.getFileNodes(); - for(ValueInfo fileNode:valueList){ - - Long uuid = NumberUtils.createLong(BeanUtils.getProperty(fileNode.instance,fileNode.name.uuidFieldName)); + for (ValueInfo fileNode : valueList) { + + Long uuid = NumberUtils.createLong(BeanUtils.getProperty(fileNode.instance, fileNode.name.uuidFieldName)); //For instance, item class in share resource tool may be url or single file. If it is URL, then the //file uuid will be null. Ignore it! - if(uuid == null) + if (uuid == null) { continue; - + } + Long version = null; //optional - try{ - version = NumberUtils.createLong(BeanUtils.getProperty(fileNode.instance,fileNode.name.versionFieldName)); - } catch (Exception e ) { + try { + version = NumberUtils + .createLong(BeanUtils.getProperty(fileNode.instance, fileNode.name.versionFieldName)); + } + catch (Exception e) { log.debug("No method for version:" + fileNode.instance); } - + //according to upload rule: the file name will be uuid. String realFileName = uuid.toString(); - String fullFileName = FileUtil.getFullPath(toolContentPath,realFileName); + String fullFileName = FileUtil.getFullPath(toolContentPath, realFileName); log.debug("Tool attachement files/packages are going to upload to repository " + fullFileName); - + //to check if the file is package (with extension name ".zip") or single file (no extension name). - File file = new File(fullFileName); + File file = new File(fullFileName); boolean isPackage = false; - if(!file.exists()){ - file = new File(fullFileName+EXPORT_TOOLCONTNET_ZIP_SUFFIX); - realFileName = realFileName + EXPORT_TOOLCONTNET_ZIP_SUFFIX; + if (!file.exists()) { + file = new File(fullFileName + ExportToolContentService.EXPORT_TOOLCONTNET_ZIP_SUFFIX); + realFileName = realFileName + ExportToolContentService.EXPORT_TOOLCONTNET_ZIP_SUFFIX; isPackage = true; //if this file is norpackage neither single file, throw exception. - if(!file.exists()) - throw new ImportToolContentException("Content attached file/package can not be found: " + fullFileName + "(.zip)"); + if (!file.exists()) { + throw new ImportToolContentException("Content attached file/package can not be found: " + + fullFileName + "(.zip)"); + } } - + //more fields values for Repository upload use - String fileName = BeanUtils.getProperty(fileNode.instance,fileNode.name.fileNameFieldName); - String fileProperty = BeanUtils.getProperty(fileNode.instance,fileNode.name.filePropertyFieldName); + String fileName = BeanUtils.getProperty(fileNode.instance, fileNode.name.fileNameFieldName); + String fileProperty = BeanUtils.getProperty(fileNode.instance, fileNode.name.filePropertyFieldName); //optional fields String mimeType = null; try { - mimeType = BeanUtils.getProperty(fileNode.instance,fileNode.name.mimeTypeFieldName); - } catch (Exception e ) { + mimeType = BeanUtils.getProperty(fileNode.instance, fileNode.name.mimeTypeFieldName); + } + catch (Exception e) { log.debug("No method for mimeType:" + fileNode.instance); } String initalItem = null; try { - initalItem = BeanUtils.getProperty(fileNode.instance,fileNode.name.initalItemFieldName); - } catch (Exception e ) { + initalItem = BeanUtils.getProperty(fileNode.instance, fileNode.name.initalItemFieldName); + } + catch (Exception e) { log.debug("No method for initial item:" + fileNode.instance); } - + InputStream is = new FileInputStream(file); //upload to repository: file or pacakge NodeKey key; - if(!isPackage) - key = toolContentHandler.uploadFile(is,fileName,mimeType,fileProperty); - else{ + if (!isPackage) { + key = toolContentHandler.uploadFile(is, fileName, mimeType, fileProperty); + } + else { String packageDirectory = ZipFileUtil.expandZip(is, realFileName); - key = toolContentHandler.uploadPackage(packageDirectory,initalItem); + key = toolContentHandler.uploadPackage(packageDirectory, initalItem); } - + //refresh file node Uuid and Version value to latest. - BeanUtils.setProperty(fileNode.instance,fileNode.name.uuidFieldName,key.getUuid()); + BeanUtils.setProperty(fileNode.instance, fileNode.name.uuidFieldName, key.getUuid()); //version id is optional - if(fileNode.name.versionFieldName != null) - BeanUtils.setProperty(fileNode.instance,fileNode.name.versionFieldName,key.getVersion()); + if (fileNode.name.versionFieldName != null) { + BeanUtils.setProperty(fileNode.instance, fileNode.name.versionFieldName, key.getVersion()); + } } } - } catch (Exception e) { + } + catch (Exception e) { throw new ImportToolContentException(e); - }finally{ - if(fileHandleClassList != null) + } + finally { + if (fileHandleClassList != null) { fileHandleClassList.clear(); - if( valueList != null) + } + if (valueList != null) { valueList.clear(); + } } - + return toolPOJO; } - + //****************************************************************** // ApplicationContextAware method implementation //****************************************************************** public void setApplicationContext(ApplicationContext context) throws BeansException { - this.applicationContext = context; + applicationContext = context; } + //****************************************************************** // Private methods //****************************************************************** @@ -1500,31 +1607,31 @@ private Document transform(InputStream sourceDoc, File stylesheetFile, Map params) throws Exception { // Set up the XSLT stylesheet TransformerFactory transformerFactory = TransformerFactory.newInstance(); - + log.debug("Export IMS: using XSLT file " + stylesheetFile.getAbsolutePath() + " to transforming..."); Templates stylesheet = transformerFactory.newTemplates(new StreamSource(stylesheetFile.getAbsolutePath())); Transformer processor = stylesheet.newTransformer(); - + //put initial params Set> entrys = params.entrySet(); for (Map.Entry entry : entrys) { processor.setParameter(entry.getKey(), entry.getValue()); } - + //result writer StringWriter writer = new StringWriter(); - + // Feed the resultant I/O stream into the XSLT processor StreamSource source = new StreamSource(sourceDoc); StreamResult result = new StreamResult(writer); - + //transform processor.transform(source, result); - + // Convert the resultant transformed document back to JDOM SAXBuilder builder = new SAXBuilder(); Document resultDoc = builder.build(new StringReader(writer.toString())); - + return resultDoc; } @@ -1539,233 +1646,254 @@ float from = 0; try { from = NumberUtils.createFloat(fromVersion); - } catch (Exception e) {} + } + catch (Exception e) { + } float to = 0; try { to = NumberUtils.createFloat(toVersion); - } catch (Exception e) {} - + } + catch (Exception e) { + } + String filterMethodPrefix; - if(from > to) - filterMethodPrefix = FILTER_METHOD_PREFIX_DOWN; - else - filterMethodPrefix = FILTER_METHOD_PREFIX_UP; - + if (from > to) { + filterMethodPrefix = ExportToolContentService.FILTER_METHOD_PREFIX_DOWN; + } + else { + filterMethodPrefix = ExportToolContentService.FILTER_METHOD_PREFIX_UP; + } + log.debug("Version filter class will filter from version " + from + " to " + to); - + Object filter = filterClass.newInstance(); Method[] methods = filterClass.getDeclaredMethods(); Map methodNeeds = new TreeMap(); for (Method method : methods) { String name = method.getName(); - if(name.startsWith(filterMethodPrefix)){ - String[] ver = name.split(filterMethodPrefix+"|"+FILTER_METHOD_MIDDLE); + if (name.startsWith(filterMethodPrefix)) { + String[] ver = name.split(filterMethodPrefix + "|" + ExportToolContentService.FILTER_METHOD_MIDDLE); Float mf = 0f; Float mt = 0f; - for (int idx=0;idx idx) - mt = NumberUtils.createFloat(ver[++idx]); + if (ver.length > idx) { + mt = NumberUtils.createFloat(ver[++idx]); + } break; } - if(mf >= from && mt <= to){ - methodNeeds.put(mf,method); + if (mf >= from && mt <= to) { + methodNeeds.put(mf, method); } } } Collection calls = methodNeeds.values(); for (Method method : calls) { - method.invoke(filter, new Object[]{}); - log.debug("Version filter class method " + method.getName() +" is executed."); + method.invoke(filter, new Object[] {}); + log.debug("Version filter class method " + method.getName() + " is executed."); } - Method transform = filterClass.getMethod("transformXML",new Class[]{String.class}); - transform.invoke(filter, new Object[]{toolFilePath}); - - + Method transform = filterClass.getMethod("transformXML", new Class[] { String.class }); + transform.invoke(filter, new Object[] { toolFilePath }); + } + /** * If there are any errors happen during tool exporting content. Writing failed message to file. */ - private void writeErrorToToolFile(String rootPath,Long toolContentId, String msg) { + private void writeErrorToToolFile(String rootPath, Long toolContentId, String msg) { //create tool's save path try { - String toolPath = FileUtil.getFullPath(rootPath,toolContentId.toString()); + String toolPath = FileUtil.getFullPath(rootPath, toolContentId.toString()); FileUtil.createDirectory(toolPath); - + //create tool xml file name : tool.xml - String toolFileName = FileUtil.getFullPath(toolPath,TOOL_FAILED_FILE_NAME); + String toolFileName = FileUtil.getFullPath(toolPath, ExportToolContentService.TOOL_FAILED_FILE_NAME); Writer toolFile = new FileWriter(new File(toolFileName)); toolFile.write(msg); toolFile.flush(); toolFile.close(); - } catch (FileUtilException e) { - log.warn("Export error file write error:",e); - } catch (IOException e) { - log.warn("Export error file write error:",e); } - } - private ILearningDesignService getLearningDesignService(){ - return (ILearningDesignService) applicationContext.getBean(LEARNING_DESIGN_SERVICE_BEAN_NAME); + catch (FileUtilException e) { + log.warn("Export error file write error:", e); + } + catch (IOException e) { + log.warn("Export error file write error:", e); + } } - private MessageService getMessageService(){ - if(messageService != null) - return messageService; - - return (messageService = (MessageService) applicationContext.getBean(MESSAGE_SERVICE_BEAN_NAME)); + + private ILearningDesignService getLearningDesignService() { + return (ILearningDesignService) applicationContext.getBean(ExportToolContentService.LEARNING_DESIGN_SERVICE_BEAN_NAME); } - private LD102Importer getLD102Importer(){ - return (LD102Importer) applicationContext.getBean(LD102IMPORTER_BEAN_NAME); + + private MessageService getMessageService() { + if (ExportToolContentService.messageService != null) { + return ExportToolContentService.messageService; + } + + return ExportToolContentService.messageService = (MessageService) applicationContext + .getBean(ExportToolContentService.MESSAGE_SERVICE_BEAN_NAME); } - - - private Object findToolService(Tool tool) throws NoSuchBeanDefinitionException - { - return applicationContext.getBean(tool.getServiceName()); - } - - public Long saveLearningDesign(LearningDesignDTO dto, User importer, WorkspaceFolder folder, - Map toolMapper, Map removedActMap) - throws ImportToolContentException { + private LD102Importer getLD102Importer() { + return (LD102Importer) applicationContext.getBean(ExportToolContentService.LD102IMPORTER_BEAN_NAME); + } + + private Object findToolService(Tool tool) throws NoSuchBeanDefinitionException { + return applicationContext.getBean(tool.getServiceName()); + } + + public Long saveLearningDesign(LearningDesignDTO dto, User importer, WorkspaceFolder folder, + Map toolMapper, Map removedActMap) throws ImportToolContentException { + //grouping object list List groupingDtoList = dto.getGroupings(); - Map groupingMapper = new HashMap(); - Map groupByUIIDMapper = new HashMap(); - for(GroupingDTO groupingDto : groupingDtoList){ + Map groupingMapper = new HashMap(); + Map groupByUIIDMapper = new HashMap(); + for (GroupingDTO groupingDto : groupingDtoList) { Grouping grouping = getGrouping(groupingDto, groupByUIIDMapper); - groupingMapper.put(grouping.getGroupingId(),grouping); - + groupingMapper.put(grouping.getGroupingId(), grouping); + //persist grouping.setGroupingId(null); groupingDAO.insert(grouping); } - + //================== Start handle activities ====================== //activity object list //sort them to ensure parent before its children. List actDtoList = getSortedParentList(dto.getActivities()); - - if(log.isDebugEnabled()){ - int idx=0; + + if (log.isDebugEnabled()) { + int idx = 0; for (AuthoringActivityDTO activityDTO : actDtoList) { - log.debug(idx + ": ActivityID is [" + activityDTO.getActivityID() + "], parent ID is [" + activityDTO.getParentActivityID() + "]"); + log.debug(idx + ": ActivityID is [" + activityDTO.getActivityID() + "], parent ID is [" + + activityDTO.getParentActivityID() + "]"); idx++; } } - Set actList = new TreeSet (new ActivityOrderComparator()); - Map activityMapper = new HashMap(); - Map activityByUIIDMapper = new HashMap(); + Set actList = new TreeSet(new ActivityOrderComparator()); + Map activityMapper = new HashMap(); + Map activityByUIIDMapper = new HashMap(); // as we create the activities, we need to record any "default activities" for the sequence activity // and branching activities to process later - we can't process them now as the children won't have // been created yet and if we leave it till later and then find all the activities we are // going through the activity set over and over again for no reason. - Map defaultActivityToParentActivityMapping = new HashMap(); - - for(AuthoringActivityDTO actDto: actDtoList){ - Activity act = getActivity(actDto,groupingMapper,toolMapper,defaultActivityToParentActivityMapping); + Map defaultActivityToParentActivityMapping = new HashMap(); + + for (AuthoringActivityDTO actDto : actDtoList) { + Activity act = getActivity(actDto, groupingMapper, toolMapper, defaultActivityToParentActivityMapping); //so far, the activitiy ID is still old one, so setup the mapping relation between old ID and new activity. - activityMapper.put(act.getActivityId(),act); - activityByUIIDMapper.put(act.getActivityUIID(),act); + activityMapper.put(act.getActivityId(), act); + activityByUIIDMapper.put(act.getActivityUIID(), act); //if this act is removed, then does not save it into LD - if(!removedActMap.containsKey(actDto.getActivityID())) + if (!removedActMap.containsKey(actDto.getActivityID())) { actList.add(act); + } } // rescan the activity list and refresh their parent activity and input activities - for(AuthoringActivityDTO actDto: actDtoList){ + for (AuthoringActivityDTO actDto : actDtoList) { Activity act = activityMapper.get(actDto.getActivityID()); - if(removedActMap.containsKey(actDto.getActivityID())) + if (removedActMap.containsKey(actDto.getActivityID())) { continue; - - if(actDto.getParentActivityID() != null){ + } + + if (actDto.getParentActivityID() != null) { Activity parent = activityMapper.get(actDto.getParentActivityID()); //reset children's parent as null if parent already removed - if(removedActMap.containsKey(parent.getActivityId())){ + if (removedActMap.containsKey(parent.getActivityId())) { act.setParentActivity(null); act.setParentUIID(null); - }else{ + } + else { act.setParentActivity(parent); //also add child as Complex activity: It is useless for persist data, but helpful for validate in learning design! - if(parent.isComplexActivity()){ - Set set = ((ComplexActivity)parent).getActivities(); - if(set == null){ + if (parent.isComplexActivity()) { + Set set = ((ComplexActivity) parent).getActivities(); + if (set == null) { set = new TreeSet(new ActivityOrderComparator()); - ((ComplexActivity)parent).setActivities(set); + ((ComplexActivity) parent).setActivities(set); } - if(!removedActMap.containsKey(actDto.getActivityID())) + if (!removedActMap.containsKey(actDto.getActivityID())) { set.add(act); + } } } } - + if (actDto.getInputActivities() != null) { act.setInputActivities(new HashSet()); - for ( Integer inputActivityUIID : actDto.getInputActivities() ) { + for (Integer inputActivityUIID : actDto.getInputActivities()) { Activity inputAct = activityByUIIDMapper.get(inputActivityUIID); - if ( inputAct == null ) { - log.error("Unable to find input activity with UIID "+inputActivityUIID+" for activity "+act); - } else { + if (inputAct == null) { + log.error("Unable to find input activity with UIID " + inputActivityUIID + " for activity " + act); + } + else { act.getInputActivities().add(inputAct); } - } + } } - + //persist act.setActivityId(null); activityDAO.insert(act); } - + // Process the "first child" for any sequence activities and the "default branch" for branching activities. // If the child has been removed then leave it as null as the progress engine will cope (it will pick a // new one based on the lack of an input transition) and in authoring the author will just have to set // up a new first activity. If the default branch is missing and other details are missing (e.g. missing conditions) // from the design then it may have to be fixed in authoring before it will run, so the default branch missing // case needs to be picked up by the validation (done later). - if ( defaultActivityToParentActivityMapping.size() > 0 ) { - for ( Integer childUIID : defaultActivityToParentActivityMapping.keySet() ) { + if (defaultActivityToParentActivityMapping.size() > 0) { + for (Integer childUIID : defaultActivityToParentActivityMapping.keySet()) { ComplexActivity complex = defaultActivityToParentActivityMapping.get(childUIID); Activity childActivity = activityByUIIDMapper.get(childUIID); - if ( childActivity == null ) { - log.error("Unable to find the default child activity ("+childUIID - +") for the activity ("+complex.getTitle() - +"). The activity "+complex.getTitle()+" will need to be fixed in authoring " - +"otherwise the progress engine will just do the best it can."); - } else { + if (childActivity == null) { + log.error("Unable to find the default child activity (" + childUIID + ") for the activity (" + + complex.getTitle() + "). The activity " + complex.getTitle() + + " will need to be fixed in authoring " + + "otherwise the progress engine will just do the best it can."); + } + else { complex.setDefaultActivity(childActivity); } } } - -// reset first activity UUID for LD if old first removed + + // reset first activity UUID for LD if old first removed //set first as remove activity's next existed one Integer actUiid = dto.getFirstActivityUIID(); - if(actUiid != null){ - for(AuthoringActivityDTO actDto: actDtoList){ - if(actUiid.equals(actDto.getActivityUIID())){ + if (actUiid != null) { + for (AuthoringActivityDTO actDto : actDtoList) { + if (actUiid.equals(actDto.getActivityUIID())) { //if first activity is removed - if(removedActMap.containsKey(actDto.getActivityID())){ + if (removedActMap.containsKey(actDto.getActivityID())) { List transDtoList = dto.getTransitions(); Long existFirstAct = null; Long nextActId = actDto.getActivityID(); boolean found = false; // try to find next available activity //1000 is failure tolerance: to avoid dead loop. - for(int idx=0;idx<1000;idx++){ - if(transDtoList == null || transDtoList.isEmpty()) + for (int idx = 0; idx < 1000; idx++) { + if (transDtoList == null || transDtoList.isEmpty()) { break; + } boolean transitionBreak = true; - for(TransitionDTO transDto: transDtoList){ + for (TransitionDTO transDto : transDtoList) { //find out the transition of current first activity - if(nextActId.equals(transDto.getFromActivityID())){ + if (nextActId.equals(transDto.getFromActivityID())) { transitionBreak = false; nextActId = transDto.getToActivityID(); - if(nextActId != null && !removedActMap.containsKey(nextActId)){ + if (nextActId != null && !removedActMap.containsKey(nextActId)) { existFirstAct = nextActId; found = true; break; - }else if(nextActId == null){ + } + else if (nextActId == null) { //no more activity found = true; break; @@ -1779,108 +1907,114 @@ // This activity also removed!!! then retrieve again // If found is false, then the nextAct is still not available, then continue find. // tranisitionBreak mean the activity is removed but it can not find its transition to decide next available activity. - if(found || transitionBreak) + if (found || transitionBreak) { break; + } } Activity next = activityMapper.get(existFirstAct); - dto.setFirstActivityUIID(next == null?null:next.getActivityUIID()); + dto.setFirstActivityUIID(next == null ? null : next.getActivityUIID()); } //find out the first activity, then break; break; } } } //================== END handle activities ====================== - + //transition object list List transDtoList = dto.getTransitions(); Set transList = new HashSet(); - for(TransitionDTO transDto: transDtoList){ + for (TransitionDTO transDto : transDtoList) { //Any transitions relating with this tool will be removed! Long fromId = transDto.getFromActivityID(); Long toId = transDto.getToActivityID(); - if(fromId != null && removedActMap.containsKey(fromId)){ + if (fromId != null && removedActMap.containsKey(fromId)) { continue; } - if(toId != null && removedActMap.containsKey(toId)){ + if (toId != null && removedActMap.containsKey(toId)) { continue; } - Transition trans = getTransition(transDto,activityMapper); + Transition trans = getTransition(transDto, activityMapper); transList.add(trans); - + //persist trans.setTransitionId(null); //leave it to learning design to save it. -// transitionDAO.insert(trans); + // transitionDAO.insert(trans); } - + // branch mappings - maps groups to branches, map conditions to branches List entryDtoList = dto.getBranchMappings(); - if ( entryDtoList != null ) { + if (entryDtoList != null) { Set entryList = new HashSet(); for (BranchActivityEntryDTO entryDto : entryDtoList) { BranchActivityEntry entry = getBranchActivityEntry(entryDto, groupByUIIDMapper, activityByUIIDMapper); entryList.add(entry); } } - - LearningDesign ld = getLearningDesign(dto,importer,folder,actList,transList,activityMapper); - -// validate learning design - Vector listOfValidationErrorDTOs = (Vector)getLearningDesignService().validateLearningDesign(ld); - if(listOfValidationErrorDTOs.size() > 0 ){ + + LearningDesign ld = getLearningDesign(dto, importer, folder, actList, transList, activityMapper); + + // validate learning design + Vector listOfValidationErrorDTOs = getLearningDesignService().validateLearningDesign(ld); + if (listOfValidationErrorDTOs.size() > 0) { ld.setValidDesign(false); log.error(listOfValidationErrorDTOs); -// throw new ImportToolContentException("Learning design validate error."); - }else + // throw new ImportToolContentException("Learning design validate error."); + } + else { ld.setValidDesign(true); - + } + ld.setTitle(ImportExportUtil.generateUniqueLDTitle(folder, ld.getTitle(), learningDesignDAO)); - -// persist + + // persist learningDesignDAO.insert(ld); - + return ld.getLearningDesignId(); } - - - /** - * Method to sort activity DTO according to the rule: Paretns is before their children. - * @param activities - * @return - */ + + /** + * Method to sort activity DTO according to the rule: Paretns is before their children. + * @param activities + * @return + */ private List getSortedParentList(List activities) { List result = new ArrayList(); List actIdList = new ArrayList(); - + //NOTICE: this code can not handle all nodes have their parents, ie, there is at least one node parent is null(root). int failureToleranceCount = 5000; - while(!activities.isEmpty() && failureToleranceCount > 0){ + while (!activities.isEmpty() && failureToleranceCount > 0) { Iterator iter = activities.iterator(); while (iter.hasNext()) { AuthoringActivityDTO actDto = iter.next(); - if(actDto.getParentActivityID() == null){ + if (actDto.getParentActivityID() == null) { result.add(actDto); actIdList.add(actDto.getActivityID()); iter.remove(); - }else if(actIdList.contains(actDto.getParentActivityID())){ + } + else if (actIdList.contains(actDto.getParentActivityID())) { result.add(actDto); actIdList.add(actDto.getActivityID()); iter.remove(); } } failureToleranceCount--; } - if(!activities.isEmpty()){ + if (!activities.isEmpty()) { log.warn("Some activities cannot found their parent actitivy."); //just append these activies into result list for (AuthoringActivityDTO actDto : activities) { - log.warn("Activity ID[" + actDto.getActivityID() + "] cannot found parent [" + actDto.getParentActivityID() + "]"); + log + .warn("Activity ID[" + actDto.getActivityID() + "] cannot found parent [" + actDto.getParentActivityID() + + "]"); } result.addAll(activities); } return result; } + /** * Get learning design object from this Learning design DTO object. It also following our * import rules: @@ -1894,109 +2028,125 @@ * @return * @throws ImportToolContentException */ - private LearningDesign getLearningDesign(LearningDesignDTO dto, User importer, WorkspaceFolder folder, - Set actList, Set transList, Map activityMapper) throws ImportToolContentException { + private LearningDesign getLearningDesign(LearningDesignDTO dto, User importer, WorkspaceFolder folder, Set actList, + Set transList, Map activityMapper) throws ImportToolContentException { LearningDesign ld = new LearningDesign(); - - if(dto == null) + + if (dto == null) { return ld; - + } + ld.setLearningDesignId(dto.getLearningDesignID()); ld.setLearningDesignUIID(dto.getLearningDesignUIID()); ld.setDescription(dto.getDescription()); ld.setTitle(dto.getTitle()); - + Integer actUiid = dto.getFirstActivityUIID(); - if(actUiid != null){ - for(Activity act : activityMapper.values()){ - if(actUiid.equals(act.getActivityUIID())){ + if (actUiid != null) { + for (Activity act : activityMapper.values()) { + if (actUiid.equals(act.getActivityUIID())) { ld.setFirstActivity(act); break; } } } - + ld.setMaxID(dto.getMaxID()); ld.setValidDesign(dto.getValidDesign()); ld.setReadOnly(dto.getReadOnly()); ld.setDateReadOnly(dto.getDateReadOnly()); - ld.setOfflineInstructions(dto.getOfflineInstructions()); + ld.setOfflineInstructions(dto.getOfflineInstructions()); ld.setOnlineInstructions(dto.getOnlineInstructions()); - + ld.setHelpText(dto.getHelpText()); //set to 1 ld.setCopyTypeID(1); ld.setCreateDateTime(dto.getCreateDateTime()); ld.setVersion(dto.getVersion()); - - if(folder != null) + + if (folder != null) { ld.setWorkspaceFolder(folder); - + } + ld.setDuration(dto.getDuration()); ld.setLicenseText(dto.getLicenseText()); - + Long licenseId = dto.getLicenseID(); - if(licenseId != null){ + if (licenseId != null) { License license = licenseDAO.getLicenseByID(licenseId); - if(license == null) - throw new ImportToolContentException("Import failed: License ["+dto.getLicenseText()+ "] does not exist in target database"); + if (license == null) { + throw new ImportToolContentException("Import failed: License [" + dto.getLicenseText() + + "] does not exist in target database"); + } ld.setLicense(licenseDAO.getLicenseByID(licenseId)); ld.setLicenseText(dto.getLicenseText()); } - + ld.setLastModifiedDateTime(dto.getLastModifiedDateTime()); ld.setContentFolderID(dto.getContentFolderID()); - + //set learning design to transition. - for(Transition trans:transList){ + for (Transition trans : transList) { trans.setLearningDesign(ld); } ld.setTransitions(transList); - for(Activity act :actList) + for (Activity act : actList) { act.setLearningDesign(ld); + } ld.setActivities(actList); - + ld.setCreateDateTime(new Date()); ld.setLastModifiedDateTime(new Date()); ld.setUser(importer); return ld; } + /** * Return Grouping object from given GroupingDTO. * * @param groupingDto * @return */ - private Grouping getGrouping(GroupingDTO groupingDto, Map groupByUIIDMapper) { + private Grouping getGrouping(GroupingDTO groupingDto, Map groupByUIIDMapper) { Grouping grouping = null; - if(groupingDto == null) + if (groupingDto == null) { return grouping; - + } + Integer type = groupingDto.getGroupingTypeID(); - -// grouping.setActivities(); + + // grouping.setActivities(); if (Grouping.CHOSEN_GROUPING_TYPE.equals(type)) { grouping = new ChosenGrouping(); - }else if (Grouping.RANDOM_GROUPING_TYPE.equals(type)) { + } + else if (Grouping.RANDOM_GROUPING_TYPE.equals(type)) { grouping = new RandomGrouping(); - ((RandomGrouping)grouping).setLearnersPerGroup(groupingDto.getLearnersPerGroup()); - ((RandomGrouping)grouping).setNumberOfGroups(groupingDto.getNumberOfGroups()); - }else if (Grouping.CLASS_GROUPING_TYPE.equals(type)) { + ((RandomGrouping) grouping).setLearnersPerGroup(groupingDto.getLearnersPerGroup()); + ((RandomGrouping) grouping).setNumberOfGroups(groupingDto.getNumberOfGroups()); + } + else if (Grouping.CLASS_GROUPING_TYPE.equals(type)) { grouping = new LessonClass(); - }else{ - log.error("Unable to determine the grouping type. Creating a random grouping. GroupingDTO was "+groupingDto); } - + else if (Grouping.LEARNER_CHOICE_GROUPING_TYPE.equals(type)) { + grouping = new LearnerChoiceGrouping(); + ((LearnerChoiceGrouping) grouping).setLearnersPerGroup(groupingDto.getLearnersPerGroup()); + ((LearnerChoiceGrouping) grouping).setNumberOfGroups(groupingDto.getNumberOfGroups()); + ((LearnerChoiceGrouping) grouping).setEqualNumberOfLearners(groupingDto.getEqualNumberOfLearners()); + } + else { + log.error("Unable to determine the grouping type. Creating a random grouping. GroupingDTO was " + groupingDto); + } + //common fields grouping.setGroupingId(groupingDto.getGroupingID()); grouping.setGroupingUIID(groupingDto.getGroupingUIID()); grouping.setMaxNumberOfGroups(groupingDto.getMaxNumberOfGroups()); - + // process any groups that the design might have - if ( groupingDto.getGroups() != null ) { + if (groupingDto.getGroups() != null) { Iterator iter = groupingDto.getGroups().iterator(); - while ( iter.hasNext() ) { + while (iter.hasNext()) { GroupDTO groupDto = (GroupDTO) iter.next(); Group group = getGroup(groupDto, grouping); grouping.getGroups().add(group); @@ -2005,7 +2155,7 @@ } return grouping; } - + private Group getGroup(GroupDTO groupDto, Grouping grouping) { Group group = new Group(); group.setBranchActivities(null); @@ -2015,89 +2165,92 @@ group.setOrderId(groupDto.getOrderID()); return group; } - + /** Creates the map entry between a branch sequence activity and a group. We need the group maps and the activity maps * so that we can update the ids to the groups and the activities. Therefore this method must be done after all * the groups are imported and the activities are imported. * * Note: there isn't an set in the learning design for the branch mappings. The group objects actually contain the link * to the mappings, so this method updates the group objects. */ - private BranchActivityEntry getBranchActivityEntry(BranchActivityEntryDTO entryDto, MapgroupByUIIDMapper, + private BranchActivityEntry getBranchActivityEntry(BranchActivityEntryDTO entryDto, Map groupByUIIDMapper, Map activityByUIIDMapper) { SequenceActivity branch = (SequenceActivity) activityByUIIDMapper.get(entryDto.getSequenceActivityUIID()); - if ( branch == null ) { - log.error("Unable to find matching sequence activity for group to branch mapping "+entryDto+" Skipping entry"); + if (branch == null) { + log.error("Unable to find matching sequence activity for group to branch mapping " + entryDto + " Skipping entry"); return null; } - + Activity branchingActivity = activityByUIIDMapper.get(entryDto.getBranchingActivityUIID()); - if ( branchingActivity == null ) { - log.error("Unable to find matching branching activity for group to branch mapping "+entryDto+" Skipping entry"); + if (branchingActivity == null) { + log.error("Unable to find matching branching activity for group to branch mapping " + entryDto + " Skipping entry"); return null; } Group group = groupByUIIDMapper.get(entryDto.getGroupUIID()); BranchCondition condition = null; - if ( entryDto instanceof ToolOutputBranchActivityEntryDTO ) { - BranchConditionDTO dto = ((ToolOutputBranchActivityEntryDTO)entryDto).getCondition(); - if ( dto != null ) { + if (entryDto instanceof ToolOutputBranchActivityEntryDTO) { + BranchConditionDTO dto = ((ToolOutputBranchActivityEntryDTO) entryDto).getCondition(); + if (dto != null) { condition = new BranchCondition(dto); condition.setConditionId(null); } } BranchActivityEntry entry = null; - if ( condition != null ) { - entry = condition.allocateBranchToCondition(entryDto.getEntryUIID(), (SequenceActivity) branch, (BranchingActivity) branchingActivity); - } else if ( group != null ) { - entry = group.allocateBranchToGroup(entryDto.getEntryUIID(), (SequenceActivity) branch, (BranchingActivity) branchingActivity); - } - - if ( entry != null ) { - if ( branch.getBranchEntries() == null ) { + if (condition != null) { + entry = condition.allocateBranchToCondition(entryDto.getEntryUIID(), branch, (BranchingActivity) branchingActivity); + } + else if (group != null) { + entry = group.allocateBranchToGroup(entryDto.getEntryUIID(), branch, (BranchingActivity) branchingActivity); + } + + if (entry != null) { + if (branch.getBranchEntries() == null) { branch.setBranchEntries(new HashSet()); } branch.getBranchEntries().add(entry); return entry; - } else { - log.error("Unable to find group or condition for branch mapping "+entryDto+" Skipping entry"); + } + else { + log.error("Unable to find group or condition for branch mapping " + entryDto + " Skipping entry"); return null; } } - private Transition getTransition(TransitionDTO transDto, Map activityMapper) { Transition trans = new Transition(); - - if(transDto == null) + + if (transDto == null) { return trans; - + } + trans.setDescription(transDto.getDescription()); Activity fromAct = activityMapper.get(transDto.getFromActivityID()); trans.setFromActivity(fromAct); trans.setFromUIID(fromAct.getActivityUIID()); //also set transition to activity: It is nonsense for persisit data, but it is help this learning design validated fromAct.setTransitionTo(trans); -// set to null -// trans.setLearningDesign(); + // set to null + // trans.setLearningDesign(); trans.setTitle(transDto.getTitle()); - + Activity toAct = activityMapper.get(transDto.getToActivityID()); trans.setToActivity(toAct); trans.setToUIID(toAct.getActivityUIID()); //also set transition to activity: It is nonsense for persisit data, but it is help this learning design validated toAct.setTransitionFrom(trans); - + trans.setTransitionId(transDto.getTransitionID()); trans.setTransitionUIID(transDto.getTransitionUIID()); - + //reset value trans.setCreateDateTime(new Date()); return trans; } + /** * * @param actDto @@ -2106,64 +2259,65 @@ * @param toolMapper * @return */ - private Activity getActivity(AuthoringActivityDTO actDto, Map groupingList, - Map toolMapper, Map defaultActivityToParentActivityMapping) { + private Activity getActivity(AuthoringActivityDTO actDto, Map groupingList, + Map toolMapper, Map defaultActivityToParentActivityMapping) { - if(actDto == null) + if (actDto == null) { return null; + } int type = actDto.getActivityTypeID().intValue(); Grouping newGrouping; Activity act = Activity.getActivityInstance(type); - switch(act.getActivityTypeId()){ + switch (act.getActivityTypeId()) { case Activity.TOOL_ACTIVITY_TYPE: //get back the toolContent in new system by toolContentID in old system. ToolContent content = toolMapper.get(actDto.getToolContentID()); //if activity can not find matching tool, the content should be null. - if(content != null){ - ((ToolActivity)act).setTool(content.getTool()); - ((ToolActivity)act).setToolContentId(content.getToolContentId()); - ((ToolActivity)act).setToolSessions(null); + if (content != null) { + ((ToolActivity) act).setTool(content.getTool()); + ((ToolActivity) act).setToolContentId(content.getToolContentId()); + ((ToolActivity) act).setToolSessions(null); } break; case Activity.GROUPING_ACTIVITY_TYPE: newGrouping = groupingList.get(actDto.getCreateGroupingID()); - ((GroupingActivity)act).setCreateGrouping(newGrouping); - ((GroupingActivity)act).setCreateGroupingUIID(newGrouping.getGroupingUIID()); - ((GroupingActivity)act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.GROUPING)); + ((GroupingActivity) act).setCreateGrouping(newGrouping); + ((GroupingActivity) act).setCreateGroupingUIID(newGrouping.getGroupingUIID()); + ((GroupingActivity) act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.GROUPING)); break; case Activity.SYNCH_GATE_ACTIVITY_TYPE: - ((SynchGateActivity)act).setGateActivityLevelId(actDto.getGateActivityLevelID()); + ((SynchGateActivity) act).setGateActivityLevelId(actDto.getGateActivityLevelID()); //always set false - ((SynchGateActivity)act).setGateOpen(false); - ((SynchGateActivity)act).setWaitingLearners(null); - ((SynchGateActivity)act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.SYNC_GATE)); + ((SynchGateActivity) act).setGateOpen(false); + ((SynchGateActivity) act).setWaitingLearners(null); + ((SynchGateActivity) act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.SYNC_GATE)); break; case Activity.SCHEDULE_GATE_ACTIVITY_TYPE: - ((ScheduleGateActivity)act).setGateActivityLevelId(actDto.getGateActivityLevelID()); - ((ScheduleGateActivity)act).setWaitingLearners(null); + ((ScheduleGateActivity) act).setGateActivityLevelId(actDto.getGateActivityLevelID()); + ((ScheduleGateActivity) act).setWaitingLearners(null); //always set false - ((ScheduleGateActivity)act).setGateOpen(false); - - ((ScheduleGateActivity)act).setGateEndDateTime(actDto.getGateEndDateTime()); - ((ScheduleGateActivity)act).setGateStartDateTime(actDto.getGateStartDateTime()); - ((ScheduleGateActivity)act).setGateStartTimeOffset(actDto.getGateStartTimeOffset()); - ((ScheduleGateActivity)act).setGateEndTimeOffset(actDto.getGateEndTimeOffset()); - ((ScheduleGateActivity)act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.SCHEDULE_GATE)); + ((ScheduleGateActivity) act).setGateOpen(false); + + ((ScheduleGateActivity) act).setGateEndDateTime(actDto.getGateEndDateTime()); + ((ScheduleGateActivity) act).setGateStartDateTime(actDto.getGateStartDateTime()); + ((ScheduleGateActivity) act).setGateStartTimeOffset(actDto.getGateStartTimeOffset()); + ((ScheduleGateActivity) act).setGateEndTimeOffset(actDto.getGateEndTimeOffset()); + ((ScheduleGateActivity) act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.SCHEDULE_GATE)); break; case Activity.PERMISSION_GATE_ACTIVITY_TYPE: - ((PermissionGateActivity)act).setGateActivityLevelId(actDto.getGateActivityLevelID()); - ((PermissionGateActivity)act).setGateOpen(false); - ((PermissionGateActivity)act).setWaitingLearners(null); - ((PermissionGateActivity)act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.PERMISSION_GATE)); + ((PermissionGateActivity) act).setGateActivityLevelId(actDto.getGateActivityLevelID()); + ((PermissionGateActivity) act).setGateOpen(false); + ((PermissionGateActivity) act).setWaitingLearners(null); + ((PermissionGateActivity) act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.PERMISSION_GATE)); break; case Activity.PARALLEL_ACTIVITY_TYPE: break; case Activity.OPTIONS_ACTIVITY_TYPE: case Activity.OPTIONS_WITH_SEQUENCES_TYPE: - ((OptionsActivity)act).setMaxNumberOfOptions(actDto.getMaxOptions()); - ((OptionsActivity)act).setMinNumberOfOptions(actDto.getMinOptions()); - ((OptionsActivity)act).setOptionsInstructions(actDto.getOptionsInstructions()); + ((OptionsActivity) act).setMaxNumberOfOptions(actDto.getMaxOptions()); + ((OptionsActivity) act).setMinNumberOfOptions(actDto.getMinOptions()); + ((OptionsActivity) act).setOptionsInstructions(actDto.getOptionsInstructions()); break; case Activity.SEQUENCE_ACTIVITY_TYPE: break; @@ -2179,12 +2333,12 @@ ((BranchingActivity) act).setSystemTool(systemToolDAO.getSystemToolByID(SystemTool.TOOL_BASED_BRANCHING)); processBranchingFields((BranchingActivity) act, actDto); break; - } - - if ( act.isComplexActivity() && actDto.getDefaultActivityUIID() != null ) { - defaultActivityToParentActivityMapping.put(actDto.getDefaultActivityUIID(), (ComplexActivity)act); } - + + if (act.isComplexActivity() && actDto.getDefaultActivityUIID() != null) { + defaultActivityToParentActivityMapping.put(actDto.getDefaultActivityUIID(), (ComplexActivity) act); + } + act.setGroupingSupportType(actDto.getGroupingSupportType()); act.setActivityUIID(actDto.getActivityUIID()); act.setActivityCategoryID(actDto.getActivityCategoryID()); @@ -2195,49 +2349,51 @@ act.setDescription(actDto.getDescription()); act.setHelpText(actDto.getHelpText()); act.setLanguageFile(actDto.getLanguageFile()); - + // added in 2.1 - will be missing from earlier import files. - if ( actDto.getStopAfterActivity() != null ) + if (actDto.getStopAfterActivity() != null) { act.setStopAfterActivity(actDto.getStopAfterActivity()); - + } + //do not need set so far -// act.setLearningDesign(); - -// the id will be decide in LearningObject -// actDto.getLearningDesignID() -// act.setLearningLibrary(); - + // act.setLearningDesign(); + + // the id will be decide in LearningObject + // actDto.getLearningDesignID() + // act.setLearningLibrary(); + //be to decided by Fiona: 08/06/2006: It is ok to left it as null -// actDto.getLibraryActivityID() -// act.setLibraryActivity(); - + // actDto.getLibraryActivityID() + // act.setLibraryActivity(); + act.setLibraryActivityUiImage(actDto.getLibraryActivityUIImage()); act.setOrderId(actDto.getOrderID()); //temporarily set as to null, after scan all activities, then set it to valid value. act.setParentActivity(null); - + act.setParentUIID(actDto.getParentUIID()); act.setRunOffline(actDto.getRunOffline()); act.setTitle(actDto.getActivityTitle()); - + //relation will be decide in Transition object. -// act.setTransitionFrom(); -// act.setTransitionTo(); - + // act.setTransitionFrom(); + // act.setTransitionTo(); + act.setXcoord(actDto.getxCoord()); act.setYcoord(actDto.getyCoord()); - + //tranfer old grouping to latest newGrouping = groupingList.get(actDto.getGroupingID()); act.setGrouping(newGrouping); - if(newGrouping != null) + if (newGrouping != null) { act.setGroupingUIID(newGrouping.getGroupingUIID()); + } act.setCreateDateTime(new Date()); return act; } - + private void processBranchingFields(BranchingActivity act, AuthoringActivityDTO actDto) { act.setStartXcoord(actDto.getStartXCoord()); act.setEndXcoord(actDto.getEndXCoord()); @@ -2251,54 +2407,71 @@ public IActivityDAO getActivityDAO() { return activityDAO; } + public void setActivityDAO(IActivityDAO activityDAO) { this.activityDAO = activityDAO; } + public IGroupingDAO getGroupingDAO() { return groupingDAO; } + public void setGroupingDAO(IGroupingDAO groupingDAO) { this.groupingDAO = groupingDAO; } + public ILearningDesignDAO getLearningDesignDAO() { return learningDesignDAO; } + public void setLearningDesignDAO(ILearningDesignDAO learningDesignDAO) { this.learningDesignDAO = learningDesignDAO; } + public ILicenseDAO getLicenseDAO() { return licenseDAO; } + public void setBaseDAO(IBaseDAO baseDAO) { this.baseDAO = baseDAO; } + public void setLicenseDAO(ILicenseDAO licenseDAO) { this.licenseDAO = licenseDAO; } + public IToolContentDAO getToolContentDAO() { return toolContentDAO; } + public void setToolContentDAO(IToolContentDAO toolContentDAO) { this.toolContentDAO = toolContentDAO; } + public IToolDAO getToolDAO() { return toolDAO; } + public void setToolDAO(IToolDAO toolDAO) { this.toolDAO = toolDAO; } + public ITransitionDAO getTransitionDAO() { return transitionDAO; } + public void setTransitionDAO(ITransitionDAO transitionDAO) { this.transitionDAO = transitionDAO; } + public void setToolImportSupportDAO(IToolImportSupportDAO toolImportSupportDAO) { this.toolImportSupportDAO = toolImportSupportDAO; } + public void setLearningLibraryDAO(ILearningLibraryDAO learningLibraryDAO) { this.learningLibraryDAO = learningLibraryDAO; } + public void setSystemToolDAO(ISystemToolDAO systemToolDAO) { this.systemToolDAO = systemToolDAO; } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignValidator.java =================================================================== diff -u -r62d0bb09a4512210d42ebd60885c7e1834c0cc5e -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignValidator.java (.../LearningDesignValidator.java) (revision 62d0bb09a4512210d42ebd60885c7e1834c0cc5e) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignValidator.java (.../LearningDesignValidator.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -54,75 +54,83 @@ MessageService messageService; LearningDesign learningDesign; Vector errors; - + LearningDesignValidator(LearningDesign learningDesign, MessageService messageService) { this.messageService = messageService; this.learningDesign = learningDesign; } - + /** Run the validation */ public Vector validate() { - errors = new Vector(); // initialises the list of validation messages. - + errors = new Vector(); // initialises the list of validation messages. + // check all activities have their necessary transitions. First check the // top level, then we need to check each branch inside a branching activity. - Set topLevelActivities = (Set) learningDesign.getParentActivities(); + Set topLevelActivities = learningDesign.getParentActivities(); validateActivityTransitionRules(topLevelActivities, learningDesign.getTransitions()); - - for ( Activity activity : (Set) learningDesign.getActivities() ) { + + for (Activity activity : (Set) learningDesign.getActivities()) { checkIfGroupingRequired(activity); - validateGroupingIfGroupingIsApplied(activity); + validateGroupingIfGroupingIsApplied(activity); validateOptionalActivity(activity); validateOptionsActivityOrderId(activity); validateGroupingActivity(activity); Vector activityErrors = activity.validateActivity(messageService); - if(activityErrors != null && !activityErrors.isEmpty()) + if (activityErrors != null && !activityErrors.isEmpty()) { errors.addAll(activityErrors); + } } cleanupValidationErrors(); return errors; } + /** * Cleans up multiple and redundant error messages in the list. * @param errors List of errors to cleanup. */ private void cleanupValidationErrors() { Iterator it = errors.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { cleanupTransitionErrors(it); } } - + private void cleanupTransitionErrors(Iterator topIt) { ValidationErrorDTO nextError; ValidationErrorDTO currentError = (ValidationErrorDTO) topIt.next(); Iterator it = errors.iterator(); - - while(it.hasNext()) { + + while (it.hasNext()) { nextError = (ValidationErrorDTO) it.next(); - - if(currentError.getCode().equals(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE) && - (nextError.getCode().equals(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE) || - nextError.getCode().equals(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE))) - if(currentError.getUIID().equals(nextError.getUIID())) { + + if (currentError.getCode().equals(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE) + && (nextError.getCode().equals(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE) || nextError.getCode().equals( + ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE))) { + if (currentError.getUIID().equals(nextError.getUIID())) { topIt.remove(); return; } - else if(currentError.getCode().equals(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE)) - if(nextError.getCode().equals(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE)) - if(currentError.getUIID().equals(nextError.getUIID())) + else if (currentError.getCode().equals(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE)) { + if (nextError.getCode().equals(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE)) { + if (currentError.getUIID().equals(nextError.getUIID())) { it.remove(); - else if(currentError.getCode().equals(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE)) - if(nextError.getCode().equals(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE)) - if(currentError.getUIID().equals(nextError.getUIID())) - it.remove(); - - } - - + } + else if (currentError.getCode().equals(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE)) { + if (nextError.getCode().equals(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE)) { + if (currentError.getUIID().equals(nextError.getUIID())) { + it.remove(); + } + } + } + } + } + } + + } + } - + /** * Perform transition related validations. * @@ -137,87 +145,87 @@ * @param transitions A transitions from the design * */ - private void validateActivityTransitionRules(Set activities, Set transitions) - { + private void validateActivityTransitionRules(Set activities, Set transitions) { validateTransitions(transitions); ArrayList noInputTransition = new ArrayList(); //a list to hold the activities which have no input transition ArrayList noOuputTransition = new ArrayList(); //a list to hold the activities which have no output transition int numOfTopLevelActivities = activities.size(); - + // All the branching activities and optional activities we find are stored in this list, so we can process them at the end. // We don't want to process them straight away or the branch activity errors would be mixed up with the previous level's errors. // We need the optional activities, as they may contain a branching activity. - ArrayList complexActivitiesToProcess = null; - - for ( Activity activity : activities ) - { + ArrayList complexActivitiesToProcess = null; + + for (Activity activity : activities) { checkActivityForTransition(activity, numOfTopLevelActivities); - if (activity.getTransitionFrom() == null) - { + if (activity.getTransitionFrom() == null) { noOuputTransition.add(activity); } - if (activity.getTransitionTo() == null) - { + if (activity.getTransitionTo() == null) { noInputTransition.add(activity); } complexActivitiesToProcess = checkActivityForFurtherProcessing(complexActivitiesToProcess, activity); } - - if (numOfTopLevelActivities > 0) - { - if (noInputTransition.size() == 0) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.INPUT_TRANSITION_ERROR_TYPE2_KEY))); - - if (noInputTransition.size() > 1) - { + if (numOfTopLevelActivities > 0) { + if (noInputTransition.size() == 0) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.INPUT_TRANSITION_ERROR_TYPE2_KEY))); + } + + if (noInputTransition.size() > 1) { + // put out an error for each activity, but skip the any activities that are the first activity in the branch as they shouldn't have an input transition. - for ( Activity a : noInputTransition) { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.INPUT_TRANSITION_ERROR_TYPE1_KEY), a.getActivityUIID())); + for (Activity a : noInputTransition) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.INPUT_TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.INPUT_TRANSITION_ERROR_TYPE1_KEY), a.getActivityUIID())); } } - if (noOuputTransition.size() == 0) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE,messageService.getMessage(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_TYPE2_KEY))); + if (noOuputTransition.size() == 0) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_TYPE2_KEY))); + } - if (noOuputTransition.size() > 1) - { + if (noOuputTransition.size() > 1) { //there is more than one activity with no output transitions - for ( Activity a : noOuputTransition) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_TYPE1_KEY), a.getActivityUIID())); + for (Activity a : noOuputTransition) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.OUTPUT_TRANSITION_ERROR_TYPE1_KEY), a.getActivityUIID())); + } } } - + processComplexActivitiesForTransitions(complexActivitiesToProcess); } private void processComplexActivitiesForTransitions(ArrayList complexActivitiesToProcess) { - if ( complexActivitiesToProcess != null ) - { - for ( ComplexActivity complex : complexActivitiesToProcess ) + if (complexActivitiesToProcess != null) { + for (ComplexActivity complex : complexActivitiesToProcess) { checkTransitionsInComplexActivity(complex); + } } - + } - - private void checkTransitionsInComplexActivity(ComplexActivity complexActivity) - { + + private void checkTransitionsInComplexActivity(ComplexActivity complexActivity) { // All the branching activities and optional activities we find are stored in this list, so we can process them at the end. // We don't want to process them straight away or the branch activity errors would be mixed up with the previous level's errors. // We need the optional activities, as they may contain a branching activity. - ArrayList complexActivitiesToProcess = null; + ArrayList complexActivitiesToProcess = null; - if ( complexActivity.isBranchingActivity() ) { - for ( ComplexActivity sequence : (Set) complexActivity.getActivities() ) { - for ( Activity activity : (Set) sequence.getActivities() ) { + if (complexActivity.isBranchingActivity()) { + for (ComplexActivity sequence : (Set) complexActivity.getActivities()) { + for (Activity activity : (Set) sequence.getActivities()) { checkActivityForTransition(activity, sequence.getActivities().size()); complexActivitiesToProcess = checkActivityForFurtherProcessing(complexActivitiesToProcess, activity); } } - } else { - for ( Activity activity : (Set) complexActivity.getActivities() ) { + } + else { + for (Activity activity : (Set) complexActivity.getActivities()) { complexActivitiesToProcess = checkActivityForFurtherProcessing(complexActivitiesToProcess, activity); } } @@ -230,26 +238,27 @@ * @param activity * @return */ - private ArrayList checkActivityForFurtherProcessing( - ArrayList complexActivitiesToProcess, + private ArrayList checkActivityForFurtherProcessing(ArrayList complexActivitiesToProcess, Activity activity) { - if ( activity.isComplexActivity() && ! activity.isParallelActivity() ) - { - if ( complexActivitiesToProcess == null ) + if (activity.isComplexActivity() && !activity.isParallelActivity()) { + if (complexActivitiesToProcess == null) { complexActivitiesToProcess = new ArrayList(); - complexActivitiesToProcess.add((ComplexActivity ) activity); + } + complexActivitiesToProcess.add((ComplexActivity) activity); } return complexActivitiesToProcess; } private boolean isFirstActivityInBranch(Activity a) { ComplexActivity parentActivity = (ComplexActivity) a.getParentActivity(); - if ( parentActivity == null || ! parentActivity.isSequenceActivity()) + if (parentActivity == null || !parentActivity.isSequenceActivity()) { return false; - else + } + else { return parentActivity.getDefaultActivity() != null && parentActivity.getDefaultActivity().equals(a); + } } - + /** * This method checks if each transition in the learning design has an activity * before and after the transition. @@ -258,23 +267,25 @@ * the ValidationErrorDTO is added to the list of validation messages. * @param transitions the set of transitions to iterate through and validate */ - private void validateTransitions(Set transitions) - { + private void validateTransitions(Set transitions) { Iterator i = transitions.iterator(); - while (i.hasNext()) - { - Transition transition = (Transition)i.next(); + while (i.hasNext()) { + Transition transition = (Transition) i.next(); Activity fromActivity = transition.getFromActivity(); Activity toActivity = transition.getToActivity(); - if (fromActivity == null) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.TRANSITION_ERROR_KEY), transition.getTransitionUIID())); - else if (toActivity == null) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.TRANSITION_ERROR_KEY), transition.getTransitionUIID())); - + if (fromActivity == null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.TRANSITION_ERROR_KEY), transition.getTransitionUIID())); + } + else if (toActivity == null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.TRANSITION_ERROR_KEY), transition.getTransitionUIID())); + } + } - + } - + /** * For any learning design that has more than one activity then each activity should have at least an input * or output transition. If there is only one activity in the learning design, then that activity should @@ -284,26 +295,27 @@ * @param activity The Activity to validate * @param numOfActivities The number of activities in the learning design. */ - private void checkActivityForTransition(Activity activity, int numOfActivities) - { + private void checkActivityForTransition(Activity activity, int numOfActivities) { //if one activity, then shouldn't have any transitions Transition inputTransition = activity.getTransitionTo(); Transition outputTransition = activity.getTransitionFrom(); - - if(numOfActivities > 1) - { - if (inputTransition == null && outputTransition == null && ! isFirstActivityInBranch(activity) ) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_KEY), activity.getActivityUIID())); + + if (numOfActivities > 1) { + if (inputTransition == null && outputTransition == null && !isFirstActivityInBranch(activity)) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_KEY), activity.getActivityUIID())); + } } - if (numOfActivities == 1) - { - if (inputTransition != null || outputTransition != null) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_KEY), activity.getActivityUIID())); - + if (numOfActivities == 1) { + if (inputTransition != null || outputTransition != null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.ACTIVITY_TRANSITION_ERROR_KEY), activity.getActivityUIID())); + } + } - + } - + /** * If grouping support type is set to GROUPING_SUPPORT_REQUIRED, * then the activity is validated to ensure that the grouping exists. @@ -315,55 +327,49 @@ * * @param activity */ - private void checkIfGroupingRequired(Activity activity) - { - - Integer groupingSupportType = activity.getGroupingSupportType(); - if (groupingSupportType.intValue() == Grouping.GROUPING_SUPPORT_REQUIRED) - { - //make sure activity has been assigned a grouping - Grouping grouping = activity.getGrouping(); - if (grouping == null) - { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_REQUIRED_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.GROUPING_REQUIRED_ERROR_KEY), activity.getActivityUIID())); - } + private void checkIfGroupingRequired(Activity activity) { + + Integer groupingSupportType = activity.getGroupingSupportType(); + if (groupingSupportType.intValue() == Grouping.GROUPING_SUPPORT_REQUIRED) { + //make sure activity has been assigned a grouping + Grouping grouping = activity.getGrouping(); + if (grouping == null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_REQUIRED_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.GROUPING_REQUIRED_ERROR_KEY), activity.getActivityUIID())); } - else if(groupingSupportType.intValue() == Grouping.GROUPING_SUPPORT_NONE) - { - Grouping grouping = activity.getGrouping(); - if (grouping != null) - { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_NOT_REQUIRED_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.GROUPING_NOT_REQUIRED_ERROR_KEY), activity.getActivityUIID())); - } + } + else if (groupingSupportType.intValue() == Grouping.GROUPING_SUPPORT_NONE) { + Grouping grouping = activity.getGrouping(); + if (grouping != null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_NOT_REQUIRED_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.GROUPING_NOT_REQUIRED_ERROR_KEY), activity.getActivityUIID())); } - + } + } - + /** * If this activity is an OptionalActivity, then it must contain one or more * activities. * * @param parentActivity */ - private void validateOptionalActivity(Activity parentActivity) - { - - if (parentActivity.isOptionsActivity()) - { - //get the child activities and check how many there are. - OptionsActivity optionsActivity = (OptionsActivity)parentActivity; - Set childActivities = optionsActivity.getActivities(); - int numOfChildActivities = childActivities.size(); - if(numOfChildActivities == 0) - { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.OPTIONAL_ACTIVITY_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.OPTIONAL_ACTIVITY_ERROR_KEY), optionsActivity.getActivityUIID())); - } - - + private void validateOptionalActivity(Activity parentActivity) { + + if (parentActivity.isOptionsActivity()) { + //get the child activities and check how many there are. + OptionsActivity optionsActivity = (OptionsActivity) parentActivity; + Set childActivities = optionsActivity.getActivities(); + int numOfChildActivities = childActivities.size(); + if (numOfChildActivities == 0) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.OPTIONAL_ACTIVITY_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.OPTIONAL_ACTIVITY_ERROR_KEY), optionsActivity.getActivityUIID())); } - + + } + } - + /** * If this activity is an GroupingActivity, the number of groups in the grouping records is greater than 0 and * the grouping has some groups, then the actual number of groups must no exceed the desired number of groups. @@ -372,30 +378,33 @@ * * @param parentActivity */ - private void validateGroupingActivity(Activity activity) - { - - if (activity.isGroupingActivity()) - { - //get the child activities and check how many there are. - GroupingActivity groupingActivity = (GroupingActivity)activity; - Grouping grouping = groupingActivity.getCreateGrouping(); - if ( grouping == null ) { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_ACTIVITY_MISSING_GROUPING_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_MISSING_GROUPING_KEY), activity.getActivityUIID())); - } - Integer numGroupsInteger = null; - if ( grouping.isRandomGrouping() ) { - RandomGrouping random = (RandomGrouping) grouping; - numGroupsInteger = random.getNumberOfGroups(); - } else { - numGroupsInteger = grouping.getMaxNumberOfGroups(); - } - int maxNumGroups = numGroupsInteger == null ? 0 : numGroupsInteger.intValue(); - if ( maxNumGroups > 0 && grouping.getGroups() != null && grouping.getGroups().size() > maxNumGroups) { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY), activity.getActivityUIID())); - } + private void validateGroupingActivity(Activity activity) { + + if (activity.isGroupingActivity()) { + //get the child activities and check how many there are. + GroupingActivity groupingActivity = (GroupingActivity) activity; + Grouping grouping = groupingActivity.getCreateGrouping(); + if (grouping == null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_ACTIVITY_MISSING_GROUPING_ERROR_CODE, + messageService.getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_MISSING_GROUPING_KEY), activity + .getActivityUIID())); } - + Integer numGroupsInteger = null; + if (grouping.isRandomGrouping()) { + RandomGrouping random = (RandomGrouping) grouping; + numGroupsInteger = random.getNumberOfGroups(); + } + else { + numGroupsInteger = grouping.getMaxNumberOfGroups(); + } + int maxNumGroups = numGroupsInteger == null ? 0 : numGroupsInteger.intValue(); + if (maxNumGroups > 0 && grouping.getGroups() != null && grouping.getGroups().size() > maxNumGroups) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_ERROR_CODE, + messageService.getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY), activity + .getActivityUIID())); + } + } + } /** @@ -406,59 +415,57 @@ * The currentActivityId should be 1 greater than the previous activity order id. * @param parentActivity */ - private void validateOptionsActivityOrderId(Activity parentActivity) - { + private void validateOptionsActivityOrderId(Activity parentActivity) { Integer thisActivityOrderId = null; Integer previousActivityOrderId = null; boolean validOrderId = true; - if(parentActivity.isOptionsActivity()) - { - OptionsActivity optionsActivity = (OptionsActivity)parentActivity; + if (parentActivity.isOptionsActivity()) { + OptionsActivity optionsActivity = (OptionsActivity) parentActivity; Set childActivities = optionsActivity.getActivities(); //childActivities should be sorted according to order id (using the activityOrderComparator) Iterator i = childActivities.iterator(); - while (i.hasNext() && validOrderId) - { - Activity childActivity = (Activity)i.next(); - thisActivityOrderId= childActivity.getOrderId(); - if (previousActivityOrderId != null) - { + while (i.hasNext() && validOrderId) { + Activity childActivity = (Activity) i.next(); + thisActivityOrderId = childActivity.getOrderId(); + if (previousActivityOrderId != null) { //compare the two numbers - if (thisActivityOrderId==null ) { + if (thisActivityOrderId == null) { validOrderId = false; - } else if ( thisActivityOrderId.longValue() != (previousActivityOrderId.longValue() + 1)) { + } + else if (thisActivityOrderId.longValue() != previousActivityOrderId.longValue() + 1) { validOrderId = false; } - + } - else - { + else { //this is the first activity, since the previousActivityId is null - if(thisActivityOrderId==null || thisActivityOrderId.longValue()!= 1) + if (thisActivityOrderId == null || thisActivityOrderId.longValue() != 1) { validOrderId = false; + } } - previousActivityOrderId = thisActivityOrderId; + previousActivityOrderId = thisActivityOrderId; } - - if (!validOrderId) - errors.add(new ValidationErrorDTO(ValidationErrorDTO.OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY), optionsActivity.getActivityUIID())); - - } + + if (!validOrderId) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_CODE, + messageService.getMessage(ValidationErrorDTO.OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY), + optionsActivity.getActivityUIID())); + } + + } } - /** * If applyGrouping is set, then the grouping must exist * @param activity */ - private void validateGroupingIfGroupingIsApplied(Activity activity) - { - if(activity.getApplyGrouping().booleanValue()) //if grouping is applied, ensure grouping exists - { - if (activity.getGrouping() == null) - { - errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_SELECTED_ERROR_CODE, messageService.getMessage(ValidationErrorDTO.GROUPING_SELECTED_ERROR_KEY), activity.getActivityUIID())); - } + private void validateGroupingIfGroupingIsApplied(Activity activity) { + if (activity.getApplyGrouping().booleanValue()) //if grouping is applied, ensure grouping exists + { + if (activity.getGrouping() == null) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_SELECTED_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.GROUPING_SELECTED_ERROR_KEY), activity.getActivityUIID())); } - + } + } } Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java =================================================================== diff -u -r6008e13a4cc3e08a3350be02c35a22eb6ee5a9c1 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 6008e13a4cc3e08a3350be02c35a22eb6ee5a9c1) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -70,7 +70,7 @@ * Get the count of all the learners who have started the lesson. They may not be currently online. */ public Integer getCountActiveLessonLearners(Long lessonId); - + /** Get the lesson details for the LAMS client. Suitable for the monitoring client. * Contains a count of the total number of learners in the lesson and the number of active learners. * This is a pretty intensive call as it counts all the learners in the @@ -94,145 +94,153 @@ public abstract LessonDTO getLessonData(Long lessonId); /** - * If the supplied learner is not already in a group, then perform grouping for - * the learners who have started the lesson, based on the grouping activity. - * Currently used for random grouping. - * This method should be used when we do have an grouping activity and learner that is - * already part of the Hibernate session. (e.g. from the ForceComplete) - * - * @param lessonId lesson id (mandatory) - * @param groupingActivity the activity that has create grouping. (mandatory) - * @param learner the learner to be check before grouping. (mandatory) - */ - public void performGrouping(Long lessonId, GroupingActivity groupingActivity, User learner) throws LessonServiceException; + * If the supplied learner is not already in a group, then perform grouping for + * the learners who have started the lesson, based on the grouping activity. + * Currently used for random grouping. + * This method should be used when we do have an grouping activity and learner that is + * already part of the Hibernate session. (e.g. from the ForceComplete) + * + * @param lessonId lesson id (mandatory) + * @param groupingActivity the activity that has create grouping. (mandatory) + * @param learner the learner to be check before grouping. (mandatory) + */ + public void performGrouping(Long lessonId, GroupingActivity groupingActivity, User learner) throws LessonServiceException; /** - * Perform the grouping, setting the given list of learners as one group. - * @param groupingActivity the activity that has create grouping. (mandatory) - * @param groupName (optional) - * @param learners to form one group (mandatory) - */ - public void performGrouping(GroupingActivity groupingActivity, String groupName, List learners) throws LessonServiceException; - + * Perform the grouping, setting the given list of learners as one group. + * @param groupingActivity the activity that has create grouping. (mandatory) + * @param groupName (optional) + * @param learners to form one group (mandatory) + */ + public void performGrouping(GroupingActivity groupingActivity, String groupName, List learners) throws LessonServiceException; + /** - * Perform the grouping, setting the given list of learners as one group. Used in suitations - * where there is a grouping but no grouping activity (e.g. in branching). - * @param grouping the object on which to perform the grouing. (mandatory) - * @param groupName (optional) - * @param learners to form one group (mandatory) - */ - public void performGrouping(Grouping grouping, String groupName, List learners) throws LessonServiceException; + * Perform the grouping, setting the given list of learners as one group. Used in suitations + * where there is a grouping but no grouping activity (e.g. in branching). + * @param grouping the object on which to perform the grouing. (mandatory) + * @param groupName (optional) + * @param learners to form one group (mandatory) + */ + public void performGrouping(Grouping grouping, String groupName, List learners) throws LessonServiceException; - /** - * Perform grouping for all the learners who have started the lesson, based on the grouping. - * Currently used for chosen grouping and branching - * @param lessonId lesson id (mandatory) - * @param groupId group id (mandatory) - * @param grouping the object on which to perform the grouing. (mandatory) - */ - public void performGrouping(Grouping grouping, Long groupId, List learners) throws LessonServiceException; + /** + * Perform grouping for all the learners who have started the lesson, based on the grouping. + * Currently used for chosen grouping and branching + * @param lessonId lesson id (mandatory) + * @param groupId group id (mandatory) + * @param grouping the object on which to perform the grouing. (mandatory) + */ + public void performGrouping(Grouping grouping, Long groupId, List learners) throws LessonServiceException; - /** - * Remove learners from the given group. - * @param grouping the grouping from which to remove the learners (mandatory) - * @param groupName if not null only remove user from this group, if null remove learner from any group. - * @param learners the learners to be removed (mandatory) - */ - public void removeLearnersFromGroup(Grouping grouping, Long groupId, List learners) throws LessonServiceException; - - /** Create an empty group for the given grouping. If the group name already exists - * then it will force the name to be unique. - * - * @param grouping the grouping. (mandatory) - * @param groupName (mandatory) - * @return the new group - */ - public Group createGroup(Grouping grouping, String name) throws LessonServiceException; + /** + * Perform grouping for the given learner. + * + * @param grouping the object on which to perform the grouing. (mandatory) + * @param groupId group id (mandatory) + * @param learner learner to group (mandatory) + * @throws LessonServiceException + */ + public void performGrouping(Grouping grouping, Long groupId, User learner) throws LessonServiceException; - /** - * Remove a group for the given grouping. If the group is already used (e.g. a tool session exists) - * then it throws a GroupingException. - * - * @param grouping the grouping that contains the group to remove. (mandatory) - * @param groupName (mandatory) - */ - public void removeGroup(Grouping grouping, Long groupId) throws LessonServiceException; - - /** - * Add a learner to the lesson class. Checks for duplicates. - * @paran userId new learner id - * @return true if added user, returns false if the user already a learner and hence not added. - */ - public boolean addLearner(Long lessonId, Integer userId) throws LessonServiceException; + /** + * Remove learners from the given group. + * @param grouping the grouping from which to remove the learners (mandatory) + * @param groupName if not null only remove user from this group, if null remove learner from any group. + * @param learners the learners to be removed (mandatory) + */ + public void removeLearnersFromGroup(Grouping grouping, Long groupId, List learners) throws LessonServiceException; - /** - * Add a set of learners to the lesson class. + /** Create an empty group for the given grouping. If the group name already exists + * then it will force the name to be unique. * + * @param grouping the grouping. (mandatory) + * @param groupName (mandatory) + * @return the new group + */ + public Group createGroup(Grouping grouping, String name) throws LessonServiceException; + + /** + * Remove a group for the given grouping. If the group is already used (e.g. a tool session exists) + * then it throws a GroupingException. + * + * @param grouping the grouping that contains the group to remove. (mandatory) + * @param groupName (mandatory) + */ + public void removeGroup(Grouping grouping, Long groupId) throws LessonServiceException; + + /** + * Add a learner to the lesson class. Checks for duplicates. + * @paran userId new learner id + * @return true if added user, returns false if the user already a learner and hence not added. + */ + public boolean addLearner(Long lessonId, Integer userId) throws LessonServiceException; + + /** + * Add a set of learners to the lesson class. + * * If version of the method is designed to be called from Moodle or some other external system, * and is less efficient in that it has to look up the user from the user id. * If we don't do this, then we may get a a session closed issue if this code is called from the * LoginRequestValve (as the users will be from a previous session) * - * @param lessonId new learner id - * @param userIds array of new learner ids - */ - public void addLearners(Long lessonId, Integer[] userIds) throws LessonServiceException; + * @param lessonId new learner id + * @param userIds array of new learner ids + */ + public void addLearners(Long lessonId, Integer[] userIds) throws LessonServiceException; - /** - * Add a set of learners to the lesson class. To be called within LAMS - see - * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. - * - * @param lesson lesson - * @param users the users to add as learners - */ - public void addLearners(Lesson lesson, Collection users) throws LessonServiceException; + /** + * Add a set of learners to the lesson class. To be called within LAMS - see + * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. + * + * @param lesson lesson + * @param users the users to add as learners + */ + public void addLearners(Lesson lesson, Collection users) throws LessonServiceException; + /** + * Add a new staff member to the lesson class. Checks for duplicates. + * @paran userId new learner id + * @return true if added user, returns false if the user already a staff member and hence not added. + */ + public boolean addStaffMember(Long lessonId, Integer userId) throws LessonServiceException; - /** - * Add a new staff member to the lesson class. Checks for duplicates. - * @paran userId new learner id - * @return true if added user, returns false if the user already a staff member and hence not added. - */ - public boolean addStaffMember(Long lessonId, Integer userId) throws LessonServiceException; - - /** - * Add a set of staff to the lesson class. + /** + * Add a set of staff to the lesson class. * * If version of the method is designed to be called from Moodle or some other external system, * and is less efficient in that it has to look up the user from the user id. * If we don't do this, then we may get a a session closed issue if this code is called from the * LoginRequestValve (as the users will be from a previous session) * - * @param lessonId - * @param userIds array of new staff ids - */ - public void addStaffMembers(Long lessonId, Integer[] userIds) throws LessonServiceException; - - /** - * Add a set of staff members to the lesson class. To be called within LAMS - see - * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. - * - * @param lesson lesson - * @param users the users to add as learners - */ - public void addStaffMembers(Lesson lesson, Collection users) throws LessonServiceException; - - /** - * Remove references to an activity from all learner progress entries. - * Used by Live Edit, to remove any references to the system gates - * @param activity The activity for which learner progress references should be removed. + * @param lessonId + * @param userIds array of new staff ids + */ + public void addStaffMembers(Long lessonId, Integer[] userIds) throws LessonServiceException; + + /** + * Add a set of staff members to the lesson class. To be called within LAMS - see + * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. + * + * @param lesson lesson + * @param users the users to add as learners */ - public void removeProgressReferencesToActivity(Activity activity) throws LessonServiceException; - - /** - * Mark any learner progresses for this lesson as not completed. Called when Live Edit - * ends, to ensure that if there were any completed progress records, and the design - * was extended, then they are no longer marked as completed. - * @param lessonId The lesson for which learner progress entries should be updated. - */ - public void performMarkLessonUncompleted(Long lessonId) throws LessonServiceException; + public void addStaffMembers(Lesson lesson, Collection users) throws LessonServiceException; + /** + * Remove references to an activity from all learner progress entries. + * Used by Live Edit, to remove any references to the system gates + * @param activity The activity for which learner progress references should be removed. + */ + public void removeProgressReferencesToActivity(Activity activity) throws LessonServiceException; + /** + * Mark any learner progresses for this lesson as not completed. Called when Live Edit + * ends, to ensure that if there were any completed progress records, and the design + * was extended, then they are no longer marked as completed. + * @param lessonId The lesson for which learner progress entries should be updated. + */ + public void performMarkLessonUncompleted(Long lessonId) throws LessonServiceException; + /** * Get the list of users who have attempted 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 @@ -248,7 +256,7 @@ * system activities such as branching. */ public 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. @@ -262,31 +270,31 @@ * system activities such as branching. */ public Integer getCountLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException; - + /** - * Returns map of lessons in an organisation for a particular learner or staff user. - * @param userId user's id - * @param orgId org's id - * @param isStaff return lessons where user is staff, or where user is learner - * @return map of lesson beans used in the index page - */ - public Map getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, boolean isStaff); - + * Returns map of lessons in an organisation for a particular learner or staff user. + * @param userId user's id + * @param orgId org's id + * @param isStaff return lessons where user is staff, or where user is learner + * @return map of lesson beans used in the index page + */ + public Map getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, boolean isStaff); + /** - * Gets the learner's progress details for a particular lesson. Will return null if the user - * has not started the lesson. - * - * @param learnerId user's id - * @param lessonId lesson's id - * @return learner's progress or null - */ - public LearnerProgress getUserProgressForLesson(Integer learnerId, Long lessonId); - - /** - * Gets list of lessons which are originally based on the given learning design id. - * @param ldId - * @param orgId - * @return list of lessons - */ - public List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId); + * Gets the learner's progress details for a particular lesson. Will return null if the user + * has not started the lesson. + * + * @param learnerId user's id + * @param lessonId lesson's id + * @return learner's progress or null + */ + public LearnerProgress getUserProgressForLesson(Integer learnerId, Long lessonId); + + /** + * Gets list of lessons which are originally based on the given learning design id. + * @param ldId + * @param orgId + * @return list of lessons + */ + public List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java =================================================================== diff -u -r6008e13a4cc3e08a3350be02c35a22eb6ee5a9c1 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 6008e13a4cc3e08a3350be02c35a22eb6ee5a9c1) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -21,9 +21,10 @@ * **************************************************************** */ -/* $$Id$$ */ +/* $$Id$$ */ package org.lamsfoundation.lams.lesson.service; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -53,7 +54,6 @@ import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.util.MessageService; - /** * Access the general lesson details. * @@ -74,26 +74,25 @@ * to a lesson will staying in the cache forever. * */ -public class LessonService implements ILessonService -{ +public class LessonService implements ILessonService { private static Logger log = Logger.getLogger(LessonService.class); - + private ILessonDAO lessonDAO; - private ILessonClassDAO lessonClassDAO; + private ILessonClassDAO lessonClassDAO; private IGroupingDAO groupingDAO; private MessageService messageService; private IBaseDAO baseDAO; private ILearnerProgressDAO learnerProgressDAO; - /* ******* Spring injection methods ***************************************/ + /* ******* Spring injection methods ***************************************/ public void setLessonDAO(ILessonDAO lessonDAO) { this.lessonDAO = lessonDAO; } - + public void setLessonClassDAO(ILessonClassDAO lessonClassDAO) { this.lessonClassDAO = lessonClassDAO; } - + public void setGroupingDAO(IGroupingDAO groupingDAO) { this.groupingDAO = groupingDAO; } @@ -106,60 +105,53 @@ this.messageService = messageService; } - public void setBaseDAO( - IBaseDAO baseDAO) { + public void setBaseDAO(IBaseDAO baseDAO) { this.baseDAO = baseDAO; } - - /* *********** Service methods ***********************************************/ /* (non-Javadoc) * @see org.lamsfoundation.lams.lesson.service.ILessonService#getActiveLessonLearners(java.lang.Long) */ - public List getActiveLessonLearners(Long lessonId) - { - return lessonDAO.getActiveLearnerByLesson(lessonId); - } + public List getActiveLessonLearners(Long lessonId) { + return lessonDAO.getActiveLearnerByLesson(lessonId); + } /* (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); - } + 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) - { - return lessonDAO.getCountActiveLearnerByLesson(lessonId); - } + public Integer getCountActiveLessonLearners(Long lessonId) { + return lessonDAO.getCountActiveLearnerByLesson(lessonId); + } - /* (non-Javadoc) * @see org.lamsfoundation.lams.lesson.service.ILessonService#getLessonDetails(java.lang.Long) */ public LessonDetailsDTO getLessonDetails(Long lessonId) { Lesson lesson = lessonDAO.getLesson(lessonId); LessonDetailsDTO dto = null; - if ( lesson != null ) { + if (lesson != null) { dto = lesson.getLessonDetails(); Integer active = getCountActiveLessonLearners(lessonId); - dto.setNumberStartedLearners(active!=null?active:new Integer(0)); + dto.setNumberStartedLearners(active != null ? active : new Integer(0)); } return dto; } - + /* (non-Javadoc) * @see org.lamsfoundation.lams.lesson.service.ILessonService#getLessonData(java.lang.Long) */ public LessonDTO getLessonData(Long lessonId) { Lesson lesson = lessonDAO.getLesson(lessonId); LessonDTO dto = null; - if ( lesson != null ) { + if (lesson != null) { dto = lesson.getLessonData(); } return dto; @@ -174,317 +166,357 @@ } /** - * If the supplied learner is not already in a group, then perform grouping for - * the learners who have started the lesson, based on the grouping activity. - * The grouper decides who goes in which group. - * - * Can only be run on a Random Grouping - * - * @param lessonId lesson id (mandatory) - * @param groupingActivity the activity that has create grouping. (mandatory) - * @param learner the learner to be check before grouping. (mandatory) - */ - public void performGrouping(Long lessonId, GroupingActivity groupingActivity, User learner) throws LessonServiceException - { + * If the supplied learner is not already in a group, then perform grouping for + * the learners who have started the lesson, based on the grouping activity. + * The grouper decides who goes in which group. + * + * Can only be run on a Random Grouping + * + * @param lessonId lesson id (mandatory) + * @param groupingActivity the activity that has create grouping. (mandatory) + * @param learner the learner to be check before grouping. (mandatory) + */ + public void performGrouping(Long lessonId, GroupingActivity groupingActivity, User learner) throws LessonServiceException { Grouping grouping = groupingActivity.getCreateGrouping(); - if ( grouping != null && grouping.isRandomGrouping() ) { + if (grouping != null && grouping.isRandomGrouping()) { // get the real objects, not the CGLIB version grouping = groupingDAO.getGroupingById(grouping.getGroupingId()); - Grouper grouper = grouping.getGrouper(); - - if ( grouper != null ) { - grouper.setCommonMessageService(messageService); - try { - if ( grouping.getGroups().size() == 0 ) { - // no grouping done yet - do everyone already in the lesson. - List usersInLesson = getActiveLessonLearners(lessonId); - grouper.doGrouping(grouping, (String)null, usersInLesson); - } else if ( ! grouping.doesLearnerExist(learner) ) { - // done the others, just do the one user - grouper.doGrouping(grouping, null, learner); - } - } catch ( GroupingException e ) { - throw new LessonServiceException(e); - } - groupingDAO.update(grouping); - } - - } else { - String error = "The method performGrouping supports only grouping methods where the grouper decides the groups (currently only RandomGrouping). Called with a groupingActivity with the wrong grouper "+groupingActivity.getActivityId(); - log.error(error); + Grouper grouper = grouping.getGrouper(); + + if (grouper != null) { + grouper.setCommonMessageService(messageService); + try { + if (grouping.getGroups().size() == 0) { + // no grouping done yet - do everyone already in the lesson. + List usersInLesson = getActiveLessonLearners(lessonId); + grouper.doGrouping(grouping, (String) null, usersInLesson); + } + else if (!grouping.doesLearnerExist(learner)) { + // done the others, just do the one user + grouper.doGrouping(grouping, null, learner); + } + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + groupingDAO.update(grouping); + } + + } + else { + String error = "The method performGrouping supports only grouping methods where the grouper decides the groups (currently only RandomGrouping). Called with a groupingActivity with the wrong grouper " + + groupingActivity.getActivityId(); + LessonService.log.error(error); throw new LessonServiceException(error); } - } + } /** - * Perform the grouping, setting the given list of learners as one group. - * @param groupingActivity the activity that has create grouping. (mandatory) - * @param groupName (optional) - * @param learners to form one group (mandatory) - */ - public void performGrouping(GroupingActivity groupingActivity, String groupName, List learners) throws LessonServiceException { - - Grouping grouping = groupingActivity.getCreateGrouping(); - performGrouping(grouping, groupName, learners); - } - + * Perform the grouping, setting the given list of learners as one group. + * @param groupingActivity the activity that has create grouping. (mandatory) + * @param groupName (optional) + * @param learners to form one group (mandatory) + */ + public void performGrouping(GroupingActivity groupingActivity, String groupName, List learners) throws LessonServiceException { + + Grouping grouping = groupingActivity.getCreateGrouping(); + performGrouping(grouping, groupName, learners); + } + /** - * Perform the grouping, setting the given list of learners as one group. Used in situations - * where there is a grouping but no grouping activity (e.g. in branching). - * @param groupingActivity the activity that has create grouping. (mandatory) - * @param groupName (optional) - * @param learners to form one group (mandatory) - */ - public void performGrouping(Grouping grouping, String groupName, List learners) throws LessonServiceException { - - if ( grouping != null ) { + * Perform the grouping, setting the given list of learners as one group. Used in situations + * where there is a grouping but no grouping activity (e.g. in branching). + * @param groupingActivity the activity that has create grouping. (mandatory) + * @param groupName (optional) + * @param learners to form one group (mandatory) + */ + public void performGrouping(Grouping grouping, String groupName, List learners) throws LessonServiceException { + + if (grouping != null) { // Ensure we have a real grouping object, not just a CGLIB version (LDEV-1817) grouping = groupingDAO.getGroupingById(grouping.getGroupingId()); - Grouper grouper = grouping.getGrouper(); - if ( grouper != null ) { - grouper.setCommonMessageService(messageService); - try { - grouper.doGrouping(grouping, groupName, learners); - } catch ( GroupingException e ) { - throw new LessonServiceException(e); - } - groupingDAO.update(grouping); - } + Grouper grouper = grouping.getGrouper(); + if (grouper != null) { + grouper.setCommonMessageService(messageService); + try { + grouper.doGrouping(grouping, groupName, learners); + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + groupingDAO.update(grouping); + } } - } - + } + /** - * Perform the grouping, setting the given list of learners as one group. Currently used for chosen grouping and - * teacher chosen branching, and for group based branching in preview (when the user selects a branch that would - * not be their normal branch). - * @param grouping The grouping that needs to have the grouping performed.. (mandatory) - * @param the id of the preferred group (optional) - * @param learners to form one group (mandatory) - */ - public void performGrouping(Grouping grouping, Long groupId, List learners) throws LessonServiceException { - if ( grouping != null ) { - Grouper grouper = grouping.getGrouper(); - if ( grouper != null ) { - grouper.setCommonMessageService(messageService); - try { - grouper.doGrouping(grouping, groupId, learners); - } catch ( GroupingException e ) { - throw new LessonServiceException(e); - } - groupingDAO.update(grouping); - } - } else { - String error = "The method performChosenGrouping supports only grouping methods where the supplied list should be used as a single group (currently only ChosenGrouping). Called with a grouping with the wrong grouper "+grouping; - log.error(error); + * Perform grouping for the given learner. + * + * @param grouping the object on which to perform the grouing. (mandatory) + * @param groupId group id (mandatory) + * @param learner learner to group (mandatory) + * @throws LessonServiceException + */ + public void performGrouping(Grouping grouping, Long groupId, User learner) throws LessonServiceException { + if (grouping != null) { + // Ensure we have a real grouping object, not just a CGLIB version (LDEV-1817) + grouping = groupingDAO.getGroupingById(grouping.getGroupingId()); + Grouper grouper = grouping.getGrouper(); + if (grouper != null) { + grouper.setCommonMessageService(messageService); + try { + List learners = new ArrayList(1); + learners.add(learner); + grouper.doGrouping(grouping, groupId, learners); + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + groupingDAO.update(grouping); + } + } + } + + /** + * Perform the grouping, setting the given list of learners as one group. Currently used for chosen grouping and + * teacher chosen branching, and for group based branching in preview (when the user selects a branch that would + * not be their normal branch). + * @param grouping The grouping that needs to have the grouping performed.. (mandatory) + * @param the id of the preferred group (optional) + * @param learners to form one group (mandatory) + */ + public void performGrouping(Grouping grouping, Long groupId, List learners) throws LessonServiceException { + if (grouping != null) { + Grouper grouper = grouping.getGrouper(); + if (grouper != null) { + grouper.setCommonMessageService(messageService); + try { + grouper.doGrouping(grouping, groupId, learners); + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + groupingDAO.update(grouping); + } + } + else { + String error = "The method performChosenGrouping supports only grouping methods where the supplied list should be used as a single group (currently only ChosenGrouping). Called with a grouping with the wrong grouper " + + grouping; + LessonService.log.error(error); throw new LessonServiceException(error); } - } + } /** - * Remove learners from the given group. - * @param grouping the grouping that contains the users to be removed (mandatory) - * @param groupID if not null only remove user from this group, if null remove learner from any group. - * @param learners the learners to be removed (mandatory) - */ - public void removeLearnersFromGroup(Grouping grouping, Long groupID, List learners) throws LessonServiceException - { - if ( grouping != null ) { + * Remove learners from the given group. + * @param grouping the grouping that contains the users to be removed (mandatory) + * @param groupID if not null only remove user from this group, if null remove learner from any group. + * @param learners the learners to be removed (mandatory) + */ + public void removeLearnersFromGroup(Grouping grouping, Long groupID, List learners) throws LessonServiceException { + if (grouping != null) { // get the real objects, not the CGLIB version grouping = groupingDAO.getGroupingById(grouping.getGroupingId()); - Grouper grouper = grouping.getGrouper(); - if ( grouper != null ) { - try { - grouper.removeLearnersFromGroup(grouping, groupID, learners); - } catch ( GroupingException e ) { - throw new LessonServiceException(e); - } - } - groupingDAO.update(grouping); + Grouper grouper = grouping.getGrouper(); + if (grouper != null) { + try { + grouper.removeLearnersFromGroup(grouping, groupID, learners); + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + } + groupingDAO.update(grouping); } - } + } - /** Create an empty group for the given grouping. Create an empty group for the given grouping. - * If the group name already exists then it will force the name to be unique. - * - * @param grouping the grouping. (mandatory) - * @param groupName (mandatory) - * @return the new group - */ - public Group createGroup(Grouping grouping, String name) throws LessonServiceException - { - Group newGroup = null; - if ( grouping != null ) { + /** Create an empty group for the given grouping. Create an empty group for the given grouping. + * If the group name already exists then it will force the name to be unique. + * + * @param grouping the grouping. (mandatory) + * @param groupName (mandatory) + * @return the new group + */ + public Group createGroup(Grouping grouping, String name) throws LessonServiceException { + Group newGroup = null; + if (grouping != null) { // get the real objects, not the CGLIB version grouping = groupingDAO.getGroupingById(grouping.getGroupingId()); - Grouper grouper = grouping.getGrouper(); - if ( grouper != null ) { - try { - newGroup = grouper.createGroup(grouping, name); - } catch ( GroupingException e ) { - throw new LessonServiceException(e); - } - } - groupingDAO.update(grouping); + Grouper grouper = grouping.getGrouper(); + if (grouper != null) { + try { + newGroup = grouper.createGroup(grouping, name); + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + } + groupingDAO.update(grouping); } return newGroup; } - /** - * Remove a group for the given grouping. If the group is already used (e.g. a tool session exists) - * then it throws a GroupingException. - * - * @param grouping the grouping that contains the group to be removed (mandatory) - * @param groupID (mandatory) - */ - public void removeGroup(Grouping grouping, Long groupID) throws LessonServiceException { - if ( grouping != null ) { + + /** + * Remove a group for the given grouping. If the group is already used (e.g. a tool session exists) + * then it throws a GroupingException. + * + * @param grouping the grouping that contains the group to be removed (mandatory) + * @param groupID (mandatory) + */ + public void removeGroup(Grouping grouping, Long groupID) throws LessonServiceException { + if (grouping != null) { // get the real objects, not the CGLIB version grouping = groupingDAO.getGroupingById(grouping.getGroupingId()); - Grouper grouper = grouping.getGrouper(); - if ( grouper != null ) { - try { - grouper.removeGroup(grouping, groupID); - } catch ( GroupingException e ) { - throw new LessonServiceException(e); - } - } - groupingDAO.update(grouping); + Grouper grouper = grouping.getGrouper(); + if (grouper != null) { + try { + grouper.removeGroup(grouping, groupID); + } + catch (GroupingException e) { + throw new LessonServiceException(e); + } + } + groupingDAO.update(grouping); } } - - /** - * Add a learner to the lesson class. Checks for duplicates. - * @param userId new learner id - * @return true if added user, returns false if the user already a learner and hence not added. - */ - public boolean addLearner(Long lessonId, Integer userId) throws LessonServiceException { + + /** + * Add a learner to the lesson class. Checks for duplicates. + * @param userId new learner id + * @return true if added user, returns false if the user already a learner and hence not added. + */ + 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."); + if (lesson == null) { + 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."); + if (lessonClass == null) { + 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 // from moodle. Should only be two groups - learner and staff // yes this is a bit of a hack! Group learnersGroup = lessonClass.getLearnersGroup(); - if ( learnersGroup != null ) + if (learnersGroup != null) { lessonDAO.initialize(learnersGroup); + } - User user = (User) baseDAO.find(User.class,userId); + User user = (User) baseDAO.find(User.class, userId); boolean ret = lessonClass.addLearner(user); - if ( ret ) { + if (ret) { lessonClassDAO.updateLessonClass(lessonClass); } return ret; - } + } - /** - * Add a set of learners to the lesson class. + /** + * Add a set of learners to the lesson class. * * If version of the method is designed to be called from Moodle or some other external system, * and is less efficient in that it has to look up the user from the user id. * If we don't do this, then we may get a a session closed issue if this code is called from the * LoginRequestValve (as the users will be from a previous session) * - * @param lessonId - * @param userIds array of new learner ids - */ - public void addLearners(Long lessonId, Integer[] userIds) throws LessonServiceException { - + * @param lessonId + * @param userIds array of new learner ids + */ + public void addLearners(Long lessonId, Integer[] userIds) throws LessonServiceException { + Lesson lesson = lessonDAO.getLesson(lessonId); - if ( lesson == null ) { - throw new LessonServiceException("Lesson "+lessonId+" does not exist. Unable to add learner to lesson."); + if (lesson == null) { + 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."); + if (lessonClass == null) { + 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 // when logging in from an external system. Should only be two groups - learner and staff // yes this is a bit of a hack! Group learnersGroup = lessonClass.getLearnersGroup(); - if ( learnersGroup != null ) + if (learnersGroup != null) { lessonDAO.initialize(learnersGroup); + } Set users = new HashSet(); - for ( Integer userId: userIds) { - User user = (User) baseDAO.find(User.class,userId); + for (Integer userId : userIds) { + User user = (User) baseDAO.find(User.class, userId); users.add(user); } addLearners(lesson, users); - } - - /** - * Add a set of learners to the lesson class. To be called within LAMS - see - * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. - * - * @param lesson lesson - * @param users the users to add as learners - */ - public void addLearners(Lesson lesson, Collection users) throws LessonServiceException { - - LessonClass lessonClass = lesson.getLessonClass(); - int numAdded = lessonClass.addLearners(users); - if ( numAdded > 0 ) { - lessonClassDAO.updateLessonClass(lessonClass); - } - if ( log.isDebugEnabled() ) { - log.debug("Added "+numAdded+" learners to lessonClass "+lessonClass.getGroupingId()); - } - } - - /** - * Add a new staff member to the lesson class. Checks for duplicates. - * @param userId new learner id - * @return true if added user, returns false if the user already a staff member and hence not added. - */ - public boolean addStaffMember(Long lessonId, Integer userId) { + } + + /** + * Add a set of learners to the lesson class. To be called within LAMS - see + * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. + * + * @param lesson lesson + * @param users the users to add as learners + */ + public void addLearners(Lesson lesson, Collection users) throws LessonServiceException { + + LessonClass lessonClass = lesson.getLessonClass(); + int numAdded = lessonClass.addLearners(users); + if (numAdded > 0) { + lessonClassDAO.updateLessonClass(lessonClass); + } + if (LessonService.log.isDebugEnabled()) { + LessonService.log.debug("Added " + numAdded + " learners to lessonClass " + lessonClass.getGroupingId()); + } + } + + /** + * Add a new staff member to the lesson class. Checks for duplicates. + * @param userId new learner id + * @return true if added user, returns false if the user already a staff member and hence not added. + */ + 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."); + if (lesson == null) { + 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."); + + if (lessonClass == null) { + throw new LessonServiceException("Lesson class for " + lessonId + + " does not exist. Unable to add staff member to lesson."); } - + lessonDAO.initialize(lessonClass.getStaffGroup()); - User user = (User) baseDAO.find(User.class,userId); + User user = (User) baseDAO.find(User.class, userId); boolean ret = lessonClass.addStaffMember(user); - if ( ret ) { + if (ret) { lessonClassDAO.updateLessonClass(lessonClass); } return ret; - } + } - /** - * Add a set of staff to the lesson class. + /** + * Add a set of staff to the lesson class. * * If version of the method is designed to be called from Moodle or some other external system, * and is less efficient in that it has to look up the user from the user id. * If we don't do this, then we may get a a session closed issue if this code is called from the * LoginRequestValve (as the users will be from a previous session) * - * @param lessonId - * @param userIds array of new staff ids - */ - public void addStaffMembers(Long lessonId, Integer[] userIds) throws LessonServiceException { - + * @param lessonId + * @param userIds array of new staff ids + */ + public void addStaffMembers(Long lessonId, Integer[] userIds) throws LessonServiceException { + Lesson lesson = lessonDAO.getLesson(lessonId); - if ( lesson == null ) { - throw new LessonServiceException("Lesson "+lessonId+" does not exist. Unable to add learner to lesson."); + if (lesson == null) { + 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."); + if (lessonClass == null) { + 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 @@ -493,199 +525,198 @@ lessonDAO.initialize(lessonClass.getStaffGroup()); Set users = new HashSet(); - for ( Integer userId: userIds) { - User user = (User) baseDAO.find(User.class,userId); + for (Integer userId : userIds) { + User user = (User) baseDAO.find(User.class, userId); users.add(user); } addStaffMembers(lesson, users); - } - - /** - * Add a set of staff members to the lesson class. To be called within LAMS - see - * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. - * - * @param lesson lesson - * @param users the users to add as learners - */ - public void addStaffMembers(Lesson lesson, Collection users) throws LessonServiceException { - - LessonClass lessonClass = lesson.getLessonClass(); - int numAdded = lessonClass.addStaffMembers(users); - if ( numAdded > 0 ) { - lessonClassDAO.updateLessonClass(lessonClass); + } + + /** + * Add a set of staff members to the lesson class. To be called within LAMS - see + * addLearners(Long lessonId, Integer[] userIds) if calling from an external system. + * + * @param lesson lesson + * @param users the users to add as learners + */ + public void addStaffMembers(Lesson lesson, Collection users) throws LessonServiceException { + + LessonClass lessonClass = lesson.getLessonClass(); + int numAdded = lessonClass.addStaffMembers(users); + if (numAdded > 0) { + lessonClassDAO.updateLessonClass(lessonClass); + } + if (LessonService.log.isDebugEnabled()) { + LessonService.log.debug("Added " + numAdded + " staff members to lessonClass " + lessonClass.getGroupingId()); + } + } + + /** + * Remove references to an activity from all learner progress entries. + * Used by Live Edit, to remove any references to the system gates + * @param activity The activity for which learner progress references should be removed. + */ + public void removeProgressReferencesToActivity(Activity activity) throws LessonServiceException { + if (activity != null) { + LessonService.log.debug("Processing learner progress for activity " + activity.getActivityId()); + + List progresses = learnerProgressDAO.getLearnerProgressReferringToActivity(activity); + if (progresses != null && progresses.size() > 0) { + Iterator iter = progresses.iterator(); + while (iter.hasNext()) { + LearnerProgress progress = (LearnerProgress) iter.next(); + if (removeActivityReference(activity, progress)) { + ; + } + learnerProgressDAO.updateLearnerProgress(progress); + } } - if ( log.isDebugEnabled() ) { - log.debug("Added "+numAdded+" staff members to lessonClass "+lessonClass.getGroupingId()); - } - } - - /** - * Remove references to an activity from all learner progress entries. - * Used by Live Edit, to remove any references to the system gates - * @param activity The activity for which learner progress references should be removed. - */ - public void removeProgressReferencesToActivity(Activity activity) throws LessonServiceException { - if ( activity != null ) { - log.debug("Processing learner progress for activity "+activity.getActivityId()); + } + } - List progresses = learnerProgressDAO.getLearnerProgressReferringToActivity(activity); - if ( progresses != null && progresses.size()>0) { - Iterator iter = progresses.iterator(); - while ( iter.hasNext() ) { - LearnerProgress progress = (LearnerProgress) iter.next(); - if ( removeActivityReference(activity, progress) ); - learnerProgressDAO.updateLearnerProgress(progress); - } - } - } - } + private boolean removeActivityReference(Activity activity, LearnerProgress progress) { - private boolean removeActivityReference(Activity activity, LearnerProgress progress) { - - if ( log.isDebugEnabled() ) { - log.debug("Processing learner progress learner "+progress.getUser().getUserId()); - } - - boolean recordUpdated = false; - - boolean removed = progress.getAttemptedActivities().remove(activity); - if ( removed ) { - recordUpdated = true; - log.debug("Removed activity from attempted activities"); - } - - removed = progress.getCompletedActivities().remove(activity); - if ( removed ) { - recordUpdated = true; - log.debug("Removed activity from completed activities"); - } - - if ( progress.getCurrentActivity() != null && progress.getCurrentActivity().equals(activity) ) { - progress.setCurrentActivity(null); - recordUpdated = true; - log.debug("Removed activity as current activity"); - } - - if ( progress.getNextActivity() != null && progress.getNextActivity().equals(activity) ) { - progress.setNextActivity(null); - recordUpdated = true; - log.debug("Removed activity as next activity"); - } - - if ( progress.getPreviousActivity() != null && progress.getPreviousActivity().equals(activity) ) { - progress.setPreviousActivity(null); - recordUpdated = true; - log.debug("Removed activity as previous activity"); - } - - return recordUpdated; - } + if (LessonService.log.isDebugEnabled()) { + LessonService.log.debug("Processing learner progress learner " + progress.getUser().getUserId()); + } - /** - * Mark any learner progresses for this lesson as not completed. Called when Live Edit - * ends, to ensure that if there were any completed progress records, and the design - * was extended, then they are no longer marked as completed. - * @param lessonId The lesson for which learner progress entries should be updated. - */ - public void performMarkLessonUncompleted(Long lessonId) throws LessonServiceException { - int count = 0; - if ( lessonId != null ) { - log.debug("Setting learner progress to uncompleted for lesson "+lessonId); + boolean recordUpdated = false; - List progresses = learnerProgressDAO.getCompletedLearnerProgressForLesson(lessonId); - if ( progresses != null && progresses.size()>0) { - Iterator iter = progresses.iterator(); - while ( iter.hasNext() ) { - LearnerProgress progress = (LearnerProgress) iter.next(); - if ( progress.getLessonComplete() == LearnerProgress.LESSON_END_OF_DESIGN_COMPLETE ) - progress.setLessonComplete(LearnerProgress.LESSON_NOT_COMPLETE); - count++; - } - } - } - if ( log.isDebugEnabled() ) - log.debug("Reset completed flag for "+count+" learners for lesson "+lessonId); - } + boolean removed = progress.getAttemptedActivities().remove(activity); + if (removed) { + recordUpdated = true; + LessonService.log.debug("Removed activity from attempted activities"); + } - /** - * Get the list of users who have attempted 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. - */ - public List getLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException { - return learnerProgressDAO.getLearnersHaveAttemptedActivity(activity); + removed = progress.getCompletedActivities().remove(activity); + if (removed) { + recordUpdated = true; + LessonService.log.debug("Removed activity from completed activities"); } - /** - * 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. - */ - public List getLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException { - return learnerProgressDAO.getLearnersHaveCompletedActivity(activity); + if (progress.getCurrentActivity() != null && progress.getCurrentActivity().equals(activity)) { + progress.setCurrentActivity(null); + recordUpdated = true; + LessonService.log.debug("Removed activity as current activity"); } - - /** - * 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. - */ - public Integer getCountLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException { - return learnerProgressDAO.getNumUsersAttemptedActivity(activity); + if (progress.getNextActivity() != null && progress.getNextActivity().equals(activity)) { + progress.setNextActivity(null); + recordUpdated = true; + LessonService.log.debug("Removed activity as next activity"); } - /** - * 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. - */ - public Integer getCountLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException { - return learnerProgressDAO.getNumUsersCompletedActivity(activity); + if (progress.getPreviousActivity() != null && progress.getPreviousActivity().equals(activity)) { + progress.setPreviousActivity(null); + recordUpdated = true; + LessonService.log.debug("Removed activity as previous activity"); } - - public Map getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, boolean isStaff) { - TreeMap map = new TreeMap(); - List list = this.lessonDAO.getLessonsByOrgAndUserWithCompletedFlag(userId, orgId, isStaff); - if (list != null) { - Iterator iterator = list.iterator(); - while (iterator.hasNext()) { - Object[] tuple = (Object[])iterator.next(); - Long lessonId = (Long)tuple[0]; - String lessonName = (String)tuple[1]; - String lessonDescription = (String)tuple[2]; - Integer lessonState = (Integer)tuple[3]; - Boolean lessonCompleted = (Boolean)tuple[4]; - IndexLessonBean bean = new IndexLessonBean( - lessonId, lessonName, lessonDescription, lessonState, ( - lessonCompleted == null ? false : lessonCompleted.booleanValue() - ) - ); - map.put(new Long(lessonId), bean); - } - } - return map; - } - - - /** - * Gets the learner's progress details for a particular lesson. Will return null if the user - * has not started the lesson. - * - * @param learnerId user's id - * @param lessonId lesson's id - * @return learner's progress or null - */ - public LearnerProgress getUserProgressForLesson(Integer learnerId, Long lessonId) { - return learnerProgressDAO.getLearnerProgressByLearner(learnerId,lessonId); - } - - /** - * Gets list of lessons which are originally based on the given learning design id. - */ - public List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId) { - return this.lessonDAO.getLessonsByOriginalLearningDesign(ldId, orgId); + + return recordUpdated; + } + + /** + * Mark any learner progresses for this lesson as not completed. Called when Live Edit + * ends, to ensure that if there were any completed progress records, and the design + * was extended, then they are no longer marked as completed. + * @param lessonId The lesson for which learner progress entries should be updated. + */ + public void performMarkLessonUncompleted(Long lessonId) throws LessonServiceException { + int count = 0; + if (lessonId != null) { + LessonService.log.debug("Setting learner progress to uncompleted for lesson " + lessonId); + + List progresses = learnerProgressDAO.getCompletedLearnerProgressForLesson(lessonId); + if (progresses != null && progresses.size() > 0) { + Iterator iter = progresses.iterator(); + while (iter.hasNext()) { + LearnerProgress progress = (LearnerProgress) iter.next(); + if (progress.getLessonComplete() == LearnerProgress.LESSON_END_OF_DESIGN_COMPLETE) { + progress.setLessonComplete(LearnerProgress.LESSON_NOT_COMPLETE); + } + count++; + } + } } + if (LessonService.log.isDebugEnabled()) { + LessonService.log.debug("Reset completed flag for " + count + " learners for lesson " + lessonId); + } + } + + /** + * Get the list of users who have attempted 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. + */ + public List getLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException { + return learnerProgressDAO.getLearnersHaveAttemptedActivity(activity); + } + + /** + * 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. + */ + public List getLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException { + return learnerProgressDAO.getLearnersHaveCompletedActivity(activity); + } + + /** + * 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. + */ + public Integer getCountLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException { + return learnerProgressDAO.getNumUsersAttemptedActivity(activity); + } + + /** + * 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. + */ + public Integer getCountLearnersHaveCompletedActivity(Activity activity) throws LessonServiceException { + return learnerProgressDAO.getNumUsersCompletedActivity(activity); + } + + public Map getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, boolean isStaff) { + TreeMap map = new TreeMap(); + List list = lessonDAO.getLessonsByOrgAndUserWithCompletedFlag(userId, orgId, isStaff); + if (list != null) { + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + Object[] tuple = (Object[]) iterator.next(); + Long lessonId = (Long) tuple[0]; + String lessonName = (String) tuple[1]; + String lessonDescription = (String) tuple[2]; + Integer lessonState = (Integer) tuple[3]; + Boolean lessonCompleted = (Boolean) tuple[4]; + IndexLessonBean bean = new IndexLessonBean(lessonId, lessonName, lessonDescription, lessonState, + (lessonCompleted == null ? false : lessonCompleted.booleanValue())); + map.put(new Long(lessonId), bean); + } + } + return map; + } + + /** + * Gets the learner's progress details for a particular lesson. Will return null if the user + * has not started the lesson. + * + * @param learnerId user's id + * @param lessonId lesson's id + * @return learner's progress or null + */ + public LearnerProgress getUserProgressForLesson(Integer learnerId, Long lessonId) { + return learnerProgressDAO.getLearnerProgressByLearner(learnerId, lessonId); + } + + /** + * Gets list of lessons which are originally based on the given learning design id. + */ + public List getLessonsByOriginalLearningDesign(Long ldId, Integer orgId) { + return lessonDAO.getLessonsByOriginalLearningDesign(ldId, orgId); + } } Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXTAGS.java =================================================================== diff -u -r40fd34ca6bc3ae5e5466f8c9a17047427f9cd43b -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXTAGS.java (.../WDDXTAGS.java) (revision 40fd34ca6bc3ae5e5466f8c9a17047427f9cd43b) +++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXTAGS.java (.../WDDXTAGS.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -25,14 +25,12 @@ import java.util.Date; - - /** * @author Manpreet Minhas * The tags used in WDDX Packet */ public interface WDDXTAGS { - + /** The string value in a WDDX packet that indicates that this value is really null */ public static final String STRING_NULL_VALUE = "string_null_value"; /** The Boolean value in a WDDX packet that indicates that this value is really null. @@ -52,151 +50,149 @@ public static final Double NUMERIC_NULL_VALUE_DOUBLE = new Double(-111111); /** The Date value in a WDDX packet that indicates that this value is really null.*/ public static final Date DATE_NULL_VALUE = new Date(0); - + /* General Tags */ public static final String OBJECT_TYPE = "objectType"; //not used in 1.1 - + public static final String DESCRIPTION = "description"; public static final String TITLE = "title"; - public static final String HELP_TEXT ="helpText"; - public static final String XCOORD="xCoord"; - public static final String YCOORD="yCoord"; - public static final String GROUPINGS ="groupings"; - public static final String TRANSITIONS ="transitions"; - public static final String ACTIVITIES ="activities"; + public static final String HELP_TEXT = "helpText"; + public static final String XCOORD = "xCoord"; + public static final String YCOORD = "yCoord"; + public static final String GROUPINGS = "groupings"; + public static final String TRANSITIONS = "transitions"; + public static final String ACTIVITIES = "activities"; public static final String BRANCH_MAPPINGS = "branchMappings"; - + /*Learning Library specific tags */ - public static final String LEARNING_LIBRARY_ID ="learningLibraryID"; - public static final String LIB_ACTIVITIES="templateActivities"; + public static final String LEARNING_LIBRARY_ID = "learningLibraryID"; + public static final String LIB_ACTIVITIES = "templateActivities"; public static final String LIB_PACKAGE = "libraries"; - public static final String DESIGN_PACKAGE ="designs"; - + public static final String DESIGN_PACKAGE = "designs"; + /*Activity specific tags*/ - public static final String ACTIVITY_ID ="activityID"; - public static final String ACTIVITY_UIID ="activityUIID"; + public static final String ACTIVITY_ID = "activityID"; + public static final String ACTIVITY_UIID = "activityUIID"; public static final String ACTIVITY_TITLE = "activityTitle"; - - public static final String PARENT_ACTIVITY_ID ="parentActivityID"; - public static final String PARENT_UIID ="parentUIID"; - - public static final String ACTIVITY_TYPE_ID ="activityTypeID"; - public static final String ORDER_ID ="orderID"; - + + public static final String PARENT_ACTIVITY_ID = "parentActivityID"; + public static final String PARENT_UIID = "parentUIID"; + + public static final String ACTIVITY_TYPE_ID = "activityTypeID"; + public static final String ORDER_ID = "orderID"; + public static final String ACTIVITY_CATEGORY_ID = "activityCategoryID"; - - public static final String DEFINE_LATER ="defineLater"; - public static final String RUN_OFFLINE ="runOffline"; - public static final String OFFLINE_INSTRUCTIONS ="offlineInstructions"; + + public static final String DEFINE_LATER = "defineLater"; + public static final String RUN_OFFLINE = "runOffline"; + public static final String OFFLINE_INSTRUCTIONS = "offlineInstructions"; public static final String ONLINE_INSTRUCTIONS = "onlineInstructions"; - public static final String LIBRARY_IMAGE ="libraryActivityUIImage"; - public static final String LIBRARY_ACTIVITY ="libraryActivityID"; - + public static final String LIBRARY_IMAGE = "libraryActivityUIImage"; + public static final String LIBRARY_ACTIVITY = "libraryActivityID"; + public static final String APPLY_GROUPING = "applyGrouping"; public static final String GROUPING_SUPPORT_TYPE = "groupingSupportType"; public static final String STOP_AFTER_ACTIVITY = "stopAfterActivity"; public static final String INPUT_ACTIVITIES = "inputActivities"; // not used yet public static final String INPUT_TOOL_ACTIVITY_UIID = "toolActivityUIID"; - + /** OptionsActivity specific tags*/ - public static final String MAX_OPTIONS="maxOptions"; - public static final String MIN_OPTIONS="minOptions"; - public static final String OPTIONS_INSTRUCTIONS ="optionsInstructions"; - + public static final String MAX_OPTIONS = "maxOptions"; + public static final String MIN_OPTIONS = "minOptions"; + public static final String OPTIONS_INSTRUCTIONS = "optionsInstructions"; + /** ToolActivity specific tags*/ - public static final String TOOL_ID="toolID"; - public static final String TOOL_CONTENT_ID="toolContentID"; - public static final String TOOL_CONTENT_IDS="toolContentIDs"; - - /** GateActivity specific tags*/ - public static final String GATE_ACTIVITY_LEVEL_ID ="gateActivityLevelID"; - public static final String GATE_START_DATE ="gateStartDateTime"; - public static final String GATE_END_DATE ="gateEndDateTime"; - public static final String GATE_START_OFFSET="gateStartTimeOffset"; - public static final String GATE_END_OFFSET="gateEndTimeOffset"; - public static final String GATE_OPEN ="gateOpen"; - + public static final String TOOL_ID = "toolID"; + public static final String TOOL_CONTENT_ID = "toolContentID"; + public static final String TOOL_CONTENT_IDS = "toolContentIDs"; + + /** GateActivity specific tags*/ + public static final String GATE_ACTIVITY_LEVEL_ID = "gateActivityLevelID"; + public static final String GATE_START_DATE = "gateStartDateTime"; + public static final String GATE_END_DATE = "gateEndDateTime"; + public static final String GATE_START_OFFSET = "gateStartTimeOffset"; + public static final String GATE_END_OFFSET = "gateEndTimeOffset"; + public static final String GATE_OPEN = "gateOpen"; + /** Grouping Activity specific tags */ - public static final String CREATE_GROUPING_ID ="createGroupingID"; - public static final String CREATE_GROUPING_UIID ="createGroupingUIID"; - + public static final String CREATE_GROUPING_ID = "createGroupingID"; + public static final String CREATE_GROUPING_UIID = "createGroupingUIID"; + /** Grouping specific tags */ - public static final String GROUPING_ID ="groupingID"; - public static final String GROUPING_UIID ="groupingUIID"; - public static final String GROUPING_TYPE_ID ="groupingTypeID"; - public static final String LEARNERS_PER_GROUP ="learnersPerGroup"; - public static final String MAX_NUMBER_OF_GROUPS ="maxNumberOfGroups"; - public static final String NUMBER_OF_GROUPS ="numberOfGroups"; + public static final String GROUPING_ID = "groupingID"; + public static final String GROUPING_UIID = "groupingUIID"; + public static final String GROUPING_TYPE_ID = "groupingTypeID"; + public static final String LEARNERS_PER_GROUP = "learnersPerGroup"; + public static final String EQUAL_NUMBER_OF_LEARNERS_PER_GROUP = "equalNumberOfLearnersPerGroup"; + public static final String MAX_NUMBER_OF_GROUPS = "maxNumberOfGroups"; + public static final String NUMBER_OF_GROUPS = "numberOfGroups"; public static final String STAFF_GROUP_ID = "staffGroupID"; public static final String GROUPING_DTO = "groupingDTO"; public static final String GROUPS = "groups"; - + public static final String GROUP_ID = "groupID"; public static final String GROUP_NAME = "groupName"; public static final String GROUP_USER_LIST = "userList"; public static final String GROUP_UIID = "groupUIID"; /** Transition specific tags */ - public static final String TRANSITION_ID ="transitionID"; - public static final String TRANSITION_UIID ="transitionUIID"; - public static final String TRANSITION_TO="to_activity_id"; - public static final String TRANSITION_FROM="from_activity_id"; - public static final String TO_ACTIVITY_UIID ="toUIID"; - public static final String FROM_ACTIVITY_UIID ="fromUIID"; - - + public static final String TRANSITION_ID = "transitionID"; + public static final String TRANSITION_UIID = "transitionUIID"; + public static final String TRANSITION_TO = "to_activity_id"; + public static final String TRANSITION_FROM = "from_activity_id"; + public static final String TO_ACTIVITY_UIID = "toUIID"; + public static final String FROM_ACTIVITY_UIID = "fromUIID"; + /** Tool Specific tags */ - public static final String TOOL_DISPLAY_NAME ="displayName"; - public static final String TOOl_AUTH_URL ="toolAuthoringURL"; - public static final String AUTH_URL ="authoringURLS"; - - - + public static final String TOOL_DISPLAY_NAME = "displayName"; + public static final String TOOl_AUTH_URL = "toolAuthoringURL"; + public static final String AUTH_URL = "authoringURLS"; + /** LearningDesign specific tags*/ - public static final String LEARNING_DESIGN_ID="learningDesignID"; - public static final String LEARNING_DESIGN_UIID="learningDesignUIID"; - public static final String FIRST_ACTIVITY_ID ="firstActivityID"; - public static final String FIRST_ACTIVITY_UIID ="firstActivityUIID"; - - public static final String MAX_ID ="maxID"; - public static final String VALID_DESIGN ="validDesign"; - public static final String READ_ONLY ="readOnly"; - public static final String EDIT_OVERRIDE_LOCK ="editOverrideLock"; - public static final String DATE_READ_ONLY ="dateReadOnly"; - public static final String USER_ID="userID"; - public static final String EDIT_OVERRIDE_USER_ID="editOverrideUserID"; - - public static final String COPY_TYPE="copyTypeID"; - public static final String CREATION_DATE ="createDateTime"; + public static final String LEARNING_DESIGN_ID = "learningDesignID"; + public static final String LEARNING_DESIGN_UIID = "learningDesignUIID"; + public static final String FIRST_ACTIVITY_ID = "firstActivityID"; + public static final String FIRST_ACTIVITY_UIID = "firstActivityUIID"; + + public static final String MAX_ID = "maxID"; + public static final String VALID_DESIGN = "validDesign"; + public static final String READ_ONLY = "readOnly"; + public static final String EDIT_OVERRIDE_LOCK = "editOverrideLock"; + public static final String DATE_READ_ONLY = "dateReadOnly"; + public static final String USER_ID = "userID"; + public static final String EDIT_OVERRIDE_USER_ID = "editOverrideUserID"; + + public static final String COPY_TYPE = "copyTypeID"; + public static final String CREATION_DATE = "createDateTime"; public static final String LAST_MODIFIED_DATE = "lastModifiedDateTime"; - public static final String VERSION="version"; - public static final String ORIGINAL_DESIGN_ID ="originalLearningDesignID"; - public static final String WORKSPACE_FOLDER_ID= "workspaceFolderID"; - public static final String DURATION ="duration"; - public static final String LICENCE_ID ="licenseID"; - public static final String LICENSE_TEXT ="licenseText"; + public static final String VERSION = "version"; + public static final String ORIGINAL_DESIGN_ID = "originalLearningDesignID"; + public static final String WORKSPACE_FOLDER_ID = "workspaceFolderID"; + public static final String DURATION = "duration"; + public static final String LICENCE_ID = "licenseID"; + public static final String LICENSE_TEXT = "licenseText"; public static final String CONTENT_FOLDER_ID = "contentFolderID"; public static final String SAVE_MODE = "saveMode"; - + /**ComplexActivity specific tags */ - public static final String CHILD_ACTIVITIES ="childActivities"; - public static final String DEFAULT_ACTIVITY_UIID ="defaultActivityUIID"; - + public static final String CHILD_ACTIVITIES = "childActivities"; + public static final String DEFAULT_ACTIVITY_UIID = "defaultActivityUIID"; + /** Crash Dump Specific Tags */ - public static final String CRASH_DUMP_BATCH="crashDataBatch"; - + public static final String CRASH_DUMP_BATCH = "crashDataBatch"; + /** Notebook Specific Tags */ public static final String EXTERNAL_ID = "externalID"; public static final String EXTERNAL_ID_TYPE = "externalIDType"; public static final String EXTERNAL_SIG = "externalSignature"; public static final String ENTRY = "entry"; - + /** Branching Activity Specific Tags */ - public static final String START_XCOORD="startXCoord"; - public static final String START_YCOORD="startYCoord"; - public static final String END_XCOORD="endXCoord"; - public static final String END_YCOORD="endYCoord"; - + public static final String START_XCOORD = "startXCoord"; + public static final String START_YCOORD = "startYCoord"; + public static final String END_XCOORD = "endXCoord"; + public static final String END_YCOORD = "endYCoord"; + /** Branch Mapping and Tool Condition Tags */ public static final String BRANCH_ACTIVITY_ENTRY_ID = "entryID"; public static final String BRANCH_ACTIVITY_ENTRY_UIID = "entryUIID"; @@ -205,7 +201,7 @@ public static final String BRANCH_CONDITION = "condition"; // reuse GROUP_UIID for the Group field public static final String CONDITION_ID = "conditionID"; - public static final String CONDITION_UIID = "conditionUIID"; + public static final String CONDITION_UIID = "conditionUIID"; // reuse ORDER_ID for the OrderId field public static final String CONDITION_NAME = "name"; public static final String CONDITION_DISPLAY_NAME = "displayName"; @@ -215,10 +211,10 @@ public static final String CONDITION_EXACT_MATCH_VALUE = "exactMatchValue"; /** LD Import specific tags */ - public static final String LEARNING_DESIGN_TO_IMPORT_ID="learningDesignIDToImport"; - public static final String CREATE_NEW_LEARNING_DESIGN="createNewLearningDesign"; - + public static final String LEARNING_DESIGN_TO_IMPORT_ID = "learningDesignIDToImport"; + public static final String CREATE_NEW_LEARNING_DESIGN = "createNewLearningDesign"; + /** Tool adapters specific tags*/ - public static final String CUSTOM_CSV="customCSV"; - + public static final String CUSTOM_CSV = "customCSV"; + } Index: lams_learning/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r96fe21d3195f7b3ea8932e17caf8dba065cd12bd -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 96fe21d3195f7b3ea8932e17caf8dba065cd12bd) +++ lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -30,6 +30,8 @@ label.gate.refresh.message =Click Next if you are told that the gate is open. This page will refresh automatically in 1 minute. label.gate.preview.message =As this is a preview, clicking Next will go to the next activity. Normally the learner would have to wait until the gate is opened. label.view.groups.title =Groups +label.learner.choice.group.message =Please select a group. Some groups may not be available if they reached the maximum number of members. +label.learner.choice.group.full =Group full label.view.view.groups.wait.message =Some of your following tasks require a group. You cannot continue until the groups have been selected. Click Next if you are told that the groups have been created. This page will refresh automatically in 5 minutes. label.grouping.preview.message =As this is a preview, clicking Next will do an automatic grouping. Normally the learner would have to wait until the grouping is done. error.export.portfolio.not.supported =The activity {0} does not support portfolio export. @@ -91,5 +93,5 @@ label.preview.definelater.branching.message =The next activity ({0}) is set to define in monitor. Normally a staff member would configure the branches in monitoring. For the purposes of preview, you will be able to select which branch to preview. label.optional.maxActivitiesReached =The maximum number optional activities has already been reached. label.optional.maxSequencesReached =The maximum number optional sequences has already been reached. - +label.choose.group.button =Choose #======= End labels: Exported 83 labels for en AU ===== Index: lams_learning/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r96fe21d3195f7b3ea8932e17caf8dba065cd12bd -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 96fe21d3195f7b3ea8932e17caf8dba065cd12bd) +++ lams_learning/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -30,6 +30,8 @@ label.gate.refresh.message =Click Next if you are told that the gate is open. This page will refresh automatically in 1 minute. label.gate.preview.message =As this is a preview, clicking Next will go to the next activity. Normally the learner would have to wait until the gate is opened. label.view.groups.title =Groups +label.learner.choice.group.message =Please select a group. Some groups may not be available if they reached the maximum number of members. +label.learner.choice.group.full =Group full label.view.view.groups.wait.message =Some of your following tasks require a group. You cannot continue until the groups have been selected. Click Next if you are told that the groups have been created. This page will refresh automatically in 5 minutes. label.grouping.preview.message =As this is a preview, clicking Next will do an automatic grouping. Normally the learner would have to wait until the grouping is done. error.export.portfolio.not.supported =The activity {0} does not support portfolio export. @@ -91,5 +93,5 @@ label.preview.definelater.branching.message =The next activity ({0}) is set to define in monitor. Normally a staff member would configure the branches in monitoring. For the purposes of preview, you will be able to select which branch to preview. label.optional.maxActivitiesReached =The maximum number optional activities has already been reached. label.optional.maxSequencesReached =The maximum number optional sequences has already been reached. - +label.choose.group.button =Choose #======= End labels: Exported 83 labels for en AU ===== Index: lams_learning/src/java/org/lamsfoundation/lams/learning/learningApplicationContext.xml =================================================================== diff -u -r560c00149837e66be2b9f4cbcbff95ff23a4dc28 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/src/java/org/lamsfoundation/lams/learning/learningApplicationContext.xml (.../learningApplicationContext.xml) (revision 560c00149837e66be2b9f4cbcbff95ff23a4dc28) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/learningApplicationContext.xml (.../learningApplicationContext.xml) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -49,7 +49,8 @@ PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED - PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java =================================================================== diff -u -rfdca3605f0b782b19e214abbe94df6f4a457b88e -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java (.../ICoreLearnerService.java) (revision fdca3605f0b782b19e214abbe94df6f4a457b88e) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/ICoreLearnerService.java (.../ICoreLearnerService.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -21,12 +21,11 @@ * **************************************************************** */ -/* $Id$ */ +/* $Id$ */ package org.lamsfoundation.lams.learning.service; 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; @@ -40,266 +39,284 @@ import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.MessageService; + /** * * All Learner service methods that are available within the core. These methods may require * all the tool's Spring context files to be loaded, in addition to the core Spring context files. * Hence it should only be used from lams-learning, lams-monitoring, lams-central wars. */ -public interface ICoreLearnerService extends ILearnerService -{ +public interface ICoreLearnerService extends ILearnerService { /** Get the I18N service. Used by actions for internationalising errors that go back to Flash */ - public MessageService getMessageService(); + public MessageService getMessageService(); /** Get the user service. Used when the action needs the real user object, not just the userId */ - public IUserManagementService getUserManagementService(); - - /** - * Gets the lesson object for the given key. - * - */ - public Lesson getLesson(Long lessonID); + public IUserManagementService getUserManagementService(); - /** - * Get the lesson data for a particular lesson. In a DTO format suitable for sending to the client. - */ - public LessonDTO getLessonData(Long lessonId); + /** + * Gets the lesson object for the given key. + * + */ + public Lesson getLesson(Long lessonID); - - /** - * Joins a User to a a new lesson as a learner - * @param learnerId the Learner's userID - * @param lessionID identifies the Lesson to start - * @throws LearnerServiceException in case of problems. - */ - public LearnerProgress joinLesson(Integer learnerId, Long lessonID) ; - - /** - * This method navigate through all the tool activities for the given - * activity. For each tool activity, we look up the database - * to check up the existance of correspondent tool session. If the tool - * session doesn't exist, we create a new tool session instance. - * - * @param learnerProgress the learner progress we are processing. - * @throws LamsToolServiceException - */ - public void createToolSessionsIfNecessary(Activity activity, LearnerProgress learnerProgress); - - /** - * Returns the current progress data of the User. - * @param learnerId the Learner's userID - * @param lessonId the Lesson to get progress from. - * @return LearnerProgess contains the learner's progress for the lesson. - * @throws LearnerServiceException in case of problems. - */ - public LearnerProgress getProgress(Integer learnerId, Long lessonId); - - /** - * Returns the current progress data, in the DTO format required by the jsp progress screen, of the User. - * @param learnerId the Learner's userID - * @param lessonId the Lesson to get progress from. - * @return Array of two objects. [0] List, [1] Activity ID of the current activity - * @throws LearnerServiceException in case of problems. - */ - public Object[] getStructuredActivityURLs(Integer learnerId, Long lessonId); - + /** + * Get the lesson data for a particular lesson. In a DTO format suitable for sending to the client. + */ + public LessonDTO getLessonData(Long lessonId); - /** - * Return the current progress data against progress id. - * @param progressId - * @return - */ - public LearnerProgress getProgressById(Long progressId); - - /** - * Return the current progress data for a user for a lesson - * Returns a DTO suitable to send to Flash. - * @param lesson id - * @param learner id - * @return - */ - public LearnerProgressDTO getProgressDTOByLessonId(Long lessonId, Integer learnerId); + /** + * Joins a User to a a new lesson as a learner + * @param learnerId the Learner's userID + * @param lessionID identifies the Lesson to start + * @throws LearnerServiceException in case of problems. + */ + public LearnerProgress joinLesson(Integer learnerId, Long lessonID); - /** - * Marks an activity as attempted. Called when a user selects an OptionsActivity. - * @param learnerId the Learner's userID - * @param lessonId the Lesson to get progress from. - * @param activity the activity being attempted. - * @param clearCompletedFlag If the lesson is completed but this activity is unstarted, should we mark it as incomplete? Used for branching and - * optional sequences for skipped sequences (e.g. force completed branching) - * @return LearnerProgress - */ - public LearnerProgress chooseActivity(Integer learnerId, Long lessonId, Activity activity, Boolean clearCompletedFlag); + /** + * This method navigate through all the tool activities for the given + * activity. For each tool activity, we look up the database + * to check up the existance of correspondent tool session. If the tool + * session doesn't exist, we create a new tool session instance. + * + * @param learnerProgress the learner progress we are processing. + * @throws LamsToolServiceException + */ + public void createToolSessionsIfNecessary(Activity activity, LearnerProgress learnerProgress); - - /** - * Calculates learner progress and returns the data required to be displayed to the learner (including URL(s)). - * This method is included in the interface for testing purposes. - * - * @param completedActivityID identifies the activity just completed - * @param learner the Learner - * @return the bean containing the display data for the Learner - * @throws LearnerServiceException in case of problems. - */ - public LearnerProgress calculateProgress(Activity completedActivity, Integer learnerId, LearnerProgress currentLearnerProgress); + /** + * Returns the current progress data of the User. + * @param learnerId the Learner's userID + * @param lessonId the Lesson to get progress from. + * @return LearnerProgess contains the learner's progress for the lesson. + * @throws LearnerServiceException in case of problems. + */ + public LearnerProgress getProgress(Integer learnerId, Long lessonId); - /** - * Complete the activity in the progress engine and delegate to the progress - * engine to calculate the next activity in the learning design. - * It is currently triggered by various progress engine related action classes, - * which then calculate the url to go to next, based on the ActivityMapping - * class. - * - * @param learnerId the learner who are running this activity in the design. - * @param activity the activity is being run. - * @param lessonId lesson id - * @return the updated learner progress - */ - public LearnerProgress completeActivity(Integer learnerId,Activity activity,LearnerProgress progress); + /** + * Returns the current progress data, in the DTO format required by the jsp progress screen, of the User. + * @param learnerId the Learner's userID + * @param lessonId the Lesson to get progress from. + * @return Array of two objects. [0] List, [1] Activity ID of the current activity + * @throws LearnerServiceException in case of problems. + */ + public Object[] getStructuredActivityURLs(Integer learnerId, Long lessonId); - /** - * Same as LearnerProgress completeActivity(Integer learnerId,Activity activity,LearnerProgress progress) - * except that the it works out the current learner's progress from the given lesson id. - * - * Use the other method if you already have the learner progress, as this method looks up the learner - * progress. - * - * @param learnerId the learner who are running this activity in the design. - * @param activity the activity is being run. - * @param lessonId lesson id - * @return the updated learner progress - */ - public LearnerProgress completeActivity(Integer learnerId,Activity activity,Long lessonId); + /** + * Return the current progress data against progress id. + * @param progressId + * @return + */ + public LearnerProgress getProgressById(Long progressId); - /** - * Retrieve all lessons that has been started, suspended or finished. All - * finished but archived lesson should not be loaded. - * @param learner the user who intend to start a lesson - * @return a list of active lessons. - */ - public LessonDTO[] getActiveLessonsFor(Integer learnerId); - - /** - * Mark the learner progress as restarting to indicate the current learner - * has exit the lesson. Doesn't use the cached progress object in case it - * - * @param userId - * @param lessonId - */ - public void exitLesson(Integer learnerId, Long lessonId); - - /** - * Returns an activity according to the activity id. - * @param activityId the activity id. - * @return the activity requested. - */ - public Activity getActivity(Long activityId); - - /** - * Returns all the active learners by the lesson id. - * @param lessonId the requested lesson id. - * @return the list of learners. - */ - 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); + /** + * Return the current progress data for a user for a lesson + * Returns a DTO suitable to send to Flash. + * @param lesson id + * @param learner id + * @return + */ + public LearnerProgressDTO getProgressDTOByLessonId(Long lessonId, Integer learnerId); - /** - * Perform grouping for the learners who have started the lesson, - * based on the grouping activity. - * - * @param lessonId lesson id - * @param groupingActivityId the activity that has create grouping. - * @param learnerId the learner who triggers the grouping. - * @param forceGrouping if forceGrouping==true and the lesson is a preview lesson then the groupings is done irrespective of the grouping type - * @return true if grouping done, false if waiting for grouping to occur - */ - public boolean performGrouping(Long lessonId, Long groupingActivityId, Integer learnerId, boolean forceGrouping); - + /** + * Marks an activity as attempted. Called when a user selects an OptionsActivity. + * @param learnerId the Learner's userID + * @param lessonId the Lesson to get progress from. + * @param activity the activity being attempted. + * @param clearCompletedFlag If the lesson is completed but this activity is unstarted, should we mark it as incomplete? Used for branching and + * optional sequences for skipped sequences (e.g. force completed branching) + * @return LearnerProgress + */ + public LearnerProgress chooseActivity(Integer learnerId, Long lessonId, Activity activity, Boolean clearCompletedFlag); - /** - * Check up the gate status to go through the gate. This also updates the gate. - * This method should be used when we do not have an grouping activity - * that is already part of the Hibernate session. - * @param gateid the gate that current learner is facing. It could be - * 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 Updated gate details - */ - public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate); + /** + * Calculates learner progress and returns the data required to be displayed to the learner (including URL(s)). + * This method is included in the interface for testing purposes. + * + * @param completedActivityID identifies the activity just completed + * @param learner the Learner + * @return the bean containing the display data for the Learner + * @throws LearnerServiceException in case of problems. + */ + public LearnerProgress calculateProgress(Activity completedActivity, Integer learnerId, LearnerProgress currentLearnerProgress); - /** - * Check up the gate status to go through the gate. This also updates the gate. - * This method should be used when we do have an grouping activity - * that is already part of the Hibernate session. - * @param gate the gate that current learner is facing. It could be - * synch gate, schedule gate or permission gate. - * Don't supply the actual gate from the cached web version - * 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 Updated gate details - */ - public GateActivityDTO knockGate(GateActivity gateActivity, User knocker, boolean forceGate); - /** + * Complete the activity in the progress engine and delegate to the progress + * engine to calculate the next activity in the learning design. + * It is currently triggered by various progress engine related action classes, + * which then calculate the url to go to next, based on the ActivityMapping + * class. + * + * @param learnerId the learner who are running this activity in the design. + * @param activity the activity is being run. + * @param lessonId lesson id + * @return the updated learner progress + */ + public LearnerProgress completeActivity(Integer learnerId, Activity activity, LearnerProgress progress); + + /** + * Same as LearnerProgress completeActivity(Integer learnerId,Activity activity,LearnerProgress progress) + * except that the it works out the current learner's progress from the given lesson id. + * + * Use the other method if you already have the learner progress, as this method looks up the learner + * progress. + * + * @param learnerId the learner who are running this activity in the design. + * @param activity the activity is being run. + * @param lessonId lesson id + * @return the updated learner progress + */ + public LearnerProgress completeActivity(Integer learnerId, Activity activity, Long lessonId); + + /** + * Retrieve all lessons that has been started, suspended or finished. All + * finished but archived lesson should not be loaded. + * @param learner the user who intend to start a lesson + * @return a list of active lessons. + */ + public LessonDTO[] getActiveLessonsFor(Integer learnerId); + + /** + * Mark the learner progress as restarting to indicate the current learner + * has exit the lesson. Doesn't use the cached progress object in case it + * + * @param userId + * @param lessonId + */ + public void exitLesson(Integer learnerId, Long lessonId); + + /** + * Returns an activity according to the activity id. + * @param activityId the activity id. + * @return the activity requested. + */ + public Activity getActivity(Long activityId); + + /** + * Returns all the active learners by the lesson id. + * @param lessonId the requested lesson id. + * @return the list of learners. + */ + 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 lesson id + * @param groupingActivityId the activity that has create grouping. + * @param learnerId the learner who triggers the grouping. + * @param forceGrouping if forceGrouping==true and the lesson is a preview lesson then the groupings is done irrespective of the grouping type + * @return true if grouping done, false if waiting for grouping to occur + */ + public boolean performGrouping(Long lessonId, Long groupingActivityId, Integer learnerId, boolean forceGrouping); + + /** + * Perform grouping for the learner, depending on his/hers choice. + * @param lessonId lesson id + * @param groupingActivityId the activity that create grouping. + * @param groupId id of the group chosen by the learner + * @param learnerId the learner who triggers the grouping. + * @return true if the learner was successfully added to the group; false if the group was empty + * @throws LearnerServiceException + */ + public boolean learnerChooseGroup(Long lessonId, Long groupingActivityId, Long groupId, Integer learnerId) + throws LearnerServiceException; + + /** + * Returns the maximum number of learners per group in learner's choice grouping. + * @param lessonId id of the lesson + * @param groupingId id of the grouping activity + * @return the maximum number of learners per group;null if the requirement for equal number of learners in groups was not set + */ + public Integer calculateMaxNumberOfLearnersPerGroup(Long lessonId, Long groupingId); + + /** + * Check up the gate status to go through the gate. This also updates the gate. + * This method should be used when we do not have an grouping activity + * that is already part of the Hibernate session. + * @param gateid the gate that current learner is facing. It could be + * 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 Updated gate details + */ + public GateActivityDTO knockGate(Long gateActivityId, User knocker, boolean forceGate); + + /** + * Check up the gate status to go through the gate. This also updates the gate. + * This method should be used when we do have an grouping activity + * that is already part of the Hibernate session. + * @param gate the gate that current learner is facing. It could be + * synch gate, schedule gate or permission gate. + * Don't supply the actual gate from the cached web version + * 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 Updated gate details + */ + 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. - * - * @param learnerId - * @param activityId - */ - public String getLearnerActivityURL(Integer learnerId, Long activityId); - - /** - * Get the lesson for this activity. If the activity is not part of a lesson (ie is from an authoring - * design then it will return null. - */ - public Lesson getLessonByActivity(Activity activity); + public List getLearnersForGate(GateActivity gate); - /** - * - * @param learnerId the learner who triggers the move - * @param lessonId lesson id - * @param fromActivity Activity moving from - * @param toActivity Activity moving to (being run) - * @return updated Learner Progress - */ - public LearnerProgress moveToActivity(Integer learnerId, Long lessonId, Activity fromActivity, Activity toActivity); - - /** - * Work out which branch to which a user should go. If the current lesson is a preview lesson, it will force - * the user to a branch if at all possible. - * - * @param lesson current lesson. - * @param BranchingActivity the branching activity - * @param learnerId the learner who triggers the grouping. - * @throws LearnerServiceException - */ - public SequenceActivity determineBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId) throws LearnerServiceException; + /** + * Get the learner url for a particular activity. + * + * @param learnerId + * @param activityId + */ + public String getLearnerActivityURL(Integer learnerId, Long activityId); - /** - * Select a particular branch - we are in preview mode and the author has selected a particular activity. - * @param lesson current lesson. - * @param BranchingActivity the branching activity - * @param learnerId the learner who triggers the grouping. - * @return branchId of the desired branch - * @throws LearnerServiceException - */ - public SequenceActivity selectBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId, Long branchId) throws LearnerServiceException; + /** + * Get the lesson for this activity. If the activity is not part of a lesson (ie is from an authoring + * design then it will return null. + */ + public Lesson getLessonByActivity(Activity activity); + + /** + * + * @param learnerId the learner who triggers the move + * @param lessonId lesson id + * @param fromActivity Activity moving from + * @param toActivity Activity moving to (being run) + * @return updated Learner Progress + */ + public LearnerProgress moveToActivity(Integer learnerId, Long lessonId, Activity fromActivity, Activity toActivity); + + /** + * Work out which branch to which a user should go. If the current lesson is a preview lesson, it will force + * the user to a branch if at all possible. + * + * @param lesson current lesson. + * @param BranchingActivity the branching activity + * @param learnerId the learner who triggers the grouping. + * @throws LearnerServiceException + */ + public SequenceActivity determineBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId) + throws LearnerServiceException; + + /** + * Select a particular branch - we are in preview mode and the author has selected a particular activity. + * @param lesson current lesson. + * @param BranchingActivity the branching activity + * @param learnerId the learner who triggers the grouping. + * @return branchId of the desired branch + * @throws LearnerServiceException + */ + public SequenceActivity selectBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId, Long branchId) + throws LearnerServiceException; } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -r8bc8d173f84ddf9333719585a3ddfd7a676f28be -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 8bc8d173f84ddf9333719585a3ddfd7a676f28be) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -21,7 +21,7 @@ * **************************************************************** */ -/* $$Id$$ */ +/* $$Id$$ */ package org.lamsfoundation.lams.learning.service; import java.sql.Timestamp; @@ -49,6 +49,8 @@ import org.lamsfoundation.lams.learningdesign.Group; import org.lamsfoundation.lams.learningdesign.Grouping; import org.lamsfoundation.lams.learningdesign.GroupingActivity; +import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouper; +import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouping; import org.lamsfoundation.lams.learningdesign.SequenceActivity; import org.lamsfoundation.lams.learningdesign.ToolActivity; import org.lamsfoundation.lams.learningdesign.ToolBranchingActivity; @@ -71,612 +73,647 @@ import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.MessageService; + /** * This class is a facade over the Learning middle tier. * @author chris, Jacky Fang */ -public class LearnerService implements ICoreLearnerService -{ - //--------------------------------------------------------------------- - // Instance variables - //--------------------------------------------------------------------- +public class LearnerService implements ICoreLearnerService { + //--------------------------------------------------------------------- + // Instance variables + //--------------------------------------------------------------------- private static Logger log = Logger.getLogger(LearnerService.class); - - private ILearnerProgressDAO learnerProgressDAO; - private ILessonDAO lessonDAO; - private IActivityDAO activityDAO; - private IGroupingDAO groupingDAO; - private ProgressEngine progressEngine; - private IToolSessionDAO toolSessionDAO; - private ILamsCoreToolService lamsCoreToolService; - private ActivityMapping activityMapping; - private IUserManagementService userManagementService; - private ILessonService lessonService; - protected MessageService messageService; - - //--------------------------------------------------------------------- - // Inversion of Control Methods - Constructor injection - //--------------------------------------------------------------------- - - /** Creates a new instance of LearnerService*/ - public LearnerService(ProgressEngine progressEngine) { - this.progressEngine = progressEngine; - } + private ILearnerProgressDAO learnerProgressDAO; + private ILessonDAO lessonDAO; + private IActivityDAO activityDAO; + private IGroupingDAO groupingDAO; + private ProgressEngine progressEngine; + private IToolSessionDAO toolSessionDAO; + private ILamsCoreToolService lamsCoreToolService; + private ActivityMapping activityMapping; + private IUserManagementService userManagementService; + private ILessonService lessonService; + protected MessageService messageService; - /** Creates a new instance of LearnerService. To be used by Spring, assuming the Spring - * will set up the progress engine via method injection. If you are creating the bean manually - * then use the other constructor. */ - public LearnerService() { - } + //--------------------------------------------------------------------- + // Inversion of Control Methods - Constructor injection + //--------------------------------------------------------------------- - //--------------------------------------------------------------------- - // Inversion of Control Methods - Method injection - //--------------------------------------------------------------------- + /** Creates a new instance of LearnerService*/ + public LearnerService(ProgressEngine progressEngine) { + this.progressEngine = progressEngine; + } + + /** Creates a new instance of LearnerService. To be used by Spring, assuming the Spring + * will set up the progress engine via method injection. If you are creating the bean manually + * then use the other constructor. */ + public LearnerService() { + } + + //--------------------------------------------------------------------- + // Inversion of Control Methods - Method injection + //--------------------------------------------------------------------- /** * Set i18n MessageService */ public void setMessageService(MessageService messageService) { this.messageService = messageService; } - public MessageService getMessageService() { + public MessageService getMessageService() { return messageService; } + /** - * @param toolSessionDAO The toolSessionDAO to set. - */ - public void setToolSessionDAO(IToolSessionDAO toolSessionDAO) - { - this.toolSessionDAO = toolSessionDAO; - } - - /** - * @param lessonDAO The lessonDAO to set. - */ - public void setLessonDAO(ILessonDAO lessonDAO) - { + * @param toolSessionDAO The toolSessionDAO to set. + */ + public void setToolSessionDAO(IToolSessionDAO toolSessionDAO) { + this.toolSessionDAO = toolSessionDAO; + } + + /** + * @param lessonDAO The lessonDAO to set. + */ + public void setLessonDAO(ILessonDAO lessonDAO) { this.lessonDAO = lessonDAO; } - /** - * @param learnerProgressDAO The learnerProgressDAO to set. - */ - public void setLearnerProgressDAO(ILearnerProgressDAO learnerProgressDAO) - { - this.learnerProgressDAO = learnerProgressDAO; - } + /** + * @param learnerProgressDAO The learnerProgressDAO to set. + */ + public void setLearnerProgressDAO(ILearnerProgressDAO learnerProgressDAO) { + this.learnerProgressDAO = learnerProgressDAO; + } - /** - * @param lamsToolService The lamsToolService to set. - */ - public void setLamsCoreToolService(ILamsCoreToolService lamsToolService) - { - this.lamsCoreToolService = lamsToolService; - } - - public void setActivityMapping(ActivityMapping activityMapping) { + /** + * @param lamsToolService The lamsToolService to set. + */ + public void setLamsCoreToolService(ILamsCoreToolService lamsToolService) { + lamsCoreToolService = lamsToolService; + } + + public void setActivityMapping(ActivityMapping activityMapping) { this.activityMapping = activityMapping; } - - /** - * @param activityDAO The activityDAO to set. - */ - public void setActivityDAO(IActivityDAO activityDAO) - { - this.activityDAO = activityDAO; - } - - /** - * @param groupingDAO The groupingDAO to set. - */ - public void setGroupingDAO(IGroupingDAO groupingDAO) - { - this.groupingDAO = groupingDAO; - } - /** - * @return the User Management Service - */ + + /** + * @param activityDAO The activityDAO to set. + */ + public void setActivityDAO(IActivityDAO activityDAO) { + this.activityDAO = activityDAO; + } + + /** + * @param groupingDAO The groupingDAO to set. + */ + public void setGroupingDAO(IGroupingDAO groupingDAO) { + this.groupingDAO = groupingDAO; + } + + /** + * @return the User Management Service + */ public IUserManagementService getUserManagementService() { return userManagementService; } + /** * @param userService User Management Service */ public void setUserManagementService(IUserManagementService userService) { - this.userManagementService = userService; + userManagementService = userService; } - + public void setLessonService(ILessonService lessonService) { this.lessonService = lessonService; } - - //--------------------------------------------------------------------- - // Service Methods - //--------------------------------------------------------------------- - /** - * Delegate to lesson dao to load up the lessons. - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#getActiveLessonsFor(org.lamsfoundation.lams.usermanagement.User) - */ - public LessonDTO[] getActiveLessonsFor(Integer learnerId) - { - User learner = (User)userManagementService.findById(User.class,learnerId); - List activeLessons = this.lessonDAO.getActiveLessonsForLearner(learner); - return getLessonDataFor(activeLessons); - } - - public Lesson getLesson(Long lessonId) - { - return lessonDAO.getLesson(lessonId); - } - - /** - * Get the lesson data for a particular lesson. In a DTO format suitable for sending to the client. - */ - public LessonDTO getLessonData(Long lessonId) - { - Lesson lesson = getLesson(lessonId); - return ( lesson != null ? lesson.getLessonData() : null ); - } - - /** - *

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

- * - *

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

- * - *

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

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

+ * + *

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

+ * + *

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

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

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

- * - * Once lams tool session is inserted, we need to notify the tool to its - * own session. - * - * @param toolActivity - * @param learner - * @throws LamsToolServiceException - */ - private void createToolSessionFor(ToolActivity toolActivity,User learner,Lesson lesson) throws LamsToolServiceException, ToolException - { - // if the tool session already exists, createToolSession() will return null - ToolSession toolSession = lamsCoreToolService.createToolSession(learner,toolActivity,lesson); - if ( toolSession !=null ) { - toolActivity.getToolSessions().add(toolSession); - lamsCoreToolService.notifyToolsToCreateSession(toolSession, toolActivity); - } - } - - - /** - * Create an array of lesson dto based a list of lessons. - * @param lessons the list of lessons. - * @return the lesson dto array. - */ - private LessonDTO[] getLessonDataFor(List lessons) - { - List lessonDTOList = new ArrayList(); - for(Iterator i=lessons.iterator();i.hasNext();) - { - Lesson currentLesson = (Lesson)i.next(); - lessonDTOList.add(currentLesson.getLessonData()); - } - return lessonDTOList.toArray(new LessonDTO[lessonDTOList.size()]); - } + //--------------------------------------------------------------------- + // Helper Methods + //--------------------------------------------------------------------- - /** - * @throws LearnerServiceException - * @see org.lamsfoundation.lams.learning.service.ICoreLearnerService#determineBranch(org.lamsfoundation.lams.lesson.Lesson, org.lamsfoundation.lams.learningdesign.BranchingActivity, java.lang.Integer) - */ - public SequenceActivity determineBranch(Lesson lesson, BranchingActivity branchingActivity, Integer learnerId) throws LearnerServiceException - { - User learner = (User)userManagementService.findById(User.class,learnerId); - if ( learner == null ) { - String error = "determineBranch: learner "+learnerId+" does not exist. Cannot determine branch."; - log.error(error); - throw new LearnerServiceException(error); - } + /** + *

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

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

The action servlet that triggers the system driven grouping @@ -75,196 +74,209 @@ * @struts:action-forward name="viewGroup" path="/grouping.do?method=viewGrouping" * @struts:action-forward name="showGroup" path=".showgroup" * @struts:action-forward name="waitGroup" path=".waitgroup" + * @struts:action-forward name="chooseGroup" path=".choosegroup" * ----------------XDoclet Tags-------------------- * */ -public class GroupingAction extends LamsDispatchAction -{ +public class GroupingAction extends LamsDispatchAction { - /** Input parameter. Boolean value */ - public static final String PARAM_FORCE_GROUPING = "force"; + /** Input parameter. Boolean value */ + public static final String PARAM_FORCE_GROUPING = "force"; - //--------------------------------------------------------------------- - // Instance variables - //--------------------------------------------------------------------- + //--------------------------------------------------------------------- + // Instance variables + //--------------------------------------------------------------------- private static Logger log = Logger.getLogger(GroupingAction.class); - //--------------------------------------------------------------------- - // Class level constants - Session Attributes - //--------------------------------------------------------------------- + //--------------------------------------------------------------------- + // Class level constants - Session Attributes + //--------------------------------------------------------------------- public static final String GROUPS = "groups"; public static final String FINISHED_BUTTON = "finishedButton"; - public static final String LOCAL_FILES= "localFiles"; + public static final String LOCAL_FILES = "localFiles"; public static final String TITLE = "title"; - - //--------------------------------------------------------------------- - // Class level constants - Struts forward - //--------------------------------------------------------------------- + public static final String MAX_LEARNERS_PER_GROUP = "maxLearnersPerGroup"; + + //--------------------------------------------------------------------- + // Class level constants - Struts forward + //--------------------------------------------------------------------- public static final String VIEW_GROUP = "viewGroup"; public static final String WAIT_GROUP = "waitGroup"; public static final String SHOW_GROUP = "showGroup"; - - //--------------------------------------------------------------------- - // Struts Dispatch Method - //--------------------------------------------------------------------- - /** - * Perform the grouping for the users who are currently running the lesson. - * If force is set to true, then we should be in preview mode, and we want to - * override the chosen grouping to make it group straight away. - * - * @param mapping - * @param form - * @param request - * @param response - * @return - * @throws IOException - * @throws ServletException - */ - public ActionForward performGrouping(ActionMapping mapping, - ActionForm form, - HttpServletRequest request, - HttpServletResponse response) throws IOException, - ServletException - { + public static final String CHOOSE_GROUP = "chooseGroup"; - boolean forceGroup = WebUtil.readBooleanParam(request,PARAM_FORCE_GROUPING,false); + //--------------------------------------------------------------------- + // Struts Dispatch Method + //--------------------------------------------------------------------- + /** + * Perform the grouping for the users who are currently running the lesson. + * If force is set to true, then we should be in preview mode, and we want to + * override the chosen grouping to make it group straight away. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward performGrouping(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { - //initialize service object - ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); - LearnerProgress learnerProgress = LearningWebUtil.getLearnerProgress(request, learnerService); + boolean forceGroup = WebUtil.readBooleanParam(request, GroupingAction.PARAM_FORCE_GROUPING, false); + + //initialize service object + ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); + LearnerProgress learnerProgress = LearningWebUtil.getLearnerProgress(request, learnerService); Activity activity = LearningWebUtil.getActivityFromRequest(request, learnerService); - if (!(activity instanceof GroupingActivity)) - { - log.error(className+": activity not GroupingActivity"); + if (!(activity instanceof GroupingActivity)) { + GroupingAction.log.error(LamsDispatchAction.className + ": activity not GroupingActivity"); return mapping.findForward(ActivityMapping.ERROR); } - - boolean groupingDone = learnerService.performGrouping(learnerProgress.getLesson().getLessonId(), - activity.getActivityId(), - LearningWebUtil.getUserId(),forceGroup); + Long lessonId = learnerProgress.getLesson().getLessonId(); + boolean groupingDone = learnerService.performGrouping(lessonId, activity.getActivityId(), LearningWebUtil.getUserId(), + forceGroup); - LearningWebUtil.putActivityInRequest(request, activity, learnerService); - - DynaActionForm groupForm = (DynaActionForm)form; - groupForm.set("previewLesson",learnerProgress.getLesson().isPreviewLesson()); - groupForm.set("title", activity.getTitle()); - + LearningWebUtil.putActivityInRequest(request, activity, learnerService); + + DynaActionForm groupForm = (DynaActionForm) form; + groupForm.set("previewLesson", learnerProgress.getLesson().isPreviewLesson()); + groupForm.set("title", activity.getTitle()); + LearningWebUtil.setupProgressInRequest(groupForm, request, learnerProgress); - if ( groupingDone ) { - request.setAttribute(FINISHED_BUTTON, Boolean.TRUE); - return mapping.findForward(VIEW_GROUP); - } - return mapping.findForward(WAIT_GROUP); - } + if (groupingDone) { + request.setAttribute(GroupingAction.FINISHED_BUTTON, Boolean.TRUE); + return mapping.findForward(GroupingAction.VIEW_GROUP); + } + //forward to group choosing page + if (((GroupingActivity) activity).getCreateGrouping().isLearnerChoiceGrouping()) { + Integer maxNumberOfLeaernersPerGroup = learnerService.calculateMaxNumberOfLearnersPerGroup(lessonId, + ((GroupingActivity) activity).getCreateGrouping().getGroupingId()); + prepareGroupData(request); + request.setAttribute(GroupingAction.MAX_LEARNERS_PER_GROUP, maxNumberOfLeaernersPerGroup); + request.setAttribute(GroupingAction.LOCAL_FILES, Boolean.FALSE); + return mapping.findForward(GroupingAction.CHOOSE_GROUP); + } + return mapping.findForward(GroupingAction.WAIT_GROUP); + } - /** - * Load up the grouping information and forward to the jsp page to display - * all the groups and members. - * @param mapping - * @param form - * @param request - * @param response - * @return - * @throws IOException - * @throws ServletException - */ - public ActionForward viewGrouping(ActionMapping mapping, - ActionForm form, - HttpServletRequest request, - HttpServletResponse response) throws IOException, - ServletException - { - //initialize service object - ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); - - SortedSet groups = new TreeSet(new GroupComparator()); + /** + * Load up the grouping information and forward to the jsp page to display + * all the groups and members. + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward viewGrouping(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + prepareGroupData(request); + request.setAttribute(GroupingAction.LOCAL_FILES, Boolean.FALSE); + ToolAccessMode mode = WebUtil.readToolAccessModeParam(request, AttributeNames.PARAM_MODE, true); + request.setAttribute(GroupingAction.FINISHED_BUTTON, new Boolean(mode == null || !mode.isTeacher())); - Activity activity = LearningWebUtil.getActivityFromRequest(request,learnerService); + return mapping.findForward(GroupingAction.SHOW_GROUP); + } - Grouping grouping = ((GroupingActivity)activity).getCreateGrouping(); - if ( grouping != null) - groups.addAll(grouping.getGroups()); - + /** + * Do the export portfolio. Take the parameters from the standard String request parameters, don't expect + * attributes to be in the request + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward exportPortfolio(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + prepareGroupData(request); + request.setAttribute(GroupingAction.FINISHED_BUTTON, Boolean.FALSE); + request.setAttribute(GroupingAction.LOCAL_FILES, Boolean.TRUE); - request.setAttribute(GROUPS,groups); - request.setAttribute(LOCAL_FILES,Boolean.FALSE); - request.setAttribute(AttributeNames.PARAM_ACTIVITY_ID, activity.getActivityId()); - request.setAttribute(TITLE,activity.getTitle()); + return mapping.findForward(GroupingAction.SHOW_GROUP); + } - ToolAccessMode mode = WebUtil.readToolAccessModeParam(request,AttributeNames.PARAM_MODE, true); - request.setAttribute(FINISHED_BUTTON,new Boolean(mode == null || ! mode.isTeacher())); - - return mapping.findForward(SHOW_GROUP); - } + /** + * Complete the current tool activity and forward to the url of next activity + * in the learning design. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward completeActivity(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + //initialize service object + ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); + LearnerProgress progress = LearningWebUtil.getLearnerProgress(request, learnerService); + Activity groupingActivity = LearningWebUtil.getActivityFromRequest(request, learnerService); + Integer learnerId = LearningWebUtil.getUserId(); - /** - * Do the export portfolio. Take the parameters from the standard String request parameters, don't expect - * attributes to be in the request - * - * @param mapping - * @param form - * @param request - * @param response - * @return - * @throws IOException - * @throws ServletException - */ - public ActionForward exportPortfolio(ActionMapping mapping, - ActionForm form, - HttpServletRequest request, - HttpServletResponse response) throws IOException, - ServletException - { - //initialize service object - ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); - - SortedSet groups = new TreeSet(new GroupComparator()); + // so manually resume the progress. The completeActivity code can cope with a missing activity. + return LearningWebUtil.completeActivity(request, response, LearningWebUtil.getActivityMapping(this.getServlet() + .getServletContext()), progress, groupingActivity, learnerId, learnerService, true); + } - Long activityId = WebUtil.readLongParam(request,AttributeNames.PARAM_ACTIVITY_ID); - Activity activity = learnerService.getActivity(activityId); + /** + * Inserts into the request most of the data required by JSP page. This method is common for several pages. + * @param request + */ + private void prepareGroupData(HttpServletRequest request) { - Grouping grouping = ((GroupingActivity)activity).getCreateGrouping(); - if ( grouping != null) - groups.addAll(grouping.getGroups()); - - request.setAttribute(GROUPS,groups); - request.setAttribute(FINISHED_BUTTON,Boolean.FALSE); - request.setAttribute(LOCAL_FILES,Boolean.TRUE); - request.setAttribute(AttributeNames.PARAM_ACTIVITY_ID, activity.getActivityId()); - request.setAttribute(TITLE,activity.getTitle()); - - return mapping.findForward(SHOW_GROUP); - } + ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); - /** - * Complete the current tool activity and forward to the url of next activity - * in the learning design. - * - * @param mapping - * @param form - * @param request - * @param response - * @return - * @throws IOException - * @throws ServletException - */ - public ActionForward completeActivity(ActionMapping mapping, - ActionForm form, - HttpServletRequest request, - HttpServletResponse response) throws IOException, - ServletException - { - //initialize service object - ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); - LearnerProgress progress = LearningWebUtil.getLearnerProgress(request, learnerService); - Activity groupingActivity = LearningWebUtil.getActivityFromRequest(request,learnerService); - Integer learnerId = LearningWebUtil.getUserId(); + SortedSet groups = new TreeSet(new GroupComparator()); + Activity activity = LearningWebUtil.getActivityFromRequest(request, learnerService); - // so manually resume the progress. The completeActivity code can cope with a missing activity. - return LearningWebUtil.completeActivity(request, response, - LearningWebUtil.getActivityMapping(this.getServlet().getServletContext()), - progress, groupingActivity, - learnerId, learnerService, true); - } - -} + Grouping grouping = ((GroupingActivity) activity).getCreateGrouping(); + if (grouping != null) { + groups.addAll(grouping.getGroups()); + } + request.setAttribute(GroupingAction.GROUPS, groups); + request.setAttribute(GroupingAction.TITLE, activity.getTitle()); + request.setAttribute(AttributeNames.PARAM_ACTIVITY_ID, activity.getActivityId()); + } + + /** + * Responds to a learner's group choice. Might forward back to group choice page if the chosen group was full. + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward learnerChooseGroup(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); + Activity activity = LearningWebUtil.getActivityFromRequest(request, learnerService); + Long groupId = WebUtil.readLongParam(request, "groupId"); + LearnerProgress learnerProgress = LearningWebUtil.getLearnerProgress(request, learnerService); + Long lessonId = learnerProgress.getLesson().getLessonId(); + boolean learnerGroupped = learnerService.learnerChooseGroup(lessonId, activity.getActivityId(), groupId, LearningWebUtil + .getUserId()); + if (learnerGroupped) { + return viewGrouping(mapping, form, request, response); + } + + Integer maxNumberOfLeaernersPerGroup = learnerService.calculateMaxNumberOfLearnersPerGroup(lessonId, + ((GroupingActivity) activity).getCreateGrouping().getGroupingId()); + prepareGroupData(request); + request.setAttribute(GroupingAction.MAX_LEARNERS_PER_GROUP, maxNumberOfLeaernersPerGroup); + request.setAttribute(GroupingAction.LOCAL_FILES, Boolean.FALSE); + return mapping.findForward(GroupingAction.CHOOSE_GROUP); + } + +} \ No newline at end of file Index: lams_learning/test/web/WEB-INF/struts/struts-config.xml =================================================================== diff -u -rfc085e0eda6c46d659c5b98f9ee9e29f495af042 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/test/web/WEB-INF/struts/struts-config.xml (.../struts-config.xml) (revision fc085e0eda6c46d659c5b98f9ee9e29f495af042) +++ lams_learning/test/web/WEB-INF/struts/struts-config.xml (.../struts-config.xml) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -105,6 +105,11 @@ path=".grouping" redirect="false" /> + - + @@ -36,7 +36,7 @@ - + @@ -93,67 +93,40 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + Index: lams_learning/web/grouping/choose.jsp =================================================================== diff -u --- lams_learning/web/grouping/choose.jsp (revision 0) +++ lams_learning/web/grouping/choose.jsp (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -0,0 +1,77 @@ +<%-- +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 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 +--%> + +<%@ taglib uri="tags-html" prefix="html" %> +<%@ taglib uri="tags-bean" prefix="bean" %> +<%@ taglib uri="tags-logic" prefix="logic" %> +<%@ taglib uri="tags-core" prefix="c" %> +<%@ taglib uri="tags-fmt" prefix="fmt" %> +<%@ taglib uri="tags-function" prefix="fn" %> + + +

+

+

 

+

+ + + + + + + + + + + + + + +
+ + + +
+ + + +
+
+   +
+ + + + + + + + + + +
+ +
+ + + + \ No newline at end of file Index: lams_learning/web/grouping/show.jsp =================================================================== diff -u -racc5f651c03bd0895c8b189c932ea35dea91dc7d -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_learning/web/grouping/show.jsp (.../show.jsp) (revision acc5f651c03bd0895c8b189c932ea35dea91dc7d) +++ lams_learning/web/grouping/show.jsp (.../show.jsp) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -48,6 +48,7 @@
+   Index: lams_monitoring/web/WEB-INF/struts/struts-config.xml =================================================================== diff -u -r3a4c502dd96ac40fd96827f36bc450158b145113 -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_monitoring/web/WEB-INF/struts/struts-config.xml (.../struts-config.xml) (revision 3a4c502dd96ac40fd96827f36bc450158b145113) +++ lams_monitoring/web/WEB-INF/struts/struts-config.xml (.../struts-config.xml) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -43,22 +43,17 @@ - @@ -140,19 +134,42 @@ /> + + + + + @@ -68,13 +69,13 @@ - initializeLesson - org.lamsfoundation.lams.monitoring.web.InitializeLessonServlet + gateExportPortfolio + org.lamsfoundation.lams.monitoring.web.GateExportPortfolioServlet - performChosenGrouping - org.lamsfoundation.lams.monitoring.web.PerformChosenGroupingServlet + createLessonClass + org.lamsfoundation.lams.monitoring.web.CreateLessonServlet @@ -83,8 +84,8 @@ - gateExportPortfolio - org.lamsfoundation.lams.monitoring.web.GateExportPortfolioServlet + performChosenGrouping + org.lamsfoundation.lams.monitoring.web.PerformChosenGroupingServlet @@ -93,8 +94,8 @@ - createLessonClass - org.lamsfoundation.lams.monitoring.web.CreateLessonServlet + initializeLesson + org.lamsfoundation.lams.monitoring.web.InitializeLessonServlet @@ -126,28 +127,28 @@ - initializeLesson - /initializeLesson + gateExportPortfolio + /gateExportPortfolio - performChosenGrouping - /monitoring/performChosenGrouping + createLessonClass + /createLessonClass branchingExportPortfolio /branchingExportPortfolio - gateExportPortfolio - /gateExportPortfolio + performChosenGrouping + /monitoring/performChosenGrouping sequenceExportPortfolio /sequenceExportPortfolio - createLessonClass - /createLessonClass + initializeLesson + /initializeLesson @@ -255,5 +256,38 @@ /login.jsp + + + + + Student + LEARNER + + + Can create/modify a learning design + AUTHOR + + + + Can running and monitoring a learning session + MONITOR + + + + GROUP MANAGER + + + GROUP ADMIN + + + + Can add/remove users to the system, set up classes of users for sessions + SYSADMIN + + + + AUTHOR ADMIN + + Index: lams_monitoring/web/grouping/viewGroups.jsp =================================================================== diff -u -racc5f651c03bd0895c8b189c932ea35dea91dc7d -rc209be8131f22f6fe37bd8d6c14b56425a78b766 --- lams_monitoring/web/grouping/viewGroups.jsp (.../viewGroups.jsp) (revision acc5f651c03bd0895c8b189c932ea35dea91dc7d) +++ lams_monitoring/web/grouping/viewGroups.jsp (.../viewGroups.jsp) (revision c209be8131f22f6fe37bd8d6c14b56425a78b766) @@ -51,7 +51,7 @@ - +