Index: lams_build/xsd/lams_ims_export_v1p1.xsd
===================================================================
diff -u
--- lams_build/xsd/lams_ims_export_v1p1.xsd (revision 0)
+++ lams_build/xsd/lams_ims_export_v1p1.xsd (revision f8729931f5e38872e6030ac3352b70826d1f1a55)
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: lams_central/web/toolcontent/learning-design-ims.xslt
===================================================================
diff -u -reb79a21f2f297559b5cf91266e21e75994033d3e -rf8729931f5e38872e6030ac3352b70826d1f1a55
--- lams_central/web/toolcontent/learning-design-ims.xslt (.../learning-design-ims.xslt) (revision eb79a21f2f297559b5cf91266e21e75994033d3e)
+++ lams_central/web/toolcontent/learning-design-ims.xslt (.../learning-design-ims.xslt) (revision f8729931f5e38872e6030ac3352b70826d1f1a55)
@@ -19,26 +19,28 @@
http://www.gnu.org/licenses/gpl.txt
-->
-
+
+
+
-
+
IMS Metadata
1.2
-
+
-
-
+
+
@@ -54,6 +56,9 @@
Learner
+
+
+
@@ -75,6 +80,7 @@
+
@@ -112,6 +118,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -124,7 +144,7 @@
-
+
@@ -133,15 +153,14 @@
-
-
+
@@ -159,7 +178,7 @@
-
+
@@ -179,7 +198,9 @@
-
+
+
+
@@ -196,7 +217,7 @@
-
+
@@ -227,7 +248,7 @@
-
+
@@ -245,7 +266,7 @@
-
+
@@ -257,31 +278,21 @@
-
+
-
+
+
LAMS Learning design sequence
-
-
-
-
-
-
-
-
-
-
-
@@ -301,7 +312,7 @@
-
+
URN:LAMS:-
@@ -318,10 +329,14 @@
+
+ -manifest
+
+
-
+
A--
Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java
===================================================================
diff -u -rb636ac0443171b69098dd1f9599bf2bd90c3ee42 -rf8729931f5e38872e6030ac3352b70826d1f1a55
--- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision b636ac0443171b69098dd1f9599bf2bd90c3ee42)
+++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision f8729931f5e38872e6030ac3352b70826d1f1a55)
@@ -182,11 +182,26 @@
private static final String IMS_TAG_FILE = "file";
private static final String IMS_ATTR_HREF = "href";
private static final String IMS_ATTR_REF = "ref";
+ private static final String IMS_TAG_PROPERTIES = "properties";
+ private static final String IMS_TAG_LOCPERS_PROPERTY = "locpers-property";
+ private static final String IMS_TAG_DATATYPE = "datatype";
+ private static final String IMS_ATTR_DATATYPE = "datatype";
+ private static final String IMS_TAG_INITIAL_VALUE = "initial-value";
+ private static final String IMS_TAG_CONDITIONS = "conditions";
+ private static final String IMS_TAG_IF = "if";
+ private static final String IMS_TAG_THEN = "then";
+ private static final String IMS_TAG_ELSE = "else";
+ private static final String IMS_TAG_IS = "is";
+ private static final String IMS_TAG_SHOW = "show";
+ private static final String IMS_TAG_HIDE = "hide";
+ private static final String IMS_TAG_PROPERTY_REF = "property-ref";
+ private static final String IMS_TAG_PROPERTY_VALUE = "property-value";
private static final String IMS_PREFIX_RESOURCE_IDENTIFIER = "R-";
private static final String IMS_PREFIX_ACTIVITY_REF = "A-";
private static final String IMS_PREFIX_COMPLEX_REF = "S-";
-
+ private static final String IMS_PREFIX_PROPERTY_REF = "P-";
+
//this is not IMS standard tag, temporarily use to gather all tools node list
private static final String IMS_TAG_TRANSITIONS = "transitions";
@@ -204,10 +219,14 @@
private static final String IMS_RESOURCES_FILE_NAME = "resources.xml";
private static final String XSLT_PARAM_TRANSITION_FILE = "transitionsFile";
private static final String IMS_TRANSITION_FILE_NAME = "transitions.xml";
-
+ private static final String XSLT_PARAM_PROPERTIES_FILE = "propertiesFile";
+ 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_ACTIIVTY_REF = "learning-activity-ref";
+ private static final String IMS_TAG_LEARING_ACTIVITY_REF = "learning-activity-ref";
private static final String IMS_TOOL_MAIN_OBJECT = "mainObject";
@@ -566,54 +585,93 @@
List transChildren = new ArrayList();
//create transitions DOM file
List sortedActList = getSortedActivities(ldDto);
- //remove activities inside complex activities, the IMS package does not need that.
- //I don't want to disturb getSortedActivities() method, so that I removed them here.
- Iterator iter = sortedActList.iterator();
- while(iter.hasNext()){
- AuthoringActivityDTO activityDTO = iter.next();
- if(activityDTO.getParentActivityID() != null)
- iter.remove();
+
+ // Need to know what activities are branching activities, so we can set up conditions for their child sequences
+ // 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) )
+ branchingActivityIds.add(actDto.getActivityID());
}
+ Document propertiesDom = new Document();
+ Element propertiesRoot = new Element(IMS_TAG_PROPERTIES);
+ List propertiesChildren = new ArrayList();
+
+ Document conditionsDom = new Document();
+ Element conditionsRoot = new Element(IMS_TAG_CONDITIONS);
+ List conditionsChildren = new ArrayList();
+
for (AuthoringActivityDTO actDto : sortedActList) {
log.debug("Export IMS: Put actitivies " + actDto.getActivityTitle() + "[" +actDto.getToolContentID()+"] into Transition tag.");
- Element ref = new Element(IMS_TAG_LEARING_ACTIIVTY_REF);
- 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());
- 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.SEQUENCE_ACTIVITY_TYPE))
- att = new Attribute(IMS_ATTR_REF, IMS_PREFIX_COMPLEX_REF + IMS_TAG_SEQUENCE + "-" + 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());
-
- ref.setAttribute(att);
- transChildren.add(ref);
+ // 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);
+ propertiesChildren.add(propertyConditions[0]);
+ conditionsChildren.add(propertyConditions[1]);
+ conditionsChildren.add(propertyConditions[2]);
+ conditionsChildren.add(propertyConditions[3]);
+ }
+
+ } 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());
+ 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());
+
+ Element ref = new Element(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));
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));
+ 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));
+ 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);
//transform
log.debug("Export IMS: Starting transform IMS XML by XSLT...");
@@ -629,14 +687,70 @@
}
-
+
+ /** Generate the nodes for a property and the related conditions. The first element is the property, which goes
+ * in the tag, the second through fourth elements are the if-then-else that makes up the condition
+ * and goes in the tag.
+ * @param activityId
+ * @return
+ */
+ private Element[] generatePropertyCondition(Long activityId, String learningActivityRefName) {
+ Element[] returnArray = new Element[4];
+
+ String propertyName = 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));
+ locpersProperty.setChildren(new ArrayList());
+ Element el = new Element(IMS_TAG_DATATYPE);
+ el.setAttribute(new Attribute(IMS_ATTR_DATATYPE, "boolean"));
+ locpersProperty.getChildren().add(el);
+ el = new Element(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));
+ is.getChildren().add(el);
+ el = new Element(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));
+ 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));
+ 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.
*
- * It considers the broken LD situation. A frist activity will always be first one, but others brokend sequence in this LD
- * sorted by randomly. In one brokend seuqence, all acitivities will sorted by transition.
+ * It considers the broken LD situation. A first activity will always be first one, but others in the broken sequence in this LD
+ * sorted by randomly. In one broken sequence, all activities will sorted by transition.
*
- * The reason to use lots "for" is Activity DTO does not contain next transition information. It has to be iterator all transtions or activities.
+ * The reason to use lots "for" is Activity DTO does not contain next transition information. It has to be iterator all transitions or activities.
*
* @param ldDto
* @return
@@ -647,15 +761,20 @@
List transList = ldDto.getTransitions();
Long firstActId = ldDto.getFirstActivityID();
- List activities =ldDto.getActivities();
-
- //put first activity into sorted list
- for (AuthoringActivityDTO activityDTO : activities) {
+ 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)){
sortedActList.add(activityDTO);
- break;
+ }else{
+ activities.put(activityDTO.getActivityID(), activityDTO);
}
}
+
List firstActList = new ArrayList();
//try find a sorted transition list.
@@ -672,13 +791,12 @@
sortedList.add(transitionDTO);
actId = transitionDTO.getToActivityID();
- //put next activity inot sorted list
- for (AuthoringActivityDTO activityDTO : activities) {
- if(activityDTO.getActivityID().equals(actId)){
- sortedActList.add(activityDTO);
- break;
- }
- }
+ //put next activity into sorted list
+ AuthoringActivityDTO activityDTO = activities.get(actId);
+ if ( activityDTO != null ) {
+ sortedActList.add(activityDTO);
+ activities.remove(actId);
+ }
find = true;
break;
}
@@ -690,26 +808,25 @@
//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) {
+ for (AuthoringActivityDTO act: activities.values()) {
boolean isFirst = true;
for (TransitionDTO tranDto : transList) {
- //there is some transtion to this act, it is not "head activity" then skip this act.
+ //there is some transition to this act, it is not "head activity" then skip this act.
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())){
- firstActList.add(actId);
actId = act.getActivityID();
- //put next activity inot sorted list
- for (AuthoringActivityDTO activityDTO : activities) {
- if(activityDTO.getActivityID().equals(actId)){
- sortedActList.add(activityDTO);
- break;
- }
- }
+ firstActList.add(actId);
+ //put next activity into sorted list
+ AuthoringActivityDTO activityDTO = activities.get(actId);
+ if ( activityDTO != null ) {
+ sortedActList.add(activityDTO);
+ activities.remove(actId);
+ }
break;
}
}
@@ -718,21 +835,8 @@
}
//there are some sole activities exist in this LD,append them into sorted list end.
- if(sortedActList.size() < activities.size()){
- for (AuthoringActivityDTO activityDTO : activities){
- boolean exist = false;
- for (AuthoringActivityDTO sortedAct : sortedActList) {
- if(sortedAct.getActivityID().equals(activityDTO.getActivityID())){
- exist = true;
- break;
- }
- }
- if(!exist)
- sortedActList.add(activityDTO);
-
- if(sortedActList.size() == activities.size())
- break;
- }
+ if(activities.size()>0){
+ sortedActList.addAll(activities.values());
}
return sortedActList;
}