Index: lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java =================================================================== diff -u -r6cbd4eddf683da44fcbf3faed4ae3fe10e8336b8 -r09cdc04e21a3a583aafdd4972af3aecd2016dac4 --- lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 6cbd4eddf683da44fcbf3faed4ae3fe10e8336b8) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 09cdc04e21a3a583aafdd4972af3aecd2016dac4) @@ -42,13 +42,13 @@ import org.lamsfoundation.lams.learningdesign.BranchCondition; import org.lamsfoundation.lams.learningdesign.BranchingActivity; import org.lamsfoundation.lams.learningdesign.ChosenGrouping; +import org.lamsfoundation.lams.learningdesign.Competence; +import org.lamsfoundation.lams.learningdesign.CompetenceMapping; import org.lamsfoundation.lams.learningdesign.ComplexActivity; -import org.lamsfoundation.lams.learningdesign.ConditionGateActivity; import org.lamsfoundation.lams.learningdesign.GateActivity; 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.LearningLibrary; import org.lamsfoundation.lams.learningdesign.License; @@ -64,6 +64,8 @@ import org.lamsfoundation.lams.learningdesign.Transition; import org.lamsfoundation.lams.learningdesign.dao.IActivityDAO; import org.lamsfoundation.lams.learningdesign.dao.IBranchActivityEntryDAO; +import org.lamsfoundation.lams.learningdesign.dao.ICompetenceDAO; +import org.lamsfoundation.lams.learningdesign.dao.ICompetenceMappingDAO; import org.lamsfoundation.lams.learningdesign.dao.IGroupDAO; import org.lamsfoundation.lams.learningdesign.dao.IGroupingDAO; import org.lamsfoundation.lams.learningdesign.dao.ILearningDesignDAO; @@ -89,28 +91,35 @@ * @author Manpreet Minhas * @author Mailing Truong * - * This is a utility class for extracting the - * information from the WDDX packet sent by the FLASH. + * This is a utility class for extracting the information from the WDDX packet + * sent by the FLASH. * - * The following rules are applied: - * The client sends a subset of all possible data. - * If a field is included, then the value associated with this field should - * be persisted (the value maybe a new value or an unchanged value) - * If a field is not included then the server should assume that the value - * is unchanged. - * If the value of a field is one of the special null values, then null - * should be persisted. + * The following rules are applied: The client sends a subset of all possible + * data. If a field is included, then the value associated with this field + * should be persisted (the value maybe a new value or an unchanged value) If a + * field is not included then the server should assume that the value is + * unchanged. If the value of a field is one of the special null values, then + * null should be persisted. * * Object extractor has member data, so it should not be used as a singleton. * */ public class ObjectExtractor implements IObjectExtractor { - private static final Integer DEFAULT_COORD = new Integer(10); // default coordinate used if the entry from Flash is 0 or less. + private static final Integer DEFAULT_COORD = new Integer(10); // default + // coordinate + // used if + // the entry + // from + // Flash is + // 0 or + // less. protected IBaseDAO baseDAO = null; protected ILearningDesignDAO learningDesignDAO = null; protected IActivityDAO activityDAO = null; + protected ICompetenceDAO competenceDAO = null; + protected ICompetenceMappingDAO competenceMappingDAO = null; protected ITransitionDAO transitionDAO = null; protected ILearningLibraryDAO learningLibraryDAO = null; protected ILicenseDAO licenseDAO = null; @@ -123,35 +132,51 @@ private Integer mode = null; - /* The newActivityMap is a local copy of all the current activities. This will include - * the "top level" activities and subactivities. It is used to "crossreference" activities - * as we go, without having to repull them from the database. The keys are the UIIDs - * of the activities, not the IDs. It is important that the values in this map are the Activity - * objects related to the Hibernate session as they are updated by the parseTransitions code. + /* + * The newActivityMap is a local copy of all the current activities. This + * will include the "top level" activities and subactivities. It is used to + * "crossreference" activities as we go, without having to repull them from + * the database. The keys are the UIIDs of the activities, not the IDs. It + * is important that the values in this map are the Activity objects related + * to the Hibernate session as they are updated by the parseTransitions + * code. */ protected HashMap newActivityMap = new HashMap(); - /* - * Record the tool sessions and activities as we go for edit on fly. This is needed in case we delete any. - * Cannot get them at the end as Hibernate tries to store the activities before getting the - * tool sessions, and this fails due to a foriegn key error. Its the foriegn key error - * that we are trying to avoid! + /* + * Record the tool sessions and activities as we go for edit on fly. This is + * needed in case we delete any. Cannot get them at the end as Hibernate + * tries to store the activities before getting the tool sessions, and this + * fails due to a foriegn key error. Its the foriegn key error that we are + * trying to avoid! */ - protected HashMap> toolSessionMap = new HashMap>(); // Activity UIID -> ToolSession - /* Used for easy access (rather than going back to the db) and makes it easier to clean them up at the end - * - they can't be deleted easily via the cascades as we don't get a list of deleted entries sent back - * from the client! We would end up with mappings still attached to a sequence activity that shouldn't be there! Not - * done as a map as we sometimes will check via UIID, sometimes by ID + protected HashMap> toolSessionMap = new HashMap>(); // Activity + // UIID + // -> + // ToolSession + /* + * Used for easy access (rather than going back to the db) and makes it + * easier to clean them up at the end - they can't be deleted easily via the + * cascades as we don't get a list of deleted entries sent back from the + * client! We would end up with mappings still attached to a sequence + * activity that shouldn't be there! Not done as a map as we sometimes will + * check via UIID, sometimes by ID */ protected List oldbranchActivityEntryList = new ArrayList(); - protected HashMap oldActivityMap = new HashMap(); // Activity UIID -> Activity + protected HashMap oldActivityMap = new HashMap(); // Activity + // UIID + // -> + // Activity /* cache of groupings - too hard to get them from the db */ protected HashMap groupings = new HashMap(); protected HashMap groups = new HashMap(); protected HashMap branchEntries = new HashMap(); protected HashMap defaultActivityMap = new HashMap(); - /* can't delete as we go as they are linked to other items and have no way of knowing from the packet which ones - * will need to be deleted, so start off assuming all need to be deleted and remove the ones we want to keep. */ + /* + * can't delete as we go as they are linked to other items and have no way + * of knowing from the packet which ones will need to be deleted, so start + * off assuming all need to be deleted and remove the ones we want to keep. + */ protected HashMap groupingsToDelete = new HashMap(); protected LearningDesign learningDesign = null; protected Date modificationDate = null; @@ -192,6 +217,22 @@ this.activityDAO = activityDAO; } + public ICompetenceDAO getCompetenceDAO() { + return competenceDAO; + } + + public void setCompetenceDAO(ICompetenceDAO competenceDAO) { + this.competenceDAO = competenceDAO; + } + + public ICompetenceMappingDAO getCompetenceMappingDAO() { + return competenceMappingDAO; + } + + public void setCompetenceMappingDAO(ICompetenceMappingDAO competenceMappingDAO) { + this.competenceMappingDAO = competenceMappingDAO; + } + public IGroupDAO getGroupDAO() { return groupDAO; } @@ -288,16 +329,20 @@ this.branchActivityEntryDAO = branchActivityEntryDAO; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.lamsfoundation.lams.authoring.IObjectExtractor#extractSaveLearningDesign(java.util.Hashtable) */ public LearningDesign extractSaveLearningDesign(Hashtable table, LearningDesign existingLearningDesign, WorkspaceFolder workspaceFolder, User user) throws WDDXProcessorConversionException, ObjectExtractorException { - // if the learningDesign already exists, update it, otherwise create a new one. + // if the learningDesign already exists, update it, otherwise create a + // new one. learningDesign = existingLearningDesign != null ? existingLearningDesign : new LearningDesign(); - // Check the copy type. Can only update it if it is COPY_TYPE_NONE (ie authoring copy) + // Check the copy type. Can only update it if it is COPY_TYPE_NONE (ie + // authoring copy) Integer copyTypeID = WDDXProcessor.convertToInteger(table, WDDXTAGS.COPY_TYPE); if (copyTypeID == null) { copyTypeID = LearningDesign.COPY_TYPE_NONE; @@ -314,19 +359,23 @@ learningDesign.setWorkspaceFolder(workspaceFolder); learningDesign.setUser(user); - // Pull out all the existing groups. there isn't an easy way to pull them out of the db requires an outer join across - // three objects (learning design -> grouping activity -> grouping) so put both the existing ones and the new ones + // Pull out all the existing groups. there isn't an easy way to pull + // them out of the db requires an outer join across + // three objects (learning design -> grouping activity -> grouping) so + // put both the existing ones and the new ones // here for reference later. initialiseGroupings(); - // Branch activity mappings are indirectly accessible via sequence activities or groupings. Have a separate list + // Branch activity mappings are indirectly accessible via sequence + // activities or groupings. Have a separate list // to make them easier to delete unwanted ones later. intialiseBranchActivityMappings(); - // get a mapping of all the existing activities and their tool sessions, in case we need to delete some tool sessions later. + // get a mapping of all the existing activities and their tool sessions, + // in case we need to delete some tool sessions later. initialiseToolSessionMap(learningDesign); - //get the core learning design stuff - default to invalid + // get the core learning design stuff - default to invalid learningDesign.setValidDesign(Boolean.FALSE); if (keyExists(table, WDDXTAGS.LEARNING_DESIGN_UIID)) { learningDesign.setLearningDesignUIID(WDDXProcessor.convertToInteger(table, WDDXTAGS.LEARNING_DESIGN_UIID)); @@ -361,7 +410,8 @@ if (keyExists(table, WDDXTAGS.HELP_TEXT)) { learningDesign.setHelpText(WDDXProcessor.convertToString(table, WDDXTAGS.HELP_TEXT)); } - //don't receive version from flash anymore(it was hardcoded). Get it from lams configuration database. + // don't receive version from flash anymore(it was hardcoded). Get it + // from lams configuration database. learningDesign.setVersion(Configuration.get(ConfigurationKeys.SERVER_VERSION_NUMBER)); if (keyExists(table, WDDXTAGS.DURATION)) { @@ -380,7 +430,8 @@ mode = WDDXProcessor.convertToInteger(table, WDDXTAGS.SAVE_MODE); } - // Set creation date and modification date based on the server timezone, not the client. + // Set creation date and modification date based on the server timezone, + // not the client. if (learningDesign.getCreateDateTime() == null) { learningDesign.setCreateDateTime(modificationDate); } @@ -393,7 +444,7 @@ learningDesign.setLicense(license); } else { - learningDesign.setLicense(null); //special null value set + learningDesign.setLicense(null); // special null value set } } if (keyExists(table, WDDXTAGS.LICENSE_TEXT)) { @@ -414,11 +465,13 @@ learningDesignDAO.insertOrUpdate(learningDesign); // now process the "parts" of the learning design + parseCompetences((Vector) table.get(WDDXTAGS.COMPETENCES), learningDesign); parseGroupings((Vector) table.get(WDDXTAGS.GROUPINGS)); parseActivities((Vector) table.get(WDDXTAGS.ACTIVITIES)); parseActivitiesToMatchUpParentandInputActivities((Vector) table.get(WDDXTAGS.ACTIVITIES)); parseTransitions((Vector) table.get(WDDXTAGS.TRANSITIONS)); parseBranchMappings((Vector) table.get(WDDXTAGS.BRANCH_MAPPINGS)); + parseCompetenceMappings((Vector) table.get(WDDXTAGS.ACTIVITIES)); progressDefaultChildActivities(); learningDesign.setFirstActivity(learningDesign.calculateFirstActivity()); @@ -429,11 +482,15 @@ return learningDesign; } - /** Link SequenceActivities up with their firstActivity entries and BranchingActivities with their - * default branch. Also tidy up the order ids for sequence activities so that they are in the same - * order as the transitions - needed for the IMSLD export conversion to work. Not all - * the transitions may be drawn yet, so number off the others best we can. - * @throws WDDXProcessorConversionException */ + /** + * Link SequenceActivities up with their firstActivity entries and + * BranchingActivities with their default branch. Also tidy up the order ids + * for sequence activities so that they are in the same order as the + * transitions - needed for the IMSLD export conversion to work. Not all the + * transitions may be drawn yet, so number off the others best we can. + * + * @throws WDDXProcessorConversionException + */ private void progressDefaultChildActivities() throws WDDXProcessorConversionException { if (defaultActivityMap.size() > 0) { @@ -486,9 +543,10 @@ } } - /** - * Initialise the map of groupings with those in the db from a previous save. - * This must be called as soon as the learning design is read from the db and before it is changed. + /** + * Initialise the map of groupings with those in the db from a previous + * save. This must be called as soon as the learning design is read from the + * db and before it is changed. */ private void initialiseGroupings() { List dbGroupings = groupingDAO.getGroupingsByLearningDesign(learningDesign.getLearningDesignId()); @@ -504,8 +562,10 @@ oldbranchActivityEntryList = branchActivityEntryDAO.getEntriesByLearningDesign(learningDesign.getLearningDesignId()); } - /** Initialise the map of tool sessions already in the database. Used to work out what will be deleted - * by Hibernate later - useful to clean up any unwanted tool sessions for edit on the fly. + /** + * Initialise the map of tool sessions already in the database. Used to work + * out what will be deleted by Hibernate later - useful to clean up any + * unwanted tool sessions for edit on the fly. */ @SuppressWarnings("unchecked") private void initialiseToolSessionMap(LearningDesign learningDesign) { @@ -529,10 +589,14 @@ } } - /** Delete the old tool session. Won't be done via Hibernate cascades as we only want to do it - * for edit on fly. The progress engine pre-generates the tool sessions for class level activities, - * so if we edit the design, we need to delete the tool sessions. If we encounter evidence that this - * is a grouped activity - either more than one tool session exists or the activity is grouped, then abort. */ + /** + * Delete the old tool session. Won't be done via Hibernate cascades as we + * only want to do it for edit on fly. The progress engine pre-generates the + * tool sessions for class level activities, so if we edit the design, we + * need to delete the tool sessions. If we encounter evidence that this is a + * grouped activity - either more than one tool session exists or the + * activity is grouped, then abort. + */ private void deleteUnwantedToolSessions(LearningDesign learningDesign) throws ObjectExtractorException { if (learningDesign.getEditOverrideLock() && learningDesign.getEditOverrideUser() != null) { @@ -578,17 +642,19 @@ } /** - * Parses the groupings array sent from the WDDX packet. It will create - * the groupings object (ChosenGrouping, RandomGrouping) so that when the - * GroupingActivity is processed, it can link to the grouping object - * that has been created by this method. + * Parses the groupings array sent from the WDDX packet. It will create the + * groupings object (ChosenGrouping, RandomGrouping) so that when the + * GroupingActivity is processed, it can link to the grouping object that + * has been created by this method. + * * @param groupingsList * @throws WDDXProcessorConversionException */ private void parseGroupings(List groupingsList) throws WDDXProcessorConversionException { - //iterate through the list of groupings objects - //each object should contain information groupingUUID, groupingID, groupingTypeID + // iterate through the list of groupings objects + // each object should contain information groupingUUID, groupingID, + // groupingTypeID if (groupingsList != null) { Iterator iterator = groupingsList.iterator(); while (iterator.hasNext()) { @@ -612,7 +678,8 @@ } Grouping grouping = groupings.get(groupingUUID); - // check that the grouping type is still okay - if it is we keep the grouping otherwise + // check that the grouping type is still okay - if it is we keep the + // grouping otherwise // we get rid of the old hibernate object. if (grouping != null) { if (grouping.getGroupingTypeId().equals(groupingTypeID)) { @@ -639,10 +706,6 @@ else if (grouping.isChosenGrouping()) { createChosenGrouping((ChosenGrouping) grouping, groupingDetails); } - - else if (grouping.isLearnerChoiceGrouping()) { - createLearnerChoiceGrouping((LearnerChoiceGrouping) grouping, groupingDetails); - } else { createLessonClass((LessonClass) grouping, groupingDetails); } @@ -693,10 +756,14 @@ } Long groupID = WDDXProcessor.convertToLong(groupDetails, WDDXTAGS.GROUP_ID); - // Does it exist already? If the group was created at runtime, there will be an ID but no IU ID field. - // If it was created in authoring, will have a UI ID and may or may not have an ID. - // So try to match up on UI ID first, failing that match on ID. Then the worst case, which is the group - // is created at runtime but then modified in authoring (and has has a new UI ID added) is handled. + // Does it exist already? If the group was created at runtime, there + // will be an ID but no IU ID field. + // If it was created in authoring, will have a UI ID and may or may not + // have an ID. + // So try to match up on UI ID first, failing that match on ID. Then the + // worst case, which is the group + // is created at runtime but then modified in authoring (and has has a + // new UI ID added) is handled. if (grouping.getGroups() != null && grouping.getGroups().size() > 0) { Group uiid_match = null; Group id_match = null; @@ -734,7 +801,8 @@ private void createRandomGrouping(RandomGrouping randomGrouping, Hashtable groupingDetails) throws WDDXProcessorConversionException { - // the two settings are mutually exclusive. Flash takes care of this, but we'll code it here too just to make sure. + // the two settings are mutually exclusive. Flash takes care of this, + // but we'll code it here too just to make sure. Integer numLearnersPerGroup = WDDXProcessor.convertToInteger(groupingDetails, WDDXTAGS.LEARNERS_PER_GROUP); if (numLearnersPerGroup != null && numLearnersPerGroup.intValue() > 0) { randomGrouping.setLearnersPerGroup(numLearnersPerGroup); @@ -754,43 +822,19 @@ private void createChosenGrouping(ChosenGrouping chosenGrouping, Hashtable groupingDetails) throws WDDXProcessorConversionException { - //no extra properties as yet + // no extra properties as yet } - private void createLearnerChoiceGrouping(LearnerChoiceGrouping learnerChoiceGrouping, Hashtable groupingDetails) - throws WDDXProcessorConversionException { - - Integer numLearnersPerGroup = WDDXProcessor.convertToInteger(groupingDetails, WDDXTAGS.LEARNERS_PER_GROUP); - if (numLearnersPerGroup != null && numLearnersPerGroup.intValue() > 0) { - learnerChoiceGrouping.setLearnersPerGroup(numLearnersPerGroup); - learnerChoiceGrouping.setNumberOfGroups(null); - learnerChoiceGrouping.setEqualNumberOfLearnersPerGroup(null); - } - else { - Integer numGroups = WDDXProcessor.convertToInteger(groupingDetails, WDDXTAGS.NUMBER_OF_GROUPS); - if (numGroups != null && numGroups.intValue() > 0) { - learnerChoiceGrouping.setNumberOfGroups(numGroups); - } - else { - learnerChoiceGrouping.setNumberOfGroups(null); - } - learnerChoiceGrouping.setLearnersPerGroup(null); - Boolean equalNumberOfLearnersPerGroup = WDDXProcessor.convertToBoolean(groupingDetails, - WDDXTAGS.EQUAL_NUMBER_OF_LEARNERS_PER_GROUP); - if (equalNumberOfLearnersPerGroup != null) { - learnerChoiceGrouping.setEqualNumberOfLearnersPerGroup(equalNumberOfLearnersPerGroup); - } - } - } - /** - * Parses the list of activities sent from the WDDX packet. The current activities that - * belong to this learning design will be compared with the new list of activities. Any new activities will - * be added to the database, existing activities will be updated, and any activities that are not - * present in the list of activities from the wddx packet (but appear in the list of current activities) - * are deleted. + * Parses the list of activities sent from the WDDX packet. The current + * activities that belong to this learning design will be compared with the + * new list of activities. Any new activities will be added to the database, + * existing activities will be updated, and any activities that are not + * present in the list of activities from the wddx packet (but appear in the + * list of current activities) are deleted. * - * @param activitiesList The list of activities from the WDDX packet. + * @param activitiesList + * The list of activities from the WDDX packet. * @throws WDDXProcessorConversionException * @throws ObjectExtractorException */ @@ -808,21 +852,212 @@ } // clear the transitions. - // clear the old set and reset up the activities set. Done this way to keep the Hibernate cascading happy. + // clear the old set and reset up the activities set. Done this way to + // keep the Hibernate cascading happy. // this means we don't have to manually remove the transition object. - // Note: This will leave orphan content in the tool tables. It can be removed by the tool content cleaning job, - // which may be run from the admin screen or via a cron job. + // Note: This will leave orphan content in the tool tables. It can be + // removed by the tool content cleaning job, + // which may be run from the admin screen or via a cron job. learningDesign.getActivities().clear(); learningDesign.getActivities().addAll(newActivityMap.values()); - //TODO: Need to double check that the toolID/toolContentID combinations match entries in lams_tool_content table, or put FK on table. + // TODO: Need to double check that the toolID/toolContentID combinations + // match entries in lams_tool_content table, or put FK on table. learningDesignDAO.insertOrUpdate(learningDesign); } /** - * Because the activities list was processed before by the method parseActivities, it is assumed that - * all activities have already been saved into the database. So now we can go through and find the any parent + * Parses the list of activities sent from the WDDX packet for competence + * mappings. Each activity's new set of competenceMapping is compared + * against the old set and the db is updated accordingly + * + * @param activitiesList + * The list of activities from the WDDX packet. + * @throws WDDXProcessorConversionException + * @throws ObjectExtractorException + */ + @SuppressWarnings("unchecked") + private void parseCompetenceMappings(List activitiesList) throws WDDXProcessorConversionException, ObjectExtractorException { + + if (activitiesList != null) { + Iterator iterator = activitiesList.iterator(); + while (iterator.hasNext()) { + Hashtable activityDetails = (Hashtable) iterator.next(); + + // Check that this is a tool activity, otherwise continue to the + // next iteration + if (keyExists(activityDetails, WDDXTAGS.ACTIVITY_TYPE_ID)) { + int actType = WDDXProcessor.convertToInteger(activityDetails, WDDXTAGS.ACTIVITY_TYPE_ID); + if (actType != Activity.TOOL_ACTIVITY_TYPE) { + continue; + } + } + + // Get the tool activity using the UIID and the learningDesignID + ToolActivity toolActivity = null; + if (keyExists(activityDetails, WDDXTAGS.ACTIVITY_UIID)) { + toolActivity = (ToolActivity) activityDAO.getActivityByUIID(WDDXProcessor.convertToInteger(activityDetails, + WDDXTAGS.ACTIVITY_UIID), learningDesign); + } + else { + continue; + } + + if (keyExists(activityDetails, WDDXTAGS.COMPETENCE_MAPPINGS)) { + List competenceMappingsList = (Vector) activityDetails.get(WDDXTAGS.COMPETENCE_MAPPINGS); + + for (String competenceMappingEntry : competenceMappingsList) { + + if (toolActivity.getActivityId() != null) { + + // First get the competence from the competence + // mapping entry in the hashtable + Competence competence = competenceDAO.getCompetence(toolActivity.getLearningDesign(), + competenceMappingEntry); + if (competence == null) { + continue; + } + + // Now get the competence mapping using the tool + // activity and the competence as reference + CompetenceMapping competenceMapping = competenceMappingDAO.getCompetenceMapping(toolActivity, + competence); + + // Only save new competence mappings, no need to + // update existing + if (competenceMapping == null) { + CompetenceMapping newMapping = new CompetenceMapping(); + newMapping.setCompetence(competence); + newMapping.setToolActivity(toolActivity); + + // newMappings.add(newMapping); + competenceMappingDAO.saveOrUpdate(newMapping); + // toolActivity.getCompetenceMappings().add(newMapping); + } + } + else { + Competence competence = competenceDAO.getCompetence(learningDesign, competenceMappingEntry); + CompetenceMapping newMapping = new CompetenceMapping(); + newMapping.setCompetence(competence); + newMapping.setToolActivity(toolActivity); + competenceMappingDAO.saveOrUpdate(newMapping); + // toolActivity.getCompetenceMappings().add(newMapping); + } + } + + // delete any pre-existing mappings that have been deleted + Set existingMappings = toolActivity.getCompetenceMappings(); + if (existingMappings != null) { + Set removeCompetenceMappings = new HashSet(); + if (competenceMappingsList != null && competenceMappingsList.size() > 0) { + for (CompetenceMapping competenceMapping : existingMappings) { + boolean remove = true; + + for (String competenceMappingEntry : competenceMappingsList) { + if (competenceMappingEntry.equals(competenceMapping.getCompetence().getTitle())) { + remove = false; + break; + } + } + + if (remove) { + removeCompetenceMappings.add(competenceMapping); + } + } + } + else { + removeCompetenceMappings.addAll(existingMappings); + } + competenceMappingDAO.deleteAll(removeCompetenceMappings); + toolActivity.getCompetenceMappings().removeAll(removeCompetenceMappings); + } + } + } + } + } + + /** + * Parses the list of competences sent from the WDDX packet. The current + * competences that belong to this learning design will be compared with the + * new list of competences. Any new competences will be added to the + * database, existing competences will be updated, and any competences that + * are not present in the list of competences from the wddx packet (but + * appear in the list of current competences) are deleted. + * + * @param activitiesList + * The list of activities from the WDDX packet. + * @throws WDDXProcessorConversionException + * @throws ObjectExtractorException + */ + @SuppressWarnings("unchecked") + private void parseCompetences(List competenceList, LearningDesign learningDesign) + throws WDDXProcessorConversionException, ObjectExtractorException { + + Set existingCompetences = learningDesign.getCompetences(); + if (competenceList != null) { + for (Hashtable competenceTable : competenceList) { + String title = (String) competenceTable.get("title"); + String description = (String) competenceTable.get("description"); + + if (getComptenceFromSet(existingCompetences, title) != null) { + Competence updateCompetence = getComptenceFromSet(existingCompetences, title); + updateCompetence.setDescription(description); + competenceDAO.saveOrUpdate(updateCompetence); + } + else { + Competence newCompetence = new Competence(); + newCompetence.setTitle(title); + newCompetence.setDescription(description); + newCompetence.setLearningDesign(learningDesign); + competenceDAO.saveOrUpdate(newCompetence); + } + } + + // now go through and delete any competences from the old list, + // that dont exist in the new list. + Set removeCompetences = new HashSet(); + if (existingCompetences != null) { + if (competenceList != null && competenceList.size() > 0) { + for (Competence existingCompetence : existingCompetences) { + boolean remove = true; + for (Hashtable competenceTable : competenceList) { + if (existingCompetence.getTitle().equals(competenceTable.get("title"))) { + remove = false; + break; + } + } + + if (remove) { + removeCompetences.add(existingCompetence); + } + } + } + else { + removeCompetences.addAll(existingCompetences); + } + // competenceDAO.deleteAll(removeCompetences); + learningDesign.getCompetences().removeAll(removeCompetences); + } + } + } + + private Competence getComptenceFromSet(Set competences, String title) { + if (competences != null) { + for (Competence competence : competences) { + if (competence.getTitle().equals(title)) { + return competence; + } + } + + } + return null; + } + + /** + * Because the activities list was processed before by the method + * parseActivities, it is assumed that all activities have already been + * saved into the database. So now we can go through and find the any parent * activity or input activities for an activity. * * @param activitiesList @@ -861,11 +1096,14 @@ else { existingActivity.setParentActivity(null); existingActivity.setParentUIID(null); - existingActivity.setOrderId(null); // top level activities don't have order ids. + existingActivity.setOrderId(null); // top level + // activities don't + // have order ids. } } - // match up activity to input activities based on UIID. At present there will be only one input activity + // match up activity to input activities based on UIID. At + // present there will be only one input activity existingActivity.getInputActivities().clear(); Integer inputActivityUIID = WDDXProcessor.convertToInteger(activityDetails, WDDXTAGS.INPUT_TOOL_ACTIVITY_UIID); if (inputActivityUIID != null) { @@ -884,11 +1122,12 @@ } /** - * Like parseActivities, parseTransitions parses the list of transitions from the wddx packet. - * New transitions will be added, existing transitions updated and any transitions that are no - * longer needed are deleted. + * Like parseActivities, parseTransitions parses the list of transitions + * from the wddx packet. New transitions will be added, existing transitions + * updated and any transitions that are no longer needed are deleted. * - * @param transitionsList The list of transitions from the wddx packet + * @param transitionsList + * The list of transitions from the wddx packet * @param learningDesign * @throws WDDXProcessorConversionException */ @@ -902,7 +1141,8 @@ while (iterator.hasNext()) { Hashtable transitionDetails = (Hashtable) iterator.next(); Transition transition = extractTransitionObject(transitionDetails); - // Check if transition actually exists. extractTransitionObject returns null + // Check if transition actually exists. extractTransitionObject + // returns null // if neither the to/from activity exists. if (transition != null) { transitionDAO.insertOrUpdate(transition); @@ -922,10 +1162,12 @@ cleanupTransition(element); } } - // clear the old set and reset up the transition set. Done this way to keep the Hibernate cascading happy. + // clear the old set and reset up the transition set. Done this way to + // keep the Hibernate cascading happy. // this means we don't have to manually remove the transition object. - // Note: This will leave orphan content in the tool tables. It can be removed by the tool content cleaning job, - // which may be run from the admin screen or via a cron job. + // Note: This will leave orphan content in the tool tables. It can be + // removed by the tool content cleaning job, + // which may be run from the admin screen or via a cron job. learningDesign.getTransitions().clear(); learningDesign.getTransitions().addAll(newMap.values()); @@ -936,15 +1178,16 @@ public Activity extractActivityObject(Hashtable activityDetails) throws WDDXProcessorConversionException, ObjectExtractorException { - //it is assumed that the activityUUID will always be sent by flash. + // it is assumed that the activityUUID will always be sent by flash. Integer activityUUID = WDDXProcessor.convertToInteger(activityDetails, WDDXTAGS.ACTIVITY_UIID); Activity activity = null; Integer activityTypeID = WDDXProcessor.convertToInteger(activityDetails, WDDXTAGS.ACTIVITY_TYPE_ID); if (activityTypeID == null) { throw new ObjectExtractorException("activityTypeID missing"); } - //get the activity with the particular activity uuid, if null, then new object needs to be created. + // get the activity with the particular activity uuid, if null, then new + // object needs to be created. Activity existingActivity = activityDAO.getActivityByUIID(activityUUID, learningDesign); if (existingActivity != null && !existingActivity.getActivityTypeId().equals(activityTypeID)) { existingActivity = null; @@ -1082,8 +1325,10 @@ private void buildComplexActivity(ComplexActivity activity, Hashtable activityDetails) throws WDDXProcessorConversionException, ObjectExtractorException { - // clear all the children - will be built up again by parseActivitiesToMatchUpParentActivityByParentUIID - // we don't use all-delete-orphan on the activities relationship so we can do this clear. + // clear all the children - will be built up again by + // parseActivitiesToMatchUpParentActivityByParentUIID + // we don't use all-delete-orphan on the activities relationship so we + // can do this clear. activity.getActivities().clear(); activity.setDefaultActivity(null); @@ -1127,7 +1372,8 @@ private void buildGroupingActivity(GroupingActivity groupingActivity, Hashtable activityDetails) throws WDDXProcessorConversionException, ObjectExtractorException { /** - * read the createGroupingUUID, get the Grouping Object, and set CreateGrouping to that object + * read the createGroupingUUID, get the Grouping Object, and set + * CreateGrouping to that object */ Integer createGroupingUIID = WDDXProcessor.convertToInteger(activityDetails, WDDXTAGS.CREATE_GROUPING_UIID); Grouping grouping = groupings.get(createGroupingUIID); @@ -1139,15 +1385,15 @@ SystemTool systemTool = getSystemTool(SystemTool.GROUPING); groupingActivity.setSystemTool(systemTool); - /*Hashtable groupingDetails = (Hashtable) activityDetails.get(WDDXTAGS.GROUPING_DTO); - if( groupingDetails != null ){ - Grouping grouping = extractGroupingObject(groupingDetails); - groupingActivity.setCreateGrouping(grouping); - groupingActivity.setCreateGroupingUIID(grouping.getGroupingUIID()); - } else { - groupingActivity.setCreateGrouping(null); - groupingActivity.setCreateGroupingUIID(null); - } */ + /* + * Hashtable groupingDetails = (Hashtable) + * activityDetails.get(WDDXTAGS.GROUPING_DTO); if( groupingDetails != + * null ){ Grouping grouping = extractGroupingObject(groupingDetails); + * groupingActivity.setCreateGrouping(grouping); + * groupingActivity.setCreateGroupingUIID(grouping.getGroupingUIID()); } + * else { groupingActivity.setCreateGrouping(null); + * groupingActivity.setCreateGroupingUIID(null); } + */ } private void buildOptionsActivity(OptionsActivity optionsActivity, Hashtable activityDetails) @@ -1177,7 +1423,6 @@ log.debug("In tool activity UUID" + activityDetails.get(WDDXTAGS.ACTIVITY_UIID) + " tool content id=" + activityDetails.get(WDDXTAGS.TOOL_CONTENT_ID)); } - if (keyExists(activityDetails, WDDXTAGS.TOOL_CONTENT_ID)) { toolActivity.setToolContentId(WDDXProcessor.convertToLong(activityDetails, WDDXTAGS.TOOL_CONTENT_ID)); } @@ -1198,9 +1443,6 @@ else if (activity instanceof SystemGateActivity) { buildSystemGateActivity((SystemGateActivity) activity, activityDetails); } - else if (activity instanceof ConditionGateActivity) { - buildConditionGateActivity((ConditionGateActivity) activity, activityDetails); - } else { buildScheduleGateActivity((ScheduleGateActivity) activity, activityDetails); } @@ -1225,15 +1467,10 @@ activity.setSystemTool(getSystemTool(SystemTool.SYSTEM_GATE)); } - private void buildConditionGateActivity(ConditionGateActivity activity, Hashtable activityDetails) - throws WDDXProcessorConversionException { - activity.setSystemTool(getSystemTool(SystemTool.CONDITION_GATE)); - } - private void buildScheduleGateActivity(ScheduleGateActivity activity, Hashtable activityDetails) throws WDDXProcessorConversionException { - //activity.setGateStartDateTime(WDDXProcessor.convertToDate(activityDetails,WDDXTAGS.GATE_START_DATE)); - //activity.setGateEndDateTime(WDDXProcessor.convertToDate(activityDetails,WDDXTAGS.GATE_END_DATE)); + // activity.setGateStartDateTime(WDDXProcessor.convertToDate(activityDetails,WDDXTAGS.GATE_START_DATE)); + // activity.setGateEndDateTime(WDDXProcessor.convertToDate(activityDetails,WDDXTAGS.GATE_END_DATE)); activity.setGateStartTimeOffset(WDDXProcessor.convertToLong(activityDetails, WDDXTAGS.GATE_START_OFFSET)); activity.setGateEndTimeOffset(WDDXProcessor.convertToLong(activityDetails, WDDXTAGS.GATE_END_OFFSET)); SystemTool systemTool = getSystemTool(SystemTool.SCHEDULE_GATE); @@ -1249,15 +1486,16 @@ } } - /** Create the transition from a WDDX based hashtable. It is easier to go + /** + * Create the transition from a WDDX based hashtable. It is easier to go * straight to the data object rather than going via the DTO, as the DTO * returns the special null values from the getter methods. This makes it * hard to set up the transaction object from the transitionDTO. *

- * Assumes that all the activities have been read and are in the newActivityMap. - * The toActivity and fromActivity are only set if the activity exists in the - * newActivityMap. If this leaves the transition with no to/from activities - * then null is returned. + * Assumes that all the activities have been read and are in the + * newActivityMap. The toActivity and fromActivity are only set if the + * activity exists in the newActivityMap. If this leaves the transition with + * no to/from activities then null is returned. * * @param transitionDetails * @throws WDDXProcessorConversionException @@ -1295,7 +1533,7 @@ if (toActivity != null) { transition.setToActivity(toActivity); transition.setToUIID(toUIID); - //update the transitionTo property for the activity + // update the transitionTo property for the activity toActivity.setTransitionTo(transition); } else { @@ -1307,7 +1545,7 @@ if (fromActivity != null) { transition.setFromActivity(fromActivity); transition.setFromUIID(fromUIID); - //update the transitionFrom property for the activity + // update the transitionFrom property for the activity fromActivity.setTransitionFrom(transition); } else { @@ -1328,16 +1566,18 @@ return transition; } else { - // One of the to/from is missing, can't store this transition. Make sure we clean up the related activities + // One of the to/from is missing, can't store this transition. Make + // sure we clean up the related activities cleanupTransition(transition); transition.setLearningDesign(null); return null; } } /** - * Wipe out any links fromany activities that may be linked to it (e.g. the case where a transition has an from activity - * but not a too activity. These cases should be picked up by Flash, but just in case. + * Wipe out any links fromany activities that may be linked to it (e.g. the + * case where a transition has an from activity but not a too activity. + * These cases should be picked up by Flash, but just in case. */ private void cleanupTransition(Transition transition) { if (transition.getFromActivity().getTransitionFrom().equals(transition)) { @@ -1348,14 +1588,17 @@ } } - /** Search in learning design for existing object. Can't go to database as that will trigger - * a Flush, and we haven't updated the rest of the design, so this would trigger a - * "deleted object would be re-saved by cascade" error. - * - * Check both the UUID for a match, and the to and from for a match. If the user deletes a - * transition then redraws it between the same activities, then inserting a new one in the db - * will trigger a duplicate key exception. So we need to reuse any that have the same to/from. - */ + /** + * Search in learning design for existing object. Can't go to database as + * that will trigger a Flush, and we haven't updated the rest of the design, + * so this would trigger a "deleted object would be re-saved by cascade" + * error. + * + * Check both the UUID for a match, and the to and from for a match. If the + * user deletes a transition then redraws it between the same activities, + * then inserting a new one in the db will trigger a duplicate key + * exception. So we need to reuse any that have the same to/from. + */ private Transition findTransition(Integer transitionUUID, Integer toUIID, Integer fromUIID) { Transition existingTransition = null; Set transitions = learningDesign.getTransitions(); @@ -1374,10 +1617,14 @@ } /** - * Checks whether the hashtable contains the key specified by key - * If the key exists, returns true, otherwise return false. - * @param table The hashtable to check - * @param key The key to find + * Checks whether the hashtable contains the key specified by + * key If the key exists, returns true, otherwise return + * false. + * + * @param table + * The hashtable to check + * @param key + * The key to find * @return */ private boolean keyExists(Hashtable table, String key) { @@ -1398,11 +1645,11 @@ } /** - * Parses the mappings used for branching. They map groups to the sequence activities - * that form a branch within a branching activity. + * Parses the mappings used for branching. They map groups to the sequence + * activities that form a branch within a branching activity. * - * Must be done after all the other parsing as we need to match up activities - * and groups. + * Must be done after all the other parsing as we need to match up + * activities and groups. * * Will also delete any old (now unused) mappings * @@ -1418,8 +1665,10 @@ } } - // now go through and delete any old branch mappings that are no longer used. - // need to remove them from their collections to make sure it isn't accidently re-added. + // now go through and delete any old branch mappings that are no longer + // used. + // need to remove them from their collections to make sure it isn't + // accidently re-added. Iterator iter = oldbranchActivityEntryList.iterator(); while (iter.hasNext()) { BranchActivityEntry oldEntry = (BranchActivityEntry) iter.next(); @@ -1436,8 +1685,9 @@ } @SuppressWarnings("unchecked") - /** Get the BranchActivityEntry details. - * This may be either for group based branching, it may be for tool output based branching or for a condition gate activity. + /** + * Get the BranchActivityEntry details. This may be either for group based + * branching, or it may be for tool output based branching */ private BranchActivityEntry extractBranchActivityEntry(Hashtable details) throws WDDXProcessorConversionException { @@ -1450,53 +1700,46 @@ Integer sequenceActivityUIID = WDDXProcessor.convertToInteger(details, WDDXTAGS.BRANCH_SEQUENCE_ACTIVITY_UIID); Integer branchingActivityUIID = WDDXProcessor.convertToInteger(details, WDDXTAGS.BRANCH_ACTIVITY_UIID); + SequenceActivity sequenceActivity = null; + Activity activity = newActivityMap.get(sequenceActivityUIID); + if (activity == null) { + throw new WDDXProcessorConversionException( + "Sequence Activity listed in the branch mapping list is missing. Mapping entry UUID " + entryUIID + + " sequenceActivityUIID " + sequenceActivityUIID); + } + else if (!activity.isSequenceActivity()) { + throw new WDDXProcessorConversionException( + "Activity listed in the branch mapping list is not a sequence activity. Mapping entry UUID " + entryUIID + + " sequenceActivityUIID " + sequenceActivityUIID); + } + else { + sequenceActivity = (SequenceActivity) activity; + } + Activity branchingActivity = newActivityMap.get(branchingActivityUIID); if (branchingActivity == null) { throw new WDDXProcessorConversionException( "Branching Activity listed in the branch mapping list is missing. Mapping entry UUID " + entryUIID + " branchingActivityUIID " + branchingActivityUIID); } - if (!branchingActivity.isBranchingActivity() && !branchingActivity.isConditionGate()) { + if (!branchingActivity.isBranchingActivity()) { throw new WDDXProcessorConversionException( - "Activity listed in the branch mapping list is not a branching activity nor a condition gate. Mapping entry UUID " - + entryUIID + " branchingActivityUIID " + branchingActivityUIID); + "Activity listed in the branch mapping list is not a branching activity. Mapping entry UUID " + entryUIID + + " branchingActivityUIID " + branchingActivityUIID); } - //sequence activity is null for a condition gate - SequenceActivity sequenceActivity = null; - if (!branchingActivity.isConditionGate()) { - Activity activity = newActivityMap.get(sequenceActivityUIID); - if (activity == null) { - throw new WDDXProcessorConversionException( - "Sequence Activity listed in the branch mapping list is missing. Mapping entry UUID " + entryUIID - + " sequenceActivityUIID " + sequenceActivityUIID); - } - else if (!activity.isSequenceActivity()) { - throw new WDDXProcessorConversionException( - "Activity listed in the branch mapping list is not a sequence activity. Mapping entry UUID " + entryUIID - + " sequenceActivityUIID " + sequenceActivityUIID); - } - else { - sequenceActivity = (SequenceActivity) activity; - } - } - // If the mapping was created at runtime, there will be an ID but no IU ID field. - // If it was created in authoring, will have a UI ID and may or may not have an ID. - // So try to match up on UI ID first, failing that match on ID. Then the worst case, which is the mapping - // is created at runtime but then modified in authoring (and has has a new UI ID added) is handled. + // If the mapping was created at runtime, there will be an ID but no IU + // ID field. + // If it was created in authoring, will have a UI ID and may or may not + // have an ID. + // So try to match up on UI ID first, failing that match on ID. Then the + // worst case, which is the mapping + // is created at runtime but then modified in authoring (and has has a + // new UI ID added) is handled. BranchActivityEntry uiid_match = null; BranchActivityEntry id_match = null; - Iterator iter = null; - if (sequenceActivity != null) { - if (sequenceActivity.getBranchEntries() != null) { - iter = sequenceActivity.getBranchEntries().iterator(); - } - } - else { - iter = ((ConditionGateActivity) branchingActivity).getOpeningGateBranchEntries().iterator(); - } - - if (iter != null) { + if (sequenceActivity.getBranchEntries() != null) { + Iterator iter = sequenceActivity.getBranchEntries().iterator(); while (uiid_match == null && iter.hasNext()) { BranchActivityEntry possibleEntry = (BranchActivityEntry) iter.next(); if (entryUIID.equals(possibleEntry.getEntryUIID())) { @@ -1510,7 +1753,8 @@ BranchActivityEntry entry = uiid_match != null ? uiid_match : id_match; - // Does it exist already? If it does, remove it from the "old" set (which is used for doing deletions later). + // Does it exist already? If it does, remove it from the "old" set + // (which is used for doing deletions later). oldbranchActivityEntryList.remove(entry); BranchCondition condition = extractCondition((Hashtable) details.get(WDDXTAGS.BRANCH_CONDITION), entry); @@ -1547,13 +1791,12 @@ entry.setGroup(group); entry.setCondition(condition); - if (sequenceActivity != null) { - if (sequenceActivity.getBranchEntries() == null) { - sequenceActivity.setBranchEntries(new HashSet()); - } - sequenceActivity.getBranchEntries().add(entry); - activityDAO.update(sequenceActivity); + + if (sequenceActivity.getBranchEntries() == null) { + sequenceActivity.setBranchEntries(new HashSet()); } + sequenceActivity.getBranchEntries().add(entry); + activityDAO.update(sequenceActivity); if (group != null) { groupingDAO.update(group); @@ -1583,7 +1826,8 @@ log .warn("Unexpected behaviour: condition supplied in WDDX packet has a different ID to matching branch activity entry in the database. Dropping old database condition." + " Old db condition " + condition + " new entry in WDDX " + conditionTable); - condition = null; // Hibernate should dispose of it automatically via the cascade + condition = null; // Hibernate should dispose of it + // automatically via the cascade } Integer conditionUIID = WDDXProcessor.convertToInteger(conditionTable, WDDXTAGS.CONDITION_UIID); Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java =================================================================== diff -u -r209087915bc219f430c282ad00e5d1e6462f9b5f -r09cdc04e21a3a583aafdd4972af3aecd2016dac4 --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 209087915bc219f430c282ad00e5d1e6462f9b5f) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 09cdc04e21a3a583aafdd4972af3aecd2016dac4) @@ -46,6 +46,8 @@ import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.BranchActivityEntry; import org.lamsfoundation.lams.learningdesign.BranchingActivity; +import org.lamsfoundation.lams.learningdesign.Competence; +import org.lamsfoundation.lams.learningdesign.CompetenceMapping; import org.lamsfoundation.lams.learningdesign.ComplexActivity; import org.lamsfoundation.lams.learningdesign.GateActivity; import org.lamsfoundation.lams.learningdesign.Group; @@ -57,6 +59,8 @@ import org.lamsfoundation.lams.learningdesign.ToolActivity; import org.lamsfoundation.lams.learningdesign.Transition; import org.lamsfoundation.lams.learningdesign.dao.hibernate.ActivityDAO; +import org.lamsfoundation.lams.learningdesign.dao.hibernate.CompetenceDAO; +import org.lamsfoundation.lams.learningdesign.dao.hibernate.CompetenceMappingDAO; import org.lamsfoundation.lams.learningdesign.dao.hibernate.GroupDAO; import org.lamsfoundation.lams.learningdesign.dao.hibernate.GroupingDAO; import org.lamsfoundation.lams.learningdesign.dao.hibernate.LearningDesignDAO; @@ -120,6 +124,8 @@ protected LicenseDAO licenseDAO; protected GroupingDAO groupingDAO; protected GroupDAO groupDAO; + protected CompetenceDAO competenceDAO; + protected CompetenceMappingDAO competenceMappingDAO; protected SystemToolDAO systemToolDAO; protected ILamsCoreToolService lamsCoreToolService; protected ILearningDesignService learningDesignService; @@ -159,6 +165,38 @@ } /** + * + * @return + */ + public CompetenceDAO getCompetenceDAO() { + return competenceDAO; + } + + /** + * + * @param competenceDAO + */ + public void setCompetenceDAO(CompetenceDAO competenceDAO) { + this.competenceDAO = competenceDAO; + } + + /** + * + * @return + */ + public CompetenceMappingDAO getCompetenceMappingDAO() { + return competenceMappingDAO; + } + + /** + * + * @param competenceMappingDAO + */ + public void setCompetenceMappingDAO(CompetenceMappingDAO competenceMappingDAO) { + this.competenceMappingDAO = competenceMappingDAO; + } + + /** * @param transitionDAO The transitionDAO to set */ public void setTransitionDAO(TransitionDAO transitionDAO) { @@ -811,11 +849,16 @@ newLearningDesign.setEditOverrideLock(false); // clear the live edit flag learningDesignDAO.insert(newLearningDesign); + updateDesignCompetences(originalLearningDesign, newLearningDesign, false); HashMap newActivities = updateDesignActivities(originalLearningDesign, newLearningDesign, 0, customCSV); updateDesignTransitions(originalLearningDesign, newLearningDesign, newActivities, 0); + // set first activity assumes that the transitions are all set up correctly. newLearningDesign.setFirstActivity(newLearningDesign.calculateFirstActivity()); newLearningDesign.setLearningDesignUIID(originalLearningDesign.getLearningDesignUIID()); + + updateCompetenceMappings(newLearningDesign.getCompetences(), newActivities); + return newLearningDesign; } @@ -878,12 +921,15 @@ // now dump the import design into our main sequence. Leave the first activity ui id for the design as it is. int uiidOffset = mainDesign.getMaxID().intValue(); + updateDesignCompetences(designToImport, mainDesign, true); HashMap newActivities = updateDesignActivities(designToImport, mainDesign, uiidOffset, customCSV); updateDesignTransitions(designToImport, mainDesign, newActivities, uiidOffset); mainDesign.setMaxID(LearningDesign.addOffset(designToImport.getMaxID(), uiidOffset)); mainDesign.setValidDesign(Boolean.FALSE); learningDesignDAO.update(mainDesign); + insertCompetenceMappings(mainDesign.getCompetences(), designToImport.getCompetences(), newActivities); + return mainDesign; } @@ -1149,6 +1195,139 @@ } /** + * Updates the competence information in the newLearningDesign based + * on the originalLearningDesign + * + * @param originalLearningDesign The LearningDesign to be copied + * @param newLearningDesign The copy of the originalLearningDesign + */ + public void updateDesignCompetences(LearningDesign originalLearningDesign, LearningDesign newLearningDesign, boolean insert) { + HashSet newCompeteces = new HashSet(); + + Set oldCompetences = originalLearningDesign.getCompetences(); + for (Competence competence : oldCompetences) { + Competence newCompetence = competence.createCopy(competence); + newCompetence.setLearningDesign(newLearningDesign); + + // check for existing competences to prevent duplicates + if (competenceDAO.getCompetence(newLearningDesign, newCompetence.getTitle()) == null) { + competenceDAO.saveOrUpdate(newCompetence); + } + newCompeteces.add(newCompetence); + } + + if (newLearningDesign.getCompetences() != null) { + if (!insert) { + newLearningDesign.getCompetences().clear(); + newLearningDesign.getCompetences().addAll(newCompeteces); + } + else { + // handle inserting sequences + for (Competence newCompetence : newCompeteces) { + boolean alreadyExistsInLD = false; + for (Competence existingCompetence : originalLearningDesign.getCompetences()) { + if (newCompetence.getTitle().equals(existingCompetence.getTitle())) { + alreadyExistsInLD = true; + break; + } + } + if (!alreadyExistsInLD) { + newLearningDesign.getCompetences().add(newCompetence); + } + } + } + + } + else { + newLearningDesign.setCompetences(newCompeteces); + } + + } + + public void insertCompetenceMappings(Set oldCompetences, Set newCompetences, + HashMap newActivities) { + + for (Integer activityKey : newActivities.keySet()) { + Activity activity = newActivities.get(activityKey); + if (activity.isToolActivity()) { + Set newCompetenceMappings = new HashSet(); + ToolActivity newToolActivity = (ToolActivity) activity; + if (newToolActivity.getCompetenceMappings() != null) { + for (CompetenceMapping competenceMapping : newToolActivity.getCompetenceMappings()) { + CompetenceMapping newMapping = new CompetenceMapping(); + newMapping.setToolActivity(newToolActivity); + + // Check if competence mapping title already exists as a competence in the original sequence + // If so, simply use the existing competence to map to. + if (oldCompetences != null && oldCompetences.size() > 0 + && getCompetenceFromSet(oldCompetences, competenceMapping.getCompetence().getTitle()) != null) { + newMapping.setCompetence(getCompetenceFromSet(oldCompetences, competenceMapping.getCompetence() + .getTitle())); + competenceMappingDAO.insert(newMapping); + newCompetenceMappings.add(newMapping); + } + // If competence was not already existing in the ld, add a new mappping + else if (newCompetences != null && newCompetences.size() > 0 + && getCompetenceFromSet(newCompetences, competenceMapping.getCompetence().getTitle()) != null) { + newMapping.setCompetence(getCompetenceFromSet(newCompetences, competenceMapping.getCompetence() + .getTitle())); + competenceMappingDAO.insert(newMapping); + newCompetenceMappings.add(newMapping); + } + } + } + newToolActivity.getCompetenceMappings().addAll(newCompetenceMappings); + } + } + } + + public Competence getCompetenceFromSet(Set competences, String title) { + Competence ret = null; + for (Competence competence : competences) { + if (competence.getTitle().equals(title)) { + ret = competence; + break; + } + } + return ret; + } + + /** + * Updates the competence information in the newLearningDesign based + * on the originalLearningDesign + * + * @param originalLearningDesign The LearningDesign to be copied + * @param newLearningDesign The copy of the originalLearningDesign + */ + public void updateCompetenceMappings(Set newCompetences, HashMap newActivities) { + for (Integer activityKey : newActivities.keySet()) { + Activity activity = newActivities.get(activityKey); + if (activity.isToolActivity()) { + Set newCompetenceMappings = new HashSet(); + ToolActivity newToolActivity = (ToolActivity) activity; + if (newToolActivity.getCompetenceMappings() != null) { + for (CompetenceMapping competenceMapping : newToolActivity.getCompetenceMappings()) { + CompetenceMapping newMapping = new CompetenceMapping(); + if (newCompetences != null) { + for (Competence newCompetence : newCompetences) { + if (competenceMapping.getCompetence().getTitle().equals(newCompetence.getTitle()) + && competenceMappingDAO.getCompetenceMapping(newToolActivity, newCompetence) == null) { + newMapping.setToolActivity(newToolActivity); + newMapping.setCompetence(newCompetence); + competenceMappingDAO.insert(newMapping); + newCompetenceMappings.add(newMapping); + } + } + } + } + } + newToolActivity.getCompetenceMappings().addAll(newCompetenceMappings); + //activityDAO.update(newToolActivity); + } + } + } + + /** * Determines the type of activity and returns a deep-copy of the same * * @param activity The object to be deep-copied