Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/FlashMessage.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/HashtableUtils.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/LDWDDXValueObjectFactory.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/LDWDDXValueObjectStorer.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/WDDXProcessor.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/WDDXProcessorConversionException.java'.
Fisheye: No comparison available. Pass `N' to diff?
Fisheye: Tag fc76a4bb4e5abc614e15b642e4015295b2912c0a refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/util/WDDXTAGS.java'.
Fisheye: No comparison available. Pass `N' to diff?
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/FlashMessage.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/FlashMessage.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/FlashMessage.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+package org.lamsfoundation.lams.util.wddx;
+
+import java.io.Serializable;
+
+/**
+ * @author Manpreet Minhas
+ * This class represents the message sent by the server to the
+ * Flash client.
+ *
+ */
+public class FlashMessage implements Serializable {
+
+ /** Message type indicating that operation was
+ * unsuccessful due to some error on FLASH side.
+ * For example the WDDX packet contains a null value
+ */
+ public static final int ERROR = 1;
+
+ /**
+ * Message type indicating that operation failed
+ * due to some system eror. For example, the client
+ * was unable to serilaize the WDDX packet
+ */
+ public static final int CRITICAL_ERROR = 2;
+
+ /**
+ * Message type indicating that operation
+ * was executed successfully
+ */
+ public static final int OBJECT_MESSAGE = 3;
+
+ /** Usually the name of the method that was called by the flash */
+ private String messageKey;
+
+ /**
+ * The response to the flash's request. Normally a string either
+ * stating the error message or the WDDX packet
+ */
+ private Object messageValue;
+
+ /**
+ * Represents the type of message being sent to Flash. Can be one of
+ * the following values
+ *
+ * - ERROR
+ * - CRITICAL_ERROR
+ * - OBJECT_MESSAGE
+ *
+ */
+ private int messageType;
+
+ /** Minimal Constructor */
+ public FlashMessage(String messageKey, Object messageValue) {
+ this.messageKey = messageKey;
+ this.messageValue = messageValue;
+ this.messageType = OBJECT_MESSAGE;
+ }
+ /** Full Constructor*/
+ public FlashMessage(String messageKey, Object messageValue, int messageType) {
+ this.messageKey = messageKey;
+ this.messageValue = messageValue;
+ this.messageType = messageType;
+ }
+ public String getMessageKey() {
+ return messageKey;
+ }
+ public int getMessageType() {
+ return messageType;
+ }
+ public Object getMessageValue() {
+ return messageValue;
+ }
+ /**
+ * Return String representation of the message that will be sent to flash.
+ * @see java.lang.Object#toString()
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer(getClass().getName() + ": ");
+ sb.append("messageKey='" + getMessageKey() + "'; ");
+ sb.append("messageType='" + getMessageType()+"';");
+ sb.append("messageValue='" + getMessageValue() + "'; ");
+ return sb.toString();
+ }
+}
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/HashtableUtils.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/HashtableUtils.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/HashtableUtils.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+package org.lamsfoundation.lams.util.wddx;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * @author Manpreet Minhas
+ */
+public class HashtableUtils {
+
+ /*
+ * Takes a string (possibly null) and returns a not null string
+ */
+ public static String getValue( String possValue )
+ {
+ return ( possValue==null ? "" : possValue );
+ }
+
+ /*
+ * Takes a Long (possibly null) and returns a not null Long
+ */
+ public static Long getIdLong ( Long possValue )
+ {
+ return ( possValue==null ? WDDXTAGS.NUMERIC_NULL_VALUE_LONG : possValue );
+ }
+
+ /*
+ * Takes a Integer (possibly null) and returns a not null Integer
+ */
+ public static Integer getIdInteger ( Integer possValue )
+ {
+ return ( possValue==null ? WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER : possValue );
+ }
+
+ public static Date getIdDate(Date possValue){
+ return (possValue==null? WDDXTAGS.DATE_NULL_VALUE : possValue);
+ }
+
+ public static Boolean getBoolean(Boolean possValue){
+ return (possValue==null?WDDXTAGS.BOOLEAN_NULL_VALUE : possValue);
+ }
+
+ /**
+ * Helper function to retrieve dataset from Hashtable. As it is possible to
+ * receive object array inside a hashtable. Simply cast it to Collection
+ * will generate ClassCasting Exception. Therefore, we need to create this
+ * helper function.
+ *
+ * @param clientObj
+ * @param questionSet
+ * @return return vector of data
+ * @author Jacky Fang
+ */
+ public static Vector getCollectionDataFromHashTable(String identifier,Hashtable clientObj)
+ {
+ Vector dataSet = new Vector();
+ if(clientObj.get(identifier)instanceof Collection)
+ dataSet = (Vector)clientObj.get(identifier);
+ else if( clientObj.get(identifier)!=null)
+ dataSet.addAll(Arrays.asList((Object []) clientObj.get(identifier)));
+ return dataSet;
+ }
+
+
+
+
+
+
+
+}
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/LDWDDXValueObjectFactory.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/LDWDDXValueObjectFactory.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/LDWDDXValueObjectFactory.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,645 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+package org.lamsfoundation.lams.util.wddx;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.lamsfoundation.lams.learningdesign.Activity;
+import org.lamsfoundation.lams.learningdesign.ChosenGrouping;
+import org.lamsfoundation.lams.learningdesign.ComplexActivity;
+import org.lamsfoundation.lams.learningdesign.GateActivity;
+import org.lamsfoundation.lams.learningdesign.Grouping;
+import org.lamsfoundation.lams.learningdesign.GroupingActivity;
+import org.lamsfoundation.lams.learningdesign.LearningDesign;
+import org.lamsfoundation.lams.learningdesign.LearningLibrary;
+import org.lamsfoundation.lams.learningdesign.OptionsActivity;
+import org.lamsfoundation.lams.learningdesign.ParallelActivity;
+import org.lamsfoundation.lams.learningdesign.PermissionGateActivity;
+import org.lamsfoundation.lams.learningdesign.RandomGrouping;
+import org.lamsfoundation.lams.learningdesign.ScheduleGateActivity;
+import org.lamsfoundation.lams.learningdesign.SequenceActivity;
+import org.lamsfoundation.lams.learningdesign.SynchGateActivity;
+import org.lamsfoundation.lams.learningdesign.ToolActivity;
+import org.lamsfoundation.lams.learningdesign.Transition;
+import org.lamsfoundation.lams.learningdesign.dao.hibernate.ActivityDAO;
+import org.lamsfoundation.lams.tool.Tool;
+import org.lamsfoundation.lams.tool.dao.hibernate.ToolDAO;
+
+
+
+
+/**
+ * @author Manpreet Minhas
+ *
+ * When sending a number as a value within a hashtable, we have to either put a proper
+ * value in the hashtable (ie not null) or leave out that tag all together. On the
+ * flash end, if we leave out the tag, it will return nothing when that tag is checked,
+ * but it won't cause an error. Therefore when sending ids, if the id doesn't exist
+ * (value is null), don't add that tag to the hashtable, and that tag will be left out
+ * of the packet.
+ */
+public class LDWDDXValueObjectFactory {
+
+ static LDWDDXValueObjectFactory factory = null;
+
+ protected ActivityDAO activityDAO;
+ protected ToolDAO toolDAO;
+
+ public LDWDDXValueObjectFactory(){
+
+ }
+ /**
+ * Constructor
+ *
+ * @param activityDAO The activityDAO to set
+ * @param toolDAO The toolDAO to set
+ */
+ public LDWDDXValueObjectFactory(ActivityDAO activityDAO,ToolDAO toolDAO){
+ this.activityDAO = activityDAO;
+ this.toolDAO = toolDAO;
+ }
+ /**
+ * @return LDWDDXValueObjectFactory Returns an instance of LDWDDXValueObjectFactory
+ */
+ public static LDWDDXValueObjectFactory getInstance()
+ {
+ return (factory==null? new LDWDDXValueObjectFactory():factory);
+ }
+
+ /**
+ * Returns the list of all Learning Libraries
+ * @param learningLibraries List of Learning Libraries
+ * @return Hashtable
+ */
+ public Hashtable requestLearningLibraryList(Collection learningLibraries){
+ Hashtable libraryList = new Hashtable();
+
+ libraryList.put(WDDXTAGS.OBJECT_TYPE,LearningLibrary.LIBRARY_LIST_OBJECT);
+ libraryList.put(WDDXTAGS.TITLE,"Learning Libraries");
+ libraryList.put(WDDXTAGS.DESCRIPTION,"All available system libraries");
+
+ Vector libraries = new Vector();
+ if(learningLibraries!=null){
+ Iterator iter = learningLibraries.iterator();
+ while(iter.hasNext()){
+ LearningLibrary library = (LearningLibrary)iter.next();
+ Hashtable output = buildLearningLibraryObject(library);
+ libraries.add(output);
+ }
+ }
+ libraryList.put(WDDXTAGS.LIB_PACKAGE,libraries);
+ return libraryList;
+ }
+
+ /**
+ * Converts the LearningLibrary object into Hashtable
+ * with Key as the attribute_name and value as value as
+ * the attribute_value from the underlying database
+ *
+ * @param library The LearningLibrary to be converted
+ * @return Hashtable
+ */
+ private Hashtable buildLearningLibraryObject(LearningLibrary library){
+ Hashtable libraries = new Hashtable();
+
+ Long libraryID = library.getLearningLibraryId();
+
+ libraries.put(WDDXTAGS.LEARNING_LIBRARY_ID,libraryID);
+
+ libraries.put(WDDXTAGS.DESCRIPTION,
+ (library.getDescription()!=null?library.getDescription():WDDXTAGS.STRING_NULL_VALUE));
+
+ libraries.put(WDDXTAGS.TITLE,
+ (library.getTitle()!=null?library.getTitle():WDDXTAGS.STRING_NULL_VALUE));
+
+ libraries.put(WDDXTAGS.CREATION_DATE,
+ (library.getCreateDateTime()!=null?library.getCreateDateTime():WDDXTAGS.DATE_NULL_VALUE));
+
+ Collection coll = activityDAO.getActivitiesByLibraryID(libraryID);
+ Vector templateActivities = new Vector();
+ if(coll!=null){
+ Iterator iter = coll.iterator();
+ while (iter.hasNext()){
+ Object object = iter.next();
+ Hashtable output = buildActivityObject(object);
+ addAuthoringURLS(object,output);
+ templateActivities.add(output);
+ }
+ }
+ libraries.put(WDDXTAGS.LIB_ACTIVITIES,templateActivities);
+ return libraries;
+ }
+
+ /**
+ * In case the activity object is of type ToolActivity,
+ * this function adds tool specific information required by the
+ * authoring enviornment such as Tool's Authoring Url's.
+ *
+ * @param activity The activity object to be parsed
+ * @param output The hashtable to be updated
+ */
+ private void addAuthoringURLS(Object activity,Hashtable output){
+ if (activity.getClass().getName().equals("org.lamsfoundation.lams.learningdesign.ToolActivity")){
+ ToolActivity toolActivity = (ToolActivity)activity;
+ Tool tool =toolActivity.getTool();
+ Hashtable toolOutput = buildToolObject(tool);
+ output.put(WDDXTAGS.AUTH_URL,toolOutput);
+ }
+
+ }
+ /**
+ * Converts the Tool object into Hashtable
+ * with Key as the attribute_name and value as value as
+ * the attribute_value from the underlying database
+ *
+ * @param tool The Tool to be converted
+ * @return Hashtable
+ */
+ private Hashtable buildToolObject(Tool tool){
+ Hashtable table = new Hashtable();
+ table.put(WDDXTAGS.OBJECT_TYPE,"Tool");
+ table.put(WDDXTAGS.TOOL_ID,tool.getToolId());
+ table.put(WDDXTAGS.TOOL_DISPLAY_NAME,tool.getToolDisplayName());
+ table.put(WDDXTAGS.TOOl_AUTH_URL,tool.getAuthorUrl());
+ return table;
+ }
+ /**
+ * Determines the type of activity and adds
+ * activity specific attributes
+ *
+ * @param activities
+ * @param activity
+ */
+ private void processActivityType(Hashtable activities, Object activity){
+ String className = activity.getClass().getName();
+ if(activity instanceof GroupingActivity)
+ buildGroupingActivityObject(activities,activity);
+ else if(activity instanceof ToolActivity)
+ buildToolActivity(activities,(ToolActivity)activity);
+ else if(activity instanceof GateActivity)
+ buildGateActivityObject(activities,activity);
+ else
+ buildComplexActivityObject(activities,activity);
+ }
+
+ /**
+ * Converts the Activity object into Hashtable
+ * with Key as the attribute_name and value as value as
+ * the attribute_value from the underlying database
+ *
+ * @param objActivity The object to be converted
+ * @return Hashtable
+ */
+ private Hashtable buildActivityObject(Object objActivity){
+ Hashtable activities = new Hashtable();
+
+ activities.put(WDDXTAGS.OBJECT_TYPE,"Activity");
+
+ processActivityType(activities,objActivity);
+
+ Activity activity =(Activity)objActivity;
+
+ activities.put(WDDXTAGS.ACTIVITY_ID,activity.getActivityId());
+
+ activities.put(WDDXTAGS.ACTIVITY_UIID,
+ (activity.getActivityUIID()!=null?activity.getActivityUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.DESCRIPTION,
+ (activity.getDescription()!=null?activity.getDescription():WDDXTAGS.STRING_NULL_VALUE));
+
+ activities.put(WDDXTAGS.TITLE,
+ (activity.getTitle()!=null?activity.getTitle():WDDXTAGS.STRING_NULL_VALUE));
+
+ activities.put(WDDXTAGS.HELP_TEXT,
+ (activity.getHelpText()!=null?activity.getHelpText():WDDXTAGS.STRING_NULL_VALUE));
+
+ activities.put(WDDXTAGS.XCOORD,
+ (activity.getXcoord()!=null?activity.getXcoord():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.YCOORD,
+ (activity.getYcoord()!=null?activity.getYcoord():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.PARENT_ACTIVITY_ID,
+ (activity.getParentActivity()!=null?activity.getParentActivity().getActivityId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ activities.put(WDDXTAGS.PARENT_UIID,
+ (activity.getParentActivity()!=null?activity.getParentActivity().getActivityUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.ACTIVITY_TYPE_ID,
+ (activity.getActivityTypeId()!=null?activity.getActivityTypeId():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.GROUPING_ID,
+ (activity.getGrouping()!=null?activity.getGrouping().getGroupingId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ activities.put(WDDXTAGS.GROUPING_UIID,
+ (activity.getGrouping()!=null?activity.getGrouping().getGroupingUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.DEFINE_LATER,activity.getDefineLater());
+
+ activities.put(WDDXTAGS.RUN_OFFLINE,activity.getRunOffline());
+
+ activities.put(WDDXTAGS.LEARNING_DESIGN_ID,
+ (activity.getLearningDesign()!=null?activity.getLearningDesign().getLearningDesignId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ activities.put(WDDXTAGS.LEARNING_LIBRARY_ID,
+ (activity.getLearningLibrary()!=null?activity.getLearningLibrary().getLearningLibraryId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ if(activity.getCreateDateTime()!=null)
+ activities.put(WDDXTAGS.CREATION_DATE,activity.getCreateDateTime());
+
+ activities.put(WDDXTAGS.OFFLINE_INSTRUCTIONS,
+ (activity.getOfflineInstructions()!=null?activity.getOfflineInstructions():WDDXTAGS.STRING_NULL_VALUE));
+
+ if(activity.getLibraryActivityUiImage()!=null)
+ activities.put(WDDXTAGS.LIBRARY_IMAGE,activity.getLibraryActivityUiImage());
+
+ activities.put(WDDXTAGS.LIBRARY_ACTIVITY,
+ (activity.getLibraryActivity()!=null?activity.getLibraryActivity().getActivityId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ return activities;
+ }
+ /**
+ * This function populates the hashtable to be sent to FLASH
+ * with all the information realted to the GroupingActivity.
+ * A GroupingActivity is always associated with Grouping
+ * (Chosen or Random)so it includes that information as well.
+ *
+ * @param activities
+ * @param activity
+ */
+ private void buildGroupingActivityObject(Hashtable activities, Object activity){
+
+ GroupingActivity groupingActivity = (GroupingActivity)activity;
+ Grouping grouping = groupingActivity.getCreateGrouping();
+ Integer groupingType = grouping.getGroupingTypeId();
+
+ Hashtable groupingTable = null;
+ if(groupingType==Grouping.CHOSEN_GROUPING_TYPE)
+ groupingTable = addChosenGroupingAttributes((ChosenGrouping)grouping);
+ else
+ groupingTable = addRandomGroupingAttributes((RandomGrouping)grouping);
+
+ groupingTable.put(WDDXTAGS.MAX_NUMBER_OF_GROUPS,grouping.getMaxNumberOfGroups());
+ groupingTable.put(WDDXTAGS.GROUPING_UIID,grouping.getGroupingUIID());
+
+ activities.put(WDDXTAGS.CREATE_GROUPING_ID,grouping.getGroupingId());
+ activities.put(WDDXTAGS.CREATE_GROUPING_UIID,grouping.getGroupingUIID());
+ activities.put(WDDXTAGS.GROUPING,groupingTable);
+
+
+ }
+ /**
+ * As of now there are no additional attributes defined for
+ * ChosenGrouping, so leaving this function blank. More attributes
+ * would be added later on
+ *
+ * @param chosenGrouping The Grouping object whose values have to be
+ * populated into the hashtable
+ * @return Hashtable The populated hashtable to be passed on to FLASH
+ */
+ private Hashtable addChosenGroupingAttributes(ChosenGrouping chosenGrouping){
+ return new Hashtable();
+ }
+ /**
+ * This function adds RandomGrouping specific attributes to the
+ * hashtable to be passed on to FLASH
+ *
+ * @param randomGrouping The Grouping object whose values have to be
+ * populated into the hashtable
+ * @return Hashtable The populated hashtable to be passed on to FLASH
+ */
+ private Hashtable addRandomGroupingAttributes(RandomGrouping randomGrouping){
+ Hashtable groupingTable = new Hashtable();
+ groupingTable.put(WDDXTAGS.NUMBER_OF_GROUPS,randomGrouping.getNumberOfGroups());
+ groupingTable.put(WDDXTAGS.LEARNERS_PER_GROUP,randomGrouping.getLearnersPerGroup());
+ return groupingTable;
+ }
+
+
+ /**
+ * Adds ToolActivity specific attributes
+ * @param activities
+ * @param toolActivity
+ */
+ private void buildToolActivity(Hashtable activities, ToolActivity toolActivity){
+
+ activities.put(WDDXTAGS.ORDER_ID,
+ (toolActivity.getOrderId()!=null?toolActivity.getOrderId():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+ if(toolActivity.getTool()!=null)
+ activities.put(WDDXTAGS.TOOL_ID,toolActivity.getTool().getToolId());
+ if(toolActivity.getToolContentId()!=null)
+ activities.put(WDDXTAGS.TOOL_CONTENT_ID,toolActivity.getToolContentId());
+ }
+ /**
+ * Adds OptionsActivity specific attributes
+ * @param activities
+ * @param optActivity
+ */
+ private void buildOptionsActivityObject(Hashtable activities, OptionsActivity optActivity){
+
+ if(optActivity.getMaxNumberOfOptions()!=null)
+ activities.put(WDDXTAGS.MAX_OPTIONS,optActivity.getMaxNumberOfOptions());
+
+ if(optActivity.getMinNumberOfOptions()!=null)
+ activities.put(WDDXTAGS.MIN_OPTIONS,optActivity.getMinNumberOfOptions());
+
+ activities.put(WDDXTAGS.OPTIONS_INSTRUCTIONS,
+ (optActivity.getOptionsInstructions()!=null?optActivity.getOptionsInstructions():WDDXTAGS.STRING_NULL_VALUE));
+
+ Iterator iter = optActivity.getActivities().iterator();
+ addChildActivities(activities,iter);
+ }
+ /**
+ * TODO As of now SequenceActivity has no additional attributes of its own.
+ * So leaving this function empty for now. In case it is decided that
+ * this activity will have no additional attributes, we have to get rid
+ * of this function
+ *
+ * @param activities
+ * @param sequenceActivity
+ */
+ private void buildSequenceActivityObject(Hashtable activities,SequenceActivity sequenceActivity){
+
+ }
+
+ /**
+ * TODO As of now ParallelActivity has no additional attributes of its own.
+ * So leaving this function empty for now. In case it is decided that
+ * this activity will have no additional attributes, we have to get rid
+ * of this function
+ *
+ * @param activities
+ * @param parallelActivity
+ */
+ private void buildParallelActivityObject(Hashtable activities,ParallelActivity parallelActivity){
+
+ }
+ /**
+ * Adds ScheduleGateActivity specific attributes
+ * @param activities
+ * @param schActivity
+ */
+ private void buildScheduleGateActivityObject(Hashtable activities, ScheduleGateActivity schActivity){
+
+ if(schActivity.getGateEndTimeOffset()!=null)
+ activities.put(WDDXTAGS.GATE_END_OFFSET,schActivity.getGateEndTimeOffset());
+
+ if(schActivity.getGateStartTimeOffset()!=null)
+ activities.put(WDDXTAGS.GATE_START_OFFSET,schActivity.getGateStartTimeOffset());
+
+ activities.put(WDDXTAGS.GATE_END_DATE,
+ (schActivity.getGateEndDateTime()!=null?schActivity.getGateEndDateTime():WDDXTAGS.DATE_NULL_VALUE));
+
+ activities.put(WDDXTAGS.GATE_START_DATE,
+ (schActivity.getGateStartDateTime()!=null?schActivity.getGateStartDateTime():WDDXTAGS.DATE_NULL_VALUE));
+ }
+ /**
+ * Adds GateActivity specific attributes
+ * @param activities
+ * @param activity
+ */
+ private void buildGateActivityObject(Hashtable activities, Object activity){
+
+ if(activity instanceof PermissionGateActivity)
+ buildPermissionGateActivityObject(activities,(PermissionGateActivity)activity);
+ else if(activity instanceof SynchGateActivity)
+ buildSynchGateActivityObject(activities,(SynchGateActivity)activity);
+ else
+ buildScheduleGateActivityObject(activities,(ScheduleGateActivity)activity);
+
+ GateActivity gateActivity = (GateActivity)activity;
+
+ activities.put(WDDXTAGS.GATE_ACTIVITY_LEVEL_ID,
+ (gateActivity.getGateActivityLevelId()!=null?gateActivity.getGateActivityLevelId():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ activities.put(WDDXTAGS.GATE_OPEN,
+ (gateActivity.getGateOpen()!=null?gateActivity.getGateOpen():WDDXTAGS.BOOLEAN_NULL_VALUE));
+ }
+ private void buildPermissionGateActivityObject(Hashtable activities,PermissionGateActivity permissionGateActivity){
+
+ }
+ private void buildSynchGateActivityObject(Hashtable activities,SynchGateActivity synchGateActivity){
+
+ }
+
+ /**
+ * Adds ComplexActivity specific attributes
+ * @param activities
+ * @param activity
+ */
+ private void buildComplexActivityObject(Hashtable activities, Object activity){
+
+ if(activity instanceof OptionsActivity)
+ buildOptionsActivityObject(activities,(OptionsActivity)activity);
+ else if(activity instanceof SequenceActivity)
+ buildSequenceActivityObject(activities,(SequenceActivity)activity);
+ else
+ buildParallelActivityObject(activities,(ParallelActivity)activity);
+
+ ComplexActivity complexActivity = (ComplexActivity)activity;
+ Iterator iter = complexActivity.getActivities().iterator();
+ addChildActivities(activities,iter);
+ }
+ /**
+ * @param activities
+ * @param iter
+ */
+ private void addChildActivities(Hashtable activities,Iterator iter){
+ Vector childActivities = new Vector();
+ while(iter.hasNext()){
+ Object object = iter.next();
+ childActivities.add(buildActivityObject(object));
+ }
+ activities.put(WDDXTAGS.CHILD_ACTIVITIES,childActivities);
+ }
+ /**
+ * Converts the Transition object into Hashtable
+ * with Key as the attribute_name and value as value as
+ * the attribute_value from the underlying database
+ *
+ * @param trans
+ * @return Hashtable
+ */
+ private Hashtable buildTransitionObject(Transition trans){
+ Hashtable transitions = new Hashtable();
+
+ transitions.put(WDDXTAGS.TRANSITION_ID,trans.getTransitionId());
+
+ transitions.put(WDDXTAGS.TRANSITION_UIID,
+ (trans.getTransitionUIID()!=null?trans.getTransitionUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ if(trans.getDescription()!=null)
+ transitions.put(WDDXTAGS.DESCRIPTION,trans.getDescription());
+
+ if(trans.getTitle()!=null)
+ transitions.put(WDDXTAGS.TITLE,trans.getTitle());
+
+ transitions.put(WDDXTAGS.TRANSITION_TO,
+ (trans.getToActivity()!=null?trans.getToActivity().getActivityId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ transitions.put(WDDXTAGS.TRANSITION_FROM,
+ (trans.getFromActivity()!=null?trans.getFromActivity().getActivityId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ transitions.put(WDDXTAGS.LEARNING_DESIGN_ID,
+ (trans.getLearningDesign()!=null?trans.getLearningDesign().getLearningDesignId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ if(trans.getCreateDateTime()!=null)
+ transitions.put(WDDXTAGS.CREATION_DATE,trans.getCreateDateTime());
+
+ transitions.put(WDDXTAGS.TO_ACTIVITY_UIID,
+ (trans.getToUIID()!=null?trans.getToUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ transitions.put(WDDXTAGS.FROM_ACTIVITY_UIID,
+ (trans.getFromUIID()!=null?trans.getFromUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ return transitions;
+ }
+
+ /**
+ * Returns the list of all availabe Learning Designs
+ * @param learningDesigns
+ * @return Hashtable
+ */
+ public Hashtable requestLearningDesignList(Collection learningDesigns){
+ Hashtable designList = new Hashtable();
+
+ designList.put(WDDXTAGS.OBJECT_TYPE,"LearningDesignList");
+ designList.put(WDDXTAGS.TITLE,"Learning Designs");
+ designList.put(WDDXTAGS.DESCRIPTION,"All available Learning Designs");
+
+ Vector designs = new Vector();
+ if(learningDesigns!=null){
+ Iterator iter = learningDesigns.iterator();
+ while(iter.hasNext()){
+ LearningDesign design = (LearningDesign)iter.next();
+ Hashtable output = buildLearningDesignObject(design);
+ designs.add(output);
+ }
+ }
+ designList.put(WDDXTAGS.DESIGN_PACKAGE,designs);
+ return designList;
+ }
+ /**
+ * Converts the LearningDesign object into Hashtable
+ * with Key as the attribute_name and value as value as
+ * the attribute_value from the underlying database
+ *
+ * @param design The LearningDesign to be converted
+ * @return Hashtable
+ */
+ public Hashtable buildLearningDesignObject(LearningDesign design){
+ Hashtable designs = new Hashtable();
+
+ designs.put(WDDXTAGS.OBJECT_TYPE,LearningDesign.DESIGN_OBJECT);
+
+ designs.put(WDDXTAGS.LEARNING_DESIGN_ID,
+ (design.getLearningDesignId()!=null?design.getLearningDesignId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ designs.put(WDDXTAGS.LEARNING_DESIGN_UIID,
+ (design.getLearningDesignUIID()!=null?design.getLearningDesignUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ designs.put(WDDXTAGS.DESCRIPTION,
+ (design.getDescription()!=null?design.getDescription():WDDXTAGS.STRING_NULL_VALUE));
+
+ designs.put(WDDXTAGS.TITLE,
+ (design.getTitle()!=null?design.getTitle():WDDXTAGS.STRING_NULL_VALUE));
+
+ designs.put(WDDXTAGS.FIRST_ACTIVITY_ID,
+ (design.getFirstActivity()!=null?design.getFirstActivity().getActivityId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ designs.put(WDDXTAGS.FIRST_ACTIVITY_UIID,
+ (design.getFirstActivity()!=null?design.getFirstActivity().getActivityUIID():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ designs.put(WDDXTAGS.MAX_ID,
+ (design.getMaxId()!=null?design.getMaxId():WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER));
+
+ designs.put(WDDXTAGS.VALID_DESIGN,design.getValidDesign());
+
+ designs.put(WDDXTAGS.READ_ONLY,design.getReadOnly());
+
+ if(design.getDateReadOnly()!=null)
+ designs.put(WDDXTAGS.DATE_READ_ONLY,design.getDateReadOnly());
+
+ designs.put(WDDXTAGS.USER_ID,design.getUser().getUserId());
+
+
+ designs.put(WDDXTAGS.HELP_TEXT,
+ (design.getHelpText()!=null?design.getHelpText():WDDXTAGS.STRING_NULL_VALUE));
+
+ designs.put(WDDXTAGS.VERSION,
+ (design.getVersion()!=null?design.getVersion():WDDXTAGS.STRING_NULL_VALUE));
+
+ designs.put(WDDXTAGS.PARENT_DESIGN_ID,
+ (design.getParentLearningDesign()!=null?design.getParentLearningDesign().getLearningDesignId():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ designs.put(WDDXTAGS.WORKSPACE_FOLDER_ID,design.getWorkspaceFolder().getWorkspaceFolderId());
+
+ designs.put(WDDXTAGS.DURATION,
+ (design.getDuration()!=null?design.getDuration():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ designs.put(WDDXTAGS.LICENCE_ID,
+ (design.getLicense()!=null?design.getLicense().getLicenseID():WDDXTAGS.NUMERIC_NULL_VALUE_LONG));
+
+ designs.put(WDDXTAGS.LICENSE_TEXT,
+ (design.getLicenseText()!=null?design.getLicenseText():WDDXTAGS.STRING_NULL_VALUE));
+
+ Collection coll = design.getActivities();
+ HashSet parentActivities = new HashSet();
+ Iterator iter =null;
+ if(coll!=null){
+ iter = coll.iterator();
+ while (iter.hasNext()){
+ Activity activity = (Activity)iter.next();
+ if(activity.getParentActivity()==null){
+ parentActivities.add(activity);
+ }
+ }
+ }
+ iter = parentActivities.iterator();
+ Vector activities = new Vector();
+ while(iter.hasNext()){
+ Object object = iter.next();
+ Hashtable output = buildActivityObject(object);
+ activities.add(output);
+ }
+ designs.put(WDDXTAGS.ACTIVITIES,activities);
+
+ coll = design.getTransitions();
+ Vector transitions = new Vector();
+ if(coll!=null){
+ iter = coll.iterator();
+ while (iter.hasNext()){
+ Transition trans =(Transition) iter.next();
+ Hashtable output = buildTransitionObject(trans);
+ transitions.add(output);
+ }
+ }
+ designs.put(WDDXTAGS.TRANSITIONS,transitions);
+
+ return designs;
+ }
+}
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/LDWDDXValueObjectStorer.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/LDWDDXValueObjectStorer.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/LDWDDXValueObjectStorer.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,832 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+package org.lamsfoundation.lams.util.wddx;
+
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.lamsfoundation.lams.learningdesign.Activity;
+import org.lamsfoundation.lams.learningdesign.ChosenGrouping;
+import org.lamsfoundation.lams.learningdesign.ComplexActivity;
+import org.lamsfoundation.lams.learningdesign.GateActivity;
+import org.lamsfoundation.lams.learningdesign.Grouping;
+import org.lamsfoundation.lams.learningdesign.GroupingActivity;
+import org.lamsfoundation.lams.learningdesign.LearningDesign;
+import org.lamsfoundation.lams.learningdesign.LearningLibrary;
+import org.lamsfoundation.lams.learningdesign.License;
+import org.lamsfoundation.lams.learningdesign.OptionsActivity;
+import org.lamsfoundation.lams.learningdesign.ParallelActivity;
+import org.lamsfoundation.lams.learningdesign.PermissionGateActivity;
+import org.lamsfoundation.lams.learningdesign.RandomGrouping;
+import org.lamsfoundation.lams.learningdesign.ScheduleGateActivity;
+import org.lamsfoundation.lams.learningdesign.SequenceActivity;
+import org.lamsfoundation.lams.learningdesign.SynchGateActivity;
+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.GroupingDAO;
+import org.lamsfoundation.lams.learningdesign.dao.hibernate.LearningDesignDAO;
+import org.lamsfoundation.lams.learningdesign.dao.hibernate.LearningLibraryDAO;
+import org.lamsfoundation.lams.learningdesign.dao.hibernate.LicenseDAO;
+import org.lamsfoundation.lams.tool.Tool;
+import org.lamsfoundation.lams.tool.dao.hibernate.ToolDAO;
+import org.lamsfoundation.lams.usermanagement.User;
+import org.lamsfoundation.lams.usermanagement.WorkspaceFolder;
+import org.lamsfoundation.lams.usermanagement.dao.hibernate.UserDAO;
+import org.lamsfoundation.lams.usermanagement.dao.hibernate.WorkspaceFolderDAO;
+/**
+ * @author Manpreet Minhas
+ *
+ * This class is used to save the WDDX information into the Database.
+ * The WDDX packet sent by FLASH mainly consists of information stored
+ * in key-value pairs in a Hashtable. We check the existence of a
+ * particular key and if present we populate the corresponding object
+ * with its value and then finally persist into the database.
+ *
+ */
+public class LDWDDXValueObjectStorer {
+
+ static LDWDDXValueObjectStorer storer = null;
+ protected UserDAO userDAO = null;
+ protected LearningDesignDAO learningDesignDAO = null;
+ protected ActivityDAO activityDAO =null;
+ protected WorkspaceFolderDAO workspaceFolderDAO = null;
+ protected LearningLibraryDAO learningLibraryDAO = null;
+ protected LicenseDAO licenseDAO;
+ protected GroupingDAO groupingDAO;
+ protected ToolDAO toolDAO;
+
+ public LDWDDXValueObjectStorer(){
+
+ }
+
+ public LDWDDXValueObjectStorer(LearningDesignDAO learningDesignDAO,LearningLibraryDAO learningLibraryDAO, UserDAO userDAO, ActivityDAO activityDAO,WorkspaceFolderDAO workspaceFolderDAO,LicenseDAO licenseDAO,GroupingDAO groupingDAO){
+ this.learningDesignDAO = learningDesignDAO;
+ this.learningLibraryDAO = learningLibraryDAO;
+ this.userDAO = userDAO;
+ this.activityDAO = activityDAO;
+ this.workspaceFolderDAO = workspaceFolderDAO;
+ this.licenseDAO = licenseDAO;
+ this.groupingDAO = groupingDAO;
+ }
+ /**
+ * @return LDWDDXValueObjectStorer Instance of LDWDDXValueObjectStorer
+ */
+ public static LDWDDXValueObjectStorer getInstance()
+ {
+ return (storer==null? new LDWDDXValueObjectStorer():storer);
+ }
+
+ /**
+ * This function creates a new LearningDesign object or updates
+ * and existing design depending upon the information provided by FLASH
+ * and persists it in the database.
+ *
+ * @param table Hashtable populated with data from the WDDX packet
+ * @return Long learning_design_id of the design updated/saved
+ */
+ public Long processLearningDesign(Hashtable table)throws Exception{
+ Long learning_design_id = null;
+ Long oldDesignID=null;
+ LearningDesign learningDesign = null;
+ boolean update = false;
+ /*
+ * If the hastable already contains the key LEARNING_DESIGN_ID
+ * this means its a request to update an existing design otherwise
+ * it is a request to store a new LearningDesign
+ * */
+ if(table.containsKey(WDDXTAGS.LEARNING_DESIGN_ID)){
+ update = true;
+ learning_design_id = WDDXProcessor.convertToLong("learning_design_id",table.get(WDDXTAGS.LEARNING_DESIGN_ID));
+ learningDesign = learningDesignDAO.getLearningDesignById(learning_design_id);
+ if(learningDesign==null)
+ throw new Exception("Learning Design with the given learning_design_id " +
+ learning_design_id + " doesn't exists. Update Failed!!");
+
+ }else
+ learningDesign = new LearningDesign();
+
+ boolean readOnly = (WDDXProcessor.convertToBoolean("readOnly",table.get(WDDXTAGS.READ_ONLY))).booleanValue();
+ if(readOnly){
+ throw new Exception("This design is locked, you cannot save or update it.\n" +
+ "Please click on File | Save as... and rename it to save it");
+ }
+ if(!table.containsKey(WDDXTAGS.FIRST_ACTIVITY_UIID))
+ throw new Exception("Mandatory Field first_id is missing");
+
+ Integer firstID = WDDXProcessor.convertToInteger("first_activity_ui_id",table.get(WDDXTAGS.FIRST_ACTIVITY_UIID));
+
+ updateLearningDesign(table,learningDesign);
+ if(update){
+ learningDesignDAO.update(learningDesign);
+ }
+ else{
+ learningDesignDAO.insert(learningDesign);
+ updateDesignActivities(table,learningDesign);
+ }
+ /** The first activity of the design would be calculated only if
+ * it is a valid design */
+ if(learningDesign.getValidDesign().booleanValue())
+ calculateFirstActivity(firstID,learningDesign);
+ return learningDesign.getLearningDesignId();
+ }
+ /**
+ * This function updates the LearningDesign object with activity information
+ * from the FLASH.
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @param learningDesign The LearningDesign object to be updated
+ * @throws Exception
+ */
+ private void updateDesignActivities(Hashtable table,LearningDesign learningDesign)throws Exception{
+ Vector activities =(Vector)table.get(WDDXTAGS.ACTIVITIES);
+ Iterator iter = activities.iterator();
+ HashSet designActivities = new HashSet();
+ while(iter.hasNext()){
+ Hashtable activity =(Hashtable)iter.next();
+ activity.put(WDDXTAGS.LEARNING_DESIGN_ID,learningDesign.getLearningDesignId());
+ designActivities.add(processActivity(activity,learningDesign));
+ }
+ learningDesign.setActivities(designActivities);
+ learningDesignDAO.update(learningDesign);
+ }
+ /**
+ * This method compares the first_id sent by the Flash to the
+ * one calculated manually by the server. If everything goes well
+ * both these should be the same but if there is a conflict an
+ * exception is thrown.
+ *
+ * @param firstID The activity_ui_id of the first activity sent by flash
+ * @param design The design for whome the first activity is being calculated
+ * @throws Exception
+ */
+ private void calculateFirstActivity(Integer firstID, LearningDesign design)throws Exception{
+ Activity flashFirstActivity = activityDAO.getActivityByUIID(firstID,design);
+ Activity designFirstActivity = design.calculateFirstActivity();
+ if(flashFirstActivity.getActivityId()!=designFirstActivity.getActivityId())
+ throw new Exception ("First Activity Conflict. We have two first activities here");
+ design.setFirstActivity(flashFirstActivity);
+ }
+ private void updateDesignTransitions(Hashtable table,LearningDesign learningDesign)throws Exception{
+ if(table.containsKey(WDDXTAGS.TRANSITIONS)){
+ Vector transitions = (Vector)table.get(WDDXTAGS.TRANSITIONS);
+ Iterator iter = transitions.iterator();
+ HashSet designTransitions = new HashSet();
+ while(iter.hasNext()){
+ Hashtable transition = (Hashtable)iter.next();
+ transition.put(WDDXTAGS.LEARNING_DESIGN_ID,learningDesign.getLearningDesignId());
+ designTransitions.add((transition));
+ }
+ learningDesign.setTransitions(designTransitions);
+ learningDesignDAO.update(learningDesign);
+ }
+
+ }
+ /**
+ * This method uses the Hashtable passed as an argument to build
+ * and populate a new Transition object. This hashtable is populated
+ * at the Flash side and all we have to do is iterate through it and
+ * set the values for the Transition object. If any of the values being
+ * passed by the Flash side are inconsistent with the database or
+ * any of the mandatory fields is missing an Exception is thrown
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return Transition The populated Transition object
+ * @throws Exception
+ */
+ private Transition processTransitionObject(Hashtable table)throws Exception{
+ Transition transition = new Transition();
+
+ if(table.containsKey(WDDXTAGS.TRANSITION_UIID))
+ transition.setTransitionUIID(WDDXProcessor.convertToInteger("transition_ui_id",table.get(WDDXTAGS.TRANSITION_UIID)));
+
+ if(table.containsKey(WDDXTAGS.DESCRIPTION))
+ transition.setDescription((String)table.get(WDDXTAGS.DESCRIPTION));
+
+ if(table.containsKey(WDDXTAGS.TITLE))
+ transition.setTitle((String)WDDXTAGS.TITLE);
+
+ if(table.containsKey(WDDXTAGS.TRANSITION_TO)){
+ Long activityID = WDDXProcessor.convertToLong("to_activity_id",table.get(WDDXTAGS.TRANSITION_TO));
+ Activity activity = activityDAO.getActivityByActivityId(activityID);
+ if(activity!=null)
+ transition.setToActivity(activity);
+ else
+ throw new Exception("Error setting to_activity_id. No activity with an activity_id of " + activityID + " exists");
+ }
+ if(table.containsKey(WDDXTAGS.TRANSITION_FROM)){
+ Long activityID = WDDXProcessor.convertToLong("from_activity_id",table.get(WDDXTAGS.TRANSITION_FROM));
+ Activity activity = activityDAO.getActivityByActivityId(activityID);
+ if(activity!=null)
+ transition.setFromActivity(activity);
+ else
+ throw new Exception("Error setting from_activity_id. No activity with an activity_id of " + activityID + " exists");
+ }
+ if(table.containsKey(WDDXTAGS.CREATION_DATE))
+ transition.setCreateDateTime((Date)table.get(WDDXTAGS.CREATION_DATE));
+
+ if(table.containsKey(WDDXTAGS.TO_ACTIVITY_UIID))
+ transition.setToUIID(WDDXProcessor.convertToInteger("to_activity_ui_id",table.get(WDDXTAGS.TO_ACTIVITY_UIID)));
+
+ if(table.containsKey(WDDXTAGS.FROM_ACTIVITY_UIID))
+ transition.setFromUIID(WDDXProcessor.convertToInteger("from_activity_ui_id",table.get(WDDXTAGS.FROM_ACTIVITY_UIID)));
+
+ return transition;
+
+ }
+ /**
+ * This method uses the Hashtable passed as an argument to update
+ * the learningDesign object. This hashtable is populated
+ * at the Flash side and all we have to do is iterate through it and
+ * set the values for the LearningDesign object. If any of the values being
+ * passed by the Flash side are inconsistent with the database or any of the
+ * mandatory fields is missing an Exception is thrown.
+ *
+ * @param table The Hashtable parsed from the WDDX string
+ * @param design The LearningDesign object to be updated/populated
+ * @throws Exception
+ */
+ public void updateLearningDesign(Hashtable table, LearningDesign design) throws Exception{
+ try{
+
+ if(table.containsKey(WDDXTAGS.LEARNING_DESIGN_UIID))
+ design.setLearningDesignUIID(WDDXProcessor.convertToInteger("learning_design_ui_id",table.get(WDDXTAGS.LEARNING_DESIGN_UIID)));
+
+ if(table.containsKey(WDDXTAGS.TITLE))
+ design.setTitle((String)table.get(WDDXTAGS.TITLE));
+
+ if(table.containsKey(WDDXTAGS.DESCRIPTION))
+ design.setDescription((String)table.get(WDDXTAGS.DESCRIPTION));
+
+ if(table.containsKey(WDDXTAGS.FIRST_ACTIVITY_ID)){
+ Long firstActivityID = WDDXProcessor.convertToLong("first_activity_id",table.get(WDDXTAGS.FIRST_ACTIVITY_ID));
+ Activity activity = activityDAO.getActivityByActivityId(firstActivityID);
+ if(activity==null)
+ throw new Exception("No activity with an activity_id: " + WDDXTAGS.FIRST_ACTIVITY_ID + " exists.");
+ design.setFirstActivity(activity);
+ }
+
+ if(table.containsKey(WDDXTAGS.VERSION))
+ design.setVersion((String)table.get(WDDXTAGS.VERSION));
+ else
+ throw new Exception("Mandatory field version is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.MAX_ID))
+ design.setMaxId(WDDXProcessor.convertToInteger("max_id",table.get(WDDXTAGS.MAX_ID)));
+
+ if(table.containsKey(WDDXTAGS.VALID_DESIGN))
+ design.setValidDesign(WDDXProcessor.convertToBoolean("valid_design_flag",table.get(WDDXTAGS.VALID_DESIGN)));
+ else
+ throw new Exception("Mandatory field valid_design_flag is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.READ_ONLY))
+ design.setReadOnly(WDDXProcessor.convertToBoolean("read_only_flag",table.get(WDDXTAGS.READ_ONLY)));
+ else
+ throw new Exception("Mandatory field read_only_flag is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.DATE_READ_ONLY))
+ design.setDateReadOnly((Date)table.get(WDDXTAGS.DATE_READ_ONLY));
+
+ if(table.containsKey(WDDXTAGS.HELP_TEXT))
+ design.setHelpText((String)table.get(WDDXTAGS.HELP_TEXT));
+
+ if(table.containsKey(WDDXTAGS.COPY_TYPE))
+ design.setCopyTypeID(WDDXProcessor.convertToInteger("copy_type",table.get(WDDXTAGS.COPY_TYPE)));
+ else
+ throw new Exception("Mandatory field copy_type is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.CREATION_DATE))
+ design.setCreateDateTime((Date)table.get(WDDXTAGS.CREATION_DATE));
+ else
+ throw new Exception("Mandatory field create_date_time is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.USER_ID)){
+ Integer userId = WDDXProcessor.convertToInteger("user_id",table.get(WDDXTAGS.USER_ID));
+ User user = userDAO.getUserById(userId);
+ if(user==null)
+ throw new Exception("No user with a user_id: " + WDDXTAGS.USER_ID + " exists.");
+ design.setUser(user);
+ }else
+ throw new Exception("Mandatory Field user_id is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.WORKSPACE_FOLDER_ID)){
+ Integer workspaceFolderID = WDDXProcessor.convertToInteger("workspace_folder_id",table.get(WDDXTAGS.WORKSPACE_FOLDER_ID));
+ WorkspaceFolder workspaceFolder = workspaceFolderDAO.getWorkspaceFolderByID(workspaceFolderID);
+ if(workspaceFolder==null)
+ throw new Exception("No workspaceFolder with a with workspace_folder_id: " + WDDXTAGS.WORKSPACE_FOLDER_ID + " exists.");
+ design.setWorkspaceFolder(workspaceFolder);
+
+ }else
+ throw new Exception("Mandatory Field workspace_folder_id is missing for LearningDesign in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.PARENT_DESIGN_ID)){
+ Long parentDesignID = WDDXProcessor.convertToLong("parent_learning_design_id",table.get(WDDXTAGS.PARENT_DESIGN_ID));
+ LearningDesign parent = learningDesignDAO.getLearningDesignById(parentDesignID);
+ if(parent==null)
+ throw new Exception("No parent design with with learning_design_id of : " + WDDXTAGS.PARENT_DESIGN_ID + " exists.");
+ design.setParentLearningDesign(parent);
+ }
+
+ if(table.containsKey(WDDXTAGS.DURATION))
+ design.setDuration(WDDXProcessor.convertToLong("duration",table.get(WDDXTAGS.DURATION)));
+
+ if(table.containsKey(WDDXTAGS.LICENCE_ID)){
+ Long licenseID = WDDXProcessor.convertToLong("license_id",table.get(WDDXTAGS.LICENCE_ID));
+ License license = licenseDAO.getLicenseByID(licenseID);
+ if(license!=null)
+ design.setLicense(license);
+ else
+ throw new Exception("No License with a license_id of : " + licenseID + " exists" );
+ }
+
+ if(table.containsKey(WDDXTAGS.LICENSE_TEXT))
+ design.setLicenseText((String)table.get(WDDXTAGS.LICENSE_TEXT));
+
+
+ }catch(WDDXProcessorConversionException wpce){
+ String str = wpce.getMessage();
+ throw new Exception(wpce.getMessage());
+ }
+
+ }
+
+ /**
+ * This method uses the Hashtable passed as an argument to build and
+ * populate a new Activity object. This hashtable is populated
+ * at the Flash side and all we have to do is iterate through it and
+ * set the values for the Activity object. If any of the values being
+ * passed by the Flash side are inconsistent with the database or any of the
+ * mandatory fields is missing an Exception is thrown.
+ *
+ * @param table The hashtable passed by Flash
+ * @return Activity The populated Activity object
+ * @throws Exception
+ */
+ private Activity processActivity(Hashtable table,LearningDesign design) throws Exception {
+ Long activityID =null;
+ Activity activity = null;
+ boolean update = false;
+ if(table.containsKey(WDDXTAGS.ACTIVITY_ID)){
+ activityID = WDDXProcessor.convertToLong("activity_id",table.get(WDDXTAGS.ACTIVITY_ID));
+ activity = activityDAO.getActivityByActivityId(activityID);
+ update=true;
+ }else{
+ /* If the hastable doesn't contains the key ACTIVITY_ID
+ * this mean its a request to store a new Activity
+ */
+ Integer activityTypeID = WDDXProcessor.convertToInteger("activity_type_id",table.get(WDDXTAGS.ACTIVITY_TYPE_ID));
+ activity = createActivityInstance(activityTypeID,table);
+ }
+
+ try{
+ if(table.containsKey(WDDXTAGS.ACTIVITY_UIID))
+ activity.setActivityUIID(WDDXProcessor.convertToInteger("activity_ui_id",table.get(WDDXTAGS.ACTIVITY_UIID)));
+
+ if(table.containsKey(WDDXTAGS.DESCRIPTION))
+ activity.setDescription((String)table.get(WDDXTAGS.DESCRIPTION));
+
+ if(table.containsKey(WDDXTAGS.TITLE))
+ activity.setTitle((String)table.get(WDDXTAGS.TITLE));
+
+ if(table.containsKey(WDDXTAGS.HELP_TEXT))
+ activity.setHelpText((String)table.get(WDDXTAGS.HELP_TEXT));
+
+ if(table.containsKey(WDDXTAGS.XCOORD))
+ activity.setXcoord(WDDXProcessor.convertToInteger("xcoord",table.get(WDDXTAGS.XCOORD)));
+
+ if(table.containsKey(WDDXTAGS.YCOORD))
+ activity.setYcoord(WDDXProcessor.convertToInteger("ycoord",table.get(WDDXTAGS.YCOORD)));
+
+ if(table.containsKey(WDDXTAGS.PARENT_UIID)){
+ Integer parentUIID = WDDXProcessor.convertToInteger("parent_ui_id",table.get(WDDXTAGS.PARENT_UIID));
+ Activity objActivity = activityDAO.getActivityByUIID(parentUIID,design);
+ if(objActivity!=null){
+ activity.setParentActivity(objActivity);
+ activity.setParentUIID(parentUIID);
+ }else
+ throw new Exception ("Error setting parent_ui_id. No such activity with activity_ui_id : "+ parentUIID + "exists.");
+ }
+
+ if(table.containsKey(WDDXTAGS.PARENT_ACTIVITY_ID)){
+ Long parentActivityID = WDDXProcessor.convertToLong("parent_activity_id",table.get(WDDXTAGS.PARENT_ACTIVITY_ID));
+ Activity parent = activityDAO.getActivityByActivityId(parentActivityID);
+ if(parent!=null){
+ activity.setParentActivity(parent);
+ activity.setParentUIID(parent.getActivityUIID());
+ }
+ else
+ throw new Exception("Error setting the parent_activity_id. No such activity with activity_id of: " + parentActivityID + " exists");
+
+ }
+
+ if(table.containsKey(WDDXTAGS.ACTIVITY_TYPE_ID))
+ activity.setActivityTypeId(WDDXProcessor.convertToInteger("learning_activity_type_id",table.get(WDDXTAGS.ACTIVITY_TYPE_ID)));
+
+ if(table.containsKey(WDDXTAGS.GROUPING_UIID)){
+ Integer groupingUIID = WDDXProcessor.convertToInteger("grouping_ui_id",
+ table.get(WDDXTAGS.GROUPING_UIID));
+ activity.setGroupingUIID(groupingUIID);
+
+ Grouping grouping = groupingDAO.getGroupingByUIID(groupingUIID);
+ activity.setGrouping(grouping);
+ }
+
+ if(table.containsKey(WDDXTAGS.DEFINE_LATER))
+ activity.setDefineLater((Boolean)table.get(WDDXTAGS.DEFINE_LATER));
+ else
+ throw new Exception("Mandatory Field define_later is missing for Activity in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.RUN_OFFLINE))
+ activity.setRunOffline(WDDXProcessor.convertToBoolean("run_offline",table.get(WDDXTAGS.RUN_OFFLINE)));
+ else
+ throw new Exception("Mandatory Field run_offline is missing for Activity in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.LEARNING_DESIGN_ID)){
+ Long learningDesignID = WDDXProcessor.convertToLong("learning_design_id", table.get(WDDXTAGS.LEARNING_DESIGN_ID));
+ LearningDesign learningDesign = learningDesignDAO.getLearningDesignById(learningDesignID);
+ if(learningDesign!=null)
+ activity.setLearningDesign(learningDesign);
+ else
+ throw new Exception("Error setting learning_design_Id." +
+ "No such design with learning_design_id : " + learningDesignID + " exists");
+ }
+
+ if(table.containsKey(WDDXTAGS.LEARNING_LIBRARY_ID)){
+ Long learningLibraryID = WDDXProcessor.convertToLong("learning_library_id", table.get(WDDXTAGS.LEARNING_LIBRARY_ID));
+ LearningLibrary learningLibrary = learningLibraryDAO.getLearningLibraryById(learningLibraryID);
+ if(learningLibrary!=null)
+ activity.setLearningLibrary(learningLibrary);
+ else
+ throw new Exception("Error setting learning_library_Id." +
+ "No such design with learning_library_id : " + learningLibraryID + " exists");
+
+ }
+
+ if(table.containsKey(WDDXTAGS.CREATION_DATE))
+ activity.setCreateDateTime((Date)table.get(WDDXTAGS.CREATION_DATE));
+ else
+ throw new Exception("Mandatory Field create_date_time is missing for Activity in the WDDX packet");
+
+ if(table.containsKey(WDDXTAGS.OFFLINE_INSTRUCTIONS))
+ activity.setOfflineInstructions((String)table.get(WDDXTAGS.OFFLINE_INSTRUCTIONS));
+
+ if(table.containsKey(WDDXTAGS.LIBRARY_IMAGE))
+ activity.setLibraryActivityUiImage((String)table.get(WDDXTAGS.LIBRARY_IMAGE));
+
+ if(table.containsKey(WDDXTAGS.LIBRARY_ACTIVITY)){
+ Long libraryActivityID = WDDXProcessor.convertToLong("library_activity_id",table.get(WDDXTAGS.LIBRARY_ACTIVITY));
+ Activity libActivity = activityDAO.getActivityByActivityId(libraryActivityID);
+ if(libActivity!=null)
+ activity.setLibraryActivity(libActivity);
+ else
+ throw new Exception("Error setting library_activity_id" +
+ "No Such activity with activity_id of: " + libraryActivityID + " exists");
+ }
+ }catch(WDDXProcessorConversionException wpce){
+ throw new Exception(wpce.getMessage());
+ }
+ if(update)
+ activityDAO.update(activity);
+ else
+ activityDAO.insert(activity);
+ return activity;
+ }
+
+ /**
+ * Depending upon the activity's type this function instantiates
+ * a new object and calls the corresponding function to populate
+ * its attributes from the hashtable passed on by FLASH
+ *
+ * @param activityTypeID The type of Activity object to be instantiated
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return Activity The requires populated activity object
+ * @throws Exception
+ */
+ private Activity createActivityInstance(Integer activityTypeID,Hashtable table)throws Exception{
+ Activity activity = null;
+ int type = activityTypeID.intValue();
+ switch(type){
+ case Activity.TOOL_ACTIVITY_TYPE:
+ activity = storeToolActivity(table);
+ break;
+ case Activity.OPTIONS_ACTIVITY_TYPE:
+ activity = storeOptionsActivity(table);
+ break;
+ case Activity.GROUPING_ACTIVITY_TYPE:
+ activity = storeGroupingActivity(table);
+ break;
+ case Activity.PERMISSION_GATE_ACTIVITY_TYPE:
+ activity = storePermissionGateActivity(table);
+ break;
+ case Activity.SCHEDULE_GATE_ACTIVITY_TYPE:
+ activity = storeScheduleGateActivity(table);
+ break;
+ case Activity.SYNCH_GATE_ACTIVITY_TYPE:
+ activity = storeSynchGateActivity(table);
+ break;
+ case Activity.PARALLEL_ACTIVITY_TYPE:
+ activity = storeParallelActivity(table);
+ break;
+ case Activity.SEQUENCE_ACTIVITY_TYPE:
+ activity = storeSequenceActivity(table);
+ }
+
+ return activity;
+ }
+
+ /** A GroupingActivity creates Grouping. So when we receive a request
+ * to store a GroupingActivity the grouping_id would be missing in
+ * that case. Instead we will have a unique flash generated value for
+ * grouping_ui_id, based upon which a new record will be generated in
+ * the database for the lams_grouping table. Follwing steps are involved
+ * in saving a GroupingActivity to the database
+ *
+ * - Determine the type of Grouping being created by the GroupingActivity
+ * - Create the Grouping (Chosen/Random)
+ * - Set the Grouping details for the GroupingActivity
+ *
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return GroupingActivity The populated activity object
+ * @throws Exception
+ * */
+ private GroupingActivity storeGroupingActivity(Hashtable table)throws Exception{
+
+ GroupingActivity groupingActivity = new GroupingActivity();
+
+ Hashtable groupingTable = (Hashtable)table.get(WDDXTAGS.GROUPING);
+
+ Integer groupingType =null;
+ Grouping grouping = null;
+
+ if(groupingTable.containsKey(WDDXTAGS.GROUPING_TYPE_ID))
+ groupingType = WDDXProcessor.convertToInteger("grouping_type_id",groupingTable.get(WDDXTAGS.GROUPING_TYPE_ID));
+ else
+ throw new Exception ("grouping_type_id missing for GroupingActivity.Cannot create Grouping without that");
+
+ if(groupingType==Grouping.RANDOM_GROUPING_TYPE)
+ grouping = createRandomGrouping(groupingTable);
+ else
+ grouping = createChosenGrouping(groupingTable);
+
+ groupingActivity.setCreateGrouping(grouping);
+ groupingActivity.setCreateGroupingUIID(grouping.getGroupingUIID());
+ return groupingActivity;
+
+ }
+
+ /**
+ * This function creates and populates the RandomGrouping object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return RandomGrouping The populated activity object
+ * @throws Exception
+ */
+ private RandomGrouping createRandomGrouping(Hashtable table)throws Exception{
+
+ RandomGrouping randomGrouping = new RandomGrouping();
+
+ if(table.containsKey(WDDXTAGS.MAX_NUMBER_OF_GROUPS))
+ randomGrouping.setMaxNumberOfGroups(WDDXProcessor.convertToInteger("max_number_of_groups",table.get(WDDXTAGS.MAX_NUMBER_OF_GROUPS)));
+
+ if(table.containsKey(WDDXTAGS.GROUPING_UIID))
+ randomGrouping.setGroupingUIID(WDDXProcessor.convertToInteger("grouping_ui_id",table.get(WDDXTAGS.GROUPING_UIID)));
+
+ if(table.containsKey(WDDXTAGS.NUMBER_OF_GROUPS))
+ randomGrouping.setNumberOfGroups(WDDXProcessor.convertToInteger("number_of_groups",table.get(WDDXTAGS.NUMBER_OF_GROUPS)));
+
+ if(table.containsKey(WDDXTAGS.LEARNERS_PER_GROUP))
+ randomGrouping.setLearnersPerGroup(WDDXProcessor.convertToInteger("learners_per_group",table.get(WDDXTAGS.LEARNERS_PER_GROUP)));
+
+ groupingDAO.insert(randomGrouping);
+ return randomGrouping;
+
+ }
+ /**
+ * This function creates and populates the ChosenGrouping object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return ChosenGrouping The populated activity object
+ * @throws Exception
+ */
+ private ChosenGrouping createChosenGrouping(Hashtable table)throws Exception{
+ ChosenGrouping chosenGrouping = new ChosenGrouping();
+
+ if(table.containsKey(WDDXTAGS.MAX_NUMBER_OF_GROUPS))
+ chosenGrouping.setMaxNumberOfGroups(WDDXProcessor.convertToInteger("max_number_of_groups",table.get(WDDXTAGS.MAX_NUMBER_OF_GROUPS)));
+
+ if(table.containsKey(WDDXTAGS.GROUPING_UIID))
+ chosenGrouping.setGroupingUIID(WDDXProcessor.convertToInteger("grouping_ui_id",table.get(WDDXTAGS.GROUPING_UIID)));
+
+ groupingDAO.insert(chosenGrouping);
+ return chosenGrouping;
+ }
+
+ /**
+ * This function creates and populates the OptionsActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return OptionsActivity The populated activity object
+ * @throws Exception
+ */
+ private OptionsActivity storeOptionsActivity(Hashtable table)throws Exception{
+
+ OptionsActivity optActivity = new OptionsActivity();
+
+ if(table.containsKey(WDDXTAGS.MAX_OPTIONS))
+ optActivity.setMaxNumberOfOptions(WDDXProcessor.convertToInteger("max_number_of_options",table.get(WDDXTAGS.MAX_OPTIONS)));
+
+ if(table.containsKey(WDDXTAGS.MIN_OPTIONS))
+ optActivity.setMinNumberOfOptions(WDDXProcessor.convertToInteger("min_number_of_options",table.get(WDDXTAGS.MIN_OPTIONS)));
+
+ if(table.containsKey(WDDXTAGS.OPTIONS_INSTRUCTIONS))
+ optActivity.setOptionsInstructions((String)table.get(WDDXTAGS.OPTIONS_INSTRUCTIONS));
+ addChildActivities(optActivity,table);
+ return optActivity;
+ }
+
+ /**
+ * This function creates and populates the ToolActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return ToolActivity The populated activity object
+ * @throws Exception
+ */
+ private ToolActivity storeToolActivity(Hashtable table)throws Exception{
+
+ ToolActivity toolActivity = new ToolActivity();
+
+ if(table.containsKey(WDDXTAGS.TOOL_ID)){
+ Long toolID = WDDXProcessor.convertToLong("tool_id",table.get(WDDXTAGS.TOOL_ID));
+ Tool tool = toolDAO.getToolByID(toolID);
+ if(tool!=null)
+ toolActivity.setTool(tool);
+ else
+ throw new Exception("Error setting tool_id. " +
+ "No such tool with tool_id of: " + toolID + "exists");
+
+ }
+ if(table.containsKey(WDDXTAGS.ORDER_ID))
+ toolActivity.setOrderId(WDDXProcessor.convertToInteger("order_id",table.get(WDDXTAGS.ORDER_ID)));
+
+ if(table.containsKey(WDDXTAGS.TOOL_CONTENT_ID))
+ toolActivity.setToolContentId(WDDXProcessor.convertToLong("tool_content_id",table.get(WDDXTAGS.TOOL_CONTENT_ID)));
+
+ return toolActivity;
+
+ }
+ /**
+ * This functions adds the attributes that are common for all kind of
+ * gate activities (SYNCH/SCHEDULE/PERMISSION). Main purpose of this function
+ * is avoid any unnecessary duplicacy of code.
+ *
+ * @param gateActivity The GateActivity whose attributes are being set
+ * @param table The Hashtable containing the information populated by FLASH
+ * @throws Exception
+ */
+ private void addGateActivityAttributes(GateActivity gateActivity, Hashtable table)throws Exception{
+
+ if(table.containsKey(WDDXTAGS.GATE_ACTIVITY_LEVEL_ID))
+ gateActivity.setGateActivityLevelId(WDDXProcessor.convertToInteger("gate_activity_level_id",
+ table.get(WDDXTAGS.GATE_ACTIVITY_LEVEL_ID)));
+ if(table.containsKey(WDDXTAGS.GATE_OPEN))
+ gateActivity.setGateOpen(WDDXProcessor.convertToBoolean("gate_open",
+ table.get(WDDXTAGS.GATE_OPEN)));
+ }
+ /**
+ * This function creates and populates the PermissionGateActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return PermissionGateActivity The populated activity object
+ * @throws Exception
+ */
+ private PermissionGateActivity storePermissionGateActivity(Hashtable table)throws Exception{
+ PermissionGateActivity permissionGateActivity = new PermissionGateActivity();
+ addGateActivityAttributes(permissionGateActivity,table);
+ return permissionGateActivity;
+ }
+
+ /**
+ * This function creates and populates the ScheduleGateActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return ScheduleGateActivity The populated activity object
+ * @throws Exception
+ */
+ private ScheduleGateActivity storeScheduleGateActivity(Hashtable table)throws Exception{
+ ScheduleGateActivity scheduleGateActivity = new ScheduleGateActivity();
+ addGateActivityAttributes(scheduleGateActivity,table);
+
+ if(table.containsKey(WDDXTAGS.GATE_START_DATE))
+ scheduleGateActivity.setGateStartDateTime((Date)table.get(WDDXTAGS.GATE_START_DATE));
+
+ if(table.containsKey(WDDXTAGS.GATE_END_DATE))
+ scheduleGateActivity.setGateEndDateTime((Date)table.get(WDDXTAGS.GATE_END_DATE));
+
+ if(table.containsKey(WDDXTAGS.GATE_START_OFFSET))
+ scheduleGateActivity.setGateStartTimeOffset(WDDXProcessor.convertToLong("gate_start_time_offset",
+ table.get(WDDXTAGS.GATE_START_OFFSET)));
+ if(table.containsKey(WDDXTAGS.GATE_END_OFFSET))
+ scheduleGateActivity.setGateEndTimeOffset(WDDXProcessor.convertToLong("gate_end_time_offset",
+ table.get(WDDXTAGS.GATE_END_OFFSET)));
+
+ return scheduleGateActivity;
+ }
+
+ /**
+ * This function creates and populates the SynchGateActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return SynchGateActivity The populated activity object
+ * @throws Exception
+ */
+ private SynchGateActivity storeSynchGateActivity(Hashtable table)throws Exception{
+ SynchGateActivity synchGateActivity = new SynchGateActivity();
+ addGateActivityAttributes(synchGateActivity,table);
+ return synchGateActivity;
+ }
+
+ /**
+ * This function creates and populates the ParallelActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return ParallelActivity The populated activity object
+ * @throws Exception
+ */
+ private ParallelActivity storeParallelActivity(Hashtable table)throws Exception{
+ ParallelActivity parallelActivity = new ParallelActivity();
+ addChildActivities(parallelActivity,table);
+ return parallelActivity;
+ }
+ /**
+ * This function creates and populates the SequenceActivity object from
+ * the information passed on by FLASH in the Hashtable
+ *
+ * @param table The Hashtable containing the information populated by FLASH
+ * @return SequenceActivity The populated activity object
+ * @throws Exception
+ */
+ private SequenceActivity storeSequenceActivity(Hashtable table) throws Exception{
+ SequenceActivity sequenceActivity = new SequenceActivity();
+ addChildActivities(sequenceActivity,table);
+ return sequenceActivity;
+ }
+ /**
+ * This function parses the FLASH populated hashtable for any child activities
+ * for a given ComplexActivity. If found it sets them otherwise it throws an
+ * Exception saying an attempt was made to save a ComplexActivity without
+ * any child activities coz that is not possible. We cannot have an
+ * OptionsActivity without any optional activities (child activities) inside it.
+ *
+ * @param complexActivity The ComplexActivity whose children are being set
+ * @param table The Hashtable containing the information populated by FLASH
+ * @throws Exception
+ */
+ private void addChildActivities(ComplexActivity complexActivity, Hashtable table)throws Exception{
+
+ if(table.containsKey(WDDXTAGS.CHILD_ACTIVITIES)){
+ Vector vector = (Vector)table.get(WDDXTAGS.CHILD_ACTIVITIES);
+ HashSet childActivities = new HashSet();
+ Iterator iter = vector.iterator();
+ while(iter.hasNext()){
+ Activity activity = (Activity)iter.next();
+ childActivities.add(activity);
+ }
+ complexActivity.setActivities(childActivities);
+ }else
+ throw new Exception("An attempt to save a complex activity with no child activities");
+ }
+
+}
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXProcessor.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXProcessor.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXProcessor.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,287 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+package org.lamsfoundation.lams.util.wddx;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.xml.sax.InputSource;
+
+import com.allaire.wddx.WddxDeserializationException;
+import com.allaire.wddx.WddxDeserializer;
+import com.allaire.wddx.WddxSerializer;
+
+
+/**
+ * @author Manpreet Minhas
+ */
+public class WDDXProcessor {
+ private static Logger logger = Logger.getLogger(WDDXProcessor.class.getName());
+
+ WDDXProcessor m_theRealMe = null;
+
+ /**
+ * Constructor for Serialiser. Private to ensure singleton behaviour
+ */
+ private WDDXProcessor()
+ {
+ super();
+ }
+
+
+ WDDXProcessor getInstance()
+ {
+ if ( m_theRealMe == null )
+ m_theRealMe = new WDDXProcessor();
+ return m_theRealMe;
+ }
+
+ /** Replace any "%0D0A" in the wddx packet with true java characters
+ * Flash clients will put in "%0D0A" to get around the Flash code
+ * removing newlines before creating the packet.
+ *
+ * Made public as some parts of the system use the same format when
+ * sending from Flash clients, but not via a wddx packet (just a normal post).
+ */
+ public static String replaceNewline(String inputPacket)
+ {
+ String ret = null;
+ if ( inputPacket != null )
+ {
+ ret = StringUtils.replace(inputPacket,"%0D%0A","\r\n");
+ }
+ return ret;
+ }
+
+ /**
+ * Deserialize an arbitrary packet.
+ */
+ public static Object deserialize(String wddxPacket)
+ throws WddxDeserializationException
+ {
+ String replacedString = replaceNewline(wddxPacket);
+
+ // Create an input source (org.xml.sax.InputSource) bound to the packet
+ InputSource tempSource = new InputSource(new StringReader(replacedString));
+
+ // Create a WDDX deserializer (com.allaire.wddx.WddxDeserializer)
+ WddxDeserializer tempDeserializer = new WddxDeserializer("org.apache.xerces.parsers.SAXParser");
+
+ // Deserialize the WDDX packet
+ Object result;
+ try
+ {
+ result = tempDeserializer.deserialize(tempSource);
+ }
+ catch (IOException e)
+ {
+ throw new WddxDeserializationException( e );
+ }
+
+ return result;
+ }
+
+ /**
+ * Serialize an arbitrary packet.
+ */
+ public static String serialize(Object data) throws IOException
+ {
+ // Create a WDDX serializer
+ WddxSerializer tempws = new WddxSerializer();
+
+ // Create a writer to store the generated WDDX
+ StringWriter tempsw = new StringWriter();
+ // Serialize the data
+ tempws.serialize(data, tempsw);
+ // Return the WDDX packet
+ return tempsw.toString();
+ }
+
+ /** Convert a string to an int, based on how WDDX usually passes numbers.
+ * @param identifier - name of value being converted - using in the exception thrown
+ * if the number cannot be converted.
+ * @param value - the value to be converted
+ * @return int value
+ * @throws Exception - will contain a message "Unable to convert value (identifier): (value) to an int"
+ */
+ public static int convertToInt( String identifier, Object value)
+ throws WDDXProcessorConversionException
+ {
+ int result=-255;
+ if ( value == null )
+ {
+ throw new WDDXProcessorConversionException(identifier+" is null, cannot convert to an int");
+ }
+
+ try {
+ // WDDX should give us a double
+ result = ((Number)value).intValue();
+ return(result);
+ } catch (Exception e) {}
+
+ try {
+ String textValue = (String) value;
+ if ( textValue.length() == 0 )
+ return -1;
+
+ double dTemp = Double.parseDouble(textValue);
+ result = (int) dTemp;
+ } catch ( Exception e2) {
+ throw new WDDXProcessorConversionException("Unable to convert value "+identifier+":"+value+" to an int");
+ }
+ return(result);
+ }
+
+ /**
+ * Some conversion doesn't allow null value. Doing so will result in hidden
+ * nullpointer exception. We do need this helper function.
+ *
+ * @param identifier
+ * @param value
+ * @return converted integer.
+ * @throws WDDXProcessorConversionException
+ * @author Jacky Fang
+ */
+ public static Integer nullSafeCovertToInteger(String identifier,Object value) throws WDDXProcessorConversionException
+ {
+ if(value == null)
+ throw new IllegalArgumentException("["+identifier+"] is null. We can't convert null value to integer");
+ //delegate to convertToInteger
+ return convertToInteger(identifier,value);
+ }
+ /** Convert a string to an integer, based on how WDDX usually passes numbers.
+ * As it is an integer, if the field is blank (or not there), then return null
+ * @param identifier - name of value being converted - using in the exception thrown
+ * if the number cannot be converted.
+ * @param value - the value to be converted
+ * @return integer value or null
+ * @throws Exception - will contain a message "Unable to convert value (identifier): (value) to an int"
+ */
+ public static Integer convertToInteger( String identifier, Object value)
+ throws WDDXProcessorConversionException
+ {
+ Integer result = null;
+ if ( value == null )
+ return null;
+
+ try {
+ // WDDX should give us a double
+ result = new Integer (((Number)value).intValue() );
+ return(result);
+ } catch (Exception e) {}
+
+ try {
+ String textValue = (String) value;
+ if ( textValue.length() == 0 )
+ return null;
+
+ int posPeriod = textValue.indexOf('.');
+ if ( posPeriod > 0 )
+ {
+ textValue = textValue.substring(0,posPeriod);
+ }
+ result = new Integer (textValue);
+ } catch ( Exception e2) {
+ throw new WDDXProcessorConversionException("Unable to convert value "+identifier+":"+value+" to an int");
+ }
+ return(result);
+ }
+
+ /** Convert a String to an Long, based on how WDDX usually passes numbers.
+ * As it is a Long, if the field is blank (or not there), then return null
+ * @param identifier - name of value being converted - using in the exception thrown
+ * if the number cannot be converted.
+ * @param value - the value to be converted
+ * @return Long value or null
+ * @throws Exception - will contain a message "Unable to convert value (identifier): (value) to an int"
+ */
+ public static Long convertToLong( String identifier, Object value)
+ throws WDDXProcessorConversionException
+ {
+ Long result = null;
+ if ( value == null )
+ {
+ return null;
+ }
+
+ try {
+ // WDDX should give us a double
+ result = new Long(((Number)value).intValue() );
+ return(result);
+ } catch (Exception e) {}
+
+ try {
+ String textValue = (String) value;
+ if ( textValue.length() == 0 )
+ return null;
+
+ int posPeriod = textValue.indexOf('.');
+ if ( posPeriod > 0 )
+ {
+ textValue = textValue.substring(0,posPeriod);
+ }
+ result = new Long (textValue);
+ } catch ( Exception e2) {
+ throw new WDDXProcessorConversionException("Unable to convert value "+identifier+":"+value+" to an int");
+ }
+ return(result);
+ }
+
+ /** Convert a String/Boolean to an Boolean
+ * @param identifier - name of value being converted - using in the exception thrown
+ * if the value cannot be converted.
+ * @param value - the value to be converted
+ * @return Boolean value or null
+ * @throws Exception - will contain a message "Unable to convert value (identifier): (value) to an int"
+ */
+ public static Boolean convertToBoolean( String identifier, Object value)
+ throws WDDXProcessorConversionException
+ {
+ Boolean result = null;
+ if ( value == null )
+ {
+ return null;
+ }
+
+ try {
+ result = (Boolean) value;
+ logger.debug("identifier "+identifier+" was Boolean value "+value+" becomes "+result);
+ return(result);
+ } catch (Exception e) {}
+
+ try {
+ String textValue = (String) value;
+ if ( textValue.length() == 0 )
+ return null;
+
+ result = new Boolean (textValue);
+ logger.debug("identifier "+identifier+" was String value "+value+" becomes "+result);
+ return(result);
+ } catch ( Exception e2) {
+ throw new WDDXProcessorConversionException("Unable to convert value "+identifier+":"+value+" to a Boolean");
+ }
+ }
+}
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXProcessorConversionException.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXProcessorConversionException.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXProcessorConversionException.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+
+package org.lamsfoundation.lams.util.wddx;
+
+/**
+ * @author Manpreet Minhas
+ *
+ * Thrown if an error occurs trying to get the numeric data from the wddx generated objects.
+ *
+ */
+public class WDDXProcessorConversionException extends Exception {
+
+ /**
+ * Constructor for WDDXProcessorConversionException.
+ */
+ public WDDXProcessorConversionException() {
+ super();
+ }
+
+ /**
+ * Constructor for WDDXProcessorConversionException.
+ * @param message
+ */
+ public WDDXProcessorConversionException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor for WDDXProcessorConversionException.
+ * @param message
+ * @param cause
+ */
+ public WDDXProcessorConversionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor for WDDXProcessorConversionException.
+ * @param cause
+ */
+ public WDDXProcessorConversionException(Throwable cause) {
+ super(cause);
+ }
+
+}
Index: lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXTAGS.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXTAGS.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/wddx/WDDXTAGS.java (revision fc76a4bb4e5abc614e15b642e4015295b2912c0a)
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ************************************************************************
+ */
+package org.lamsfoundation.lams.util.wddx;
+
+import java.util.Date;
+
+
+
+/**
+ * @author Manpreet Minhas
+ * The tags used in WDDX Packet
+ */
+public interface WDDXTAGS {
+
+ /* General Tags */
+ public static final String OBJECT_TYPE = "objectType";
+
+ public static final String DESCRIPTION = "description";
+ public static final String TITLE = "title";
+ public static final String HELP_TEXT ="help_text";
+ public static final String XCOORD="xcoord";
+ public static final String YCOORD="ycoord";
+ public static final String GROUPING ="grouping";
+ public static final String TRANSITIONS ="transitions";
+ public static final String ACTIVITIES ="activities";
+
+ /*Learning Library specific tags */
+ public static final String LEARNING_LIBRARY_ID ="learning_library_id";
+ public static final String LIB_ACTIVITIES="templateActivities";
+ public static final String LIB_PACKAGE = "libraries";
+ public static final String DESIGN_PACKAGE ="designs";
+
+
+ public static final Long NUMERIC_NULL_VALUE_LONG = new Long(-111111);
+ public static final String STRING_NULL_VALUE = "string_null_value";
+ public static final Integer NUMERIC_NULL_VALUE_INTEGER = new Integer(-111111);
+ public static final Date DATE_NULL_VALUE = new Date(0);
+ public static final Boolean BOOLEAN_NULL_VALUE = new Boolean("false");
+
+ /*Activity specific tags*/
+ public static final String ACTIVITY_ID ="activity_id";
+ public static final String ACTIVITY_UIID ="activity_ui_id";
+
+ public static final String PARENT_ACTIVITY_ID ="parent_activity_id";
+ public static final String PARENT_UIID ="parent_activity_ui_id";
+
+ public static final String ACTIVITY_TYPE_ID ="learning_activity_type_id";
+ public static final String ORDER_ID ="order_id";
+
+ public static final String DEFINE_LATER ="define_later_flag";
+ public static final String RUN_OFFLINE ="run_offline";
+ public static final String OFFLINE_INSTRUCTIONS ="offline_instructions";
+ public static final String LIBRARY_IMAGE ="library_activity_ui_image";
+ public static final String LIBRARY_ACTIVITY ="library_activity_id";
+
+ /** OptionsActivity specific tags*/
+ public static final String MAX_OPTIONS="max_number_of_options";
+ public static final String MIN_OPTIONS="min_number_of_options";
+ public static final String OPTIONS_INSTRUCTIONS ="options_instructions";
+
+ /** ToolActivity specific tags*/
+ public static final String TOOL_ID="tool_id";
+ public static final String TOOL_CONTENT_ID="tool_content_id";
+
+ /** GateActivity specific tags*/
+ public static final String GATE_ACTIVITY_LEVEL_ID ="gate_activity_level_id";
+ public static final String GATE_START_DATE ="gate_start_date_time";
+ public static final String GATE_END_DATE ="gate_end_date_time";
+ public static final String GATE_START_OFFSET="gate_start_time_offset";
+ public static final String GATE_END_OFFSET="gate_end_time_offset";
+ public static final String GATE_OPEN ="gate_open";
+
+ /** Grouping Activity specific tags */
+ public static final String CREATE_GROUPING_ID ="create_grouping_id";
+ public static final String CREATE_GROUPING_UIID ="create_grouping_ui_id";
+
+ /** Grouping specific tags */
+ public static final String GROUPING_ID ="grouping_id";
+ public static final String GROUPING_UIID ="grouping_ui_id";
+ public static final String GROUPING_TYPE_ID ="grouping_type_id";
+ public static final String LEARNERS_PER_GROUP ="learners_per_group";
+ public static final String MAX_NUMBER_OF_GROUPS ="max_number_of_groups";
+ public static final String NUMBER_OF_GROUPS ="number_of_groups";
+
+ /** Transition specific tags */
+ public static final String TRANSITION_ID ="transition_id";
+ public static final String TRANSITION_UIID ="transition_ui_id";
+ 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 ="to_activity_ui_id";
+ public static final String FROM_ACTIVITY_UIID ="from_activity_ui_id";
+
+
+ /** 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";
+
+
+
+ /** LearningDesign specific tags*/
+ public static final String LEARNING_DESIGN_ID="learning_design_id";
+ public static final String LEARNING_DESIGN_UIID="learning_design_ui_id";
+ public static final String FIRST_ACTIVITY_ID ="first_activity_id";
+ public static final String FIRST_ACTIVITY_UIID ="first_activity_ui_id";
+
+ public static final String MAX_ID ="max_id";
+ public static final String VALID_DESIGN ="valid_design_flag";
+ public static final String READ_ONLY ="read_only_flag";
+ public static final String DATE_READ_ONLY ="date_read_only";
+ public static final String USER_ID="user_id";
+
+ public static final String COPY_TYPE="copy_type_id";
+ public static final String CREATION_DATE ="create_date_time";
+ public static final String VERSION="version";
+ public static final String PARENT_DESIGN_ID ="parent_learning_design_id";
+ public static final String WORKSPACE_FOLDER_ID= "workspace_folder_id";
+ public static final String DURATION ="duration";
+ public static final String LICENCE_ID ="license_id";
+ public static final String LICENSE_TEXT ="license_text";
+
+ /**ComplexActivity specific tags */
+ public static final String CHILD_ACTIVITIES ="childActivities";
+
+
+
+}