Index: lams_common/src/java/org/lamsfoundation/lams/tool/OutputFactory.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/tool/OutputFactory.java,v diff -u -r1.7 -r1.7.6.1 --- lams_common/src/java/org/lamsfoundation/lams/tool/OutputFactory.java 8 Apr 2008 04:44:27 -0000 1.7 +++ lams_common/src/java/org/lamsfoundation/lams/tool/OutputFactory.java 20 Apr 2009 05:14:45 -0000 1.7.6.1 @@ -39,268 +39,367 @@ import org.lamsfoundation.lams.learningdesign.BranchCondition; /** - * This class forms the basic implementation of an output definition and output value factory, which is the class in a tool that - * creates the output definition and output values for a tool. Each tool that has outputs should create its own factory class that - * extends this class and uses the methods implemented in this class to create the actual ToolOutputDefinition and ToolOutput objects. + * This class forms the basic implementation of an output definition and output + * value factory, which is the class in a tool that creates the output + * definition and output values for a tool. Each tool that has outputs should + * create its own factory class that extends this class and uses the methods + * implemented in this class to create the actual ToolOutputDefinition and + * ToolOutput objects. * - * The implemented factory (in the tool) needs to supply either (a) its own messageService bean (a Spring bean normally - * defined in the tool's applicationContext file in the toolMessageService property or (b) the name of its I18N language package/filename AND - * the the loadedMessageSourceService (which is defined as a Spring bean in the core context). One of the two options (but not - * both) is required so that the getDescription() method can get the internationalised description of the output definition - * from the tool's internationalisation files. If neither the messageService or the I18N name is not supplied then the name - * if the output definition will appear in the description field. + * The implemented factory (in the tool) needs to supply either (a) its own + * messageService bean (a Spring bean normally defined in the tool's + * applicationContext file in the toolMessageService property or (b) the name of + * its I18N language package/filename AND the the loadedMessageSourceService + * (which is defined as a Spring bean in the core context). One of the two + * options (but not both) is required so that the getDescription() method can + * get the internationalised description of the output definition from the + * tool's internationalisation files. If neither the messageService or the I18N + * name is not supplied then the name if the output definition will appear in + * the description field. * - * The implemented factory should implement public SortedMap getToolOutputDefinitions(Object toolContentObject) - * and this method should call the buildBlahDefinition() calls to build the definitions. + * The implemented factory should implement public SortedMap getToolOutputDefinitions(Object toolContentObject) and + * this method should call the buildBlahDefinition() calls to build the + * definitions. * - * It should also implement two methods similar to SortedMap getToolOutput(List names, various tool objects) and - * ToolOutput getToolOutput(String name, various tool objects) to get the actual outputs. The "various tool objects" will vary from tool to - * tool - some tools may wish to pass in the raw session and user ids, others may pass in specific tool objects. As these inputs will vary - * greatly from tool to tool, no abstract method has been included in this parent class. Putting these calls in the factory allows - * all the "work" of the output generation to be grouped together and it also allows the getToolOutput() logic to get to getDescription() - * logic in the factory. + * It should also implement two methods similar to SortedMap getToolOutput(List names, various tool objects) and + * ToolOutput getToolOutput(String name, various tool objects) to get the actual + * outputs. The "various tool objects" will vary from tool to tool - some tools + * may wish to pass in the raw session and user ids, others may pass in specific + * tool objects. As these inputs will vary greatly from tool to tool, no + * abstract method has been included in this parent class. Putting these calls + * in the factory allows all the "work" of the output generation to be grouped + * together and it also allows the getToolOutput() logic to get to + * getDescription() logic in the factory. * - * Example definitions for tool factories: - * - * - * org.lamsfoundation.lams.tool.mc.ApplicationResources - * - * - * - * - * - * + * Example definitions for tool factories: + * org.lamsfoundation.lams.tool.mc.ApplicationResources + * + * + * + * + * + * */ public abstract class OutputFactory { - protected Logger log = Logger.getLogger(OutputFactory.class); + protected Logger log = Logger.getLogger(OutputFactory.class); - private MessageService toolMessageService; - private ILoadedMessageSourceService loadedMessageSourceService; - private String languageFilename; - private MessageSource msgSource = null; // derived from toolMessageService, loadedMessageSourceService, languageFilename - protected final String KEY_PREFIX = "output.desc."; - protected final String CONDITION_NAME_SEPARATOR = "#"; - - /** Create a map of the tool output definitions, suitable for returning from the method - * getToolOutputDefinitions() in the ToolContentManager interface. The class for the toolContentObject - * will be unique to each tool e.g. for Multiple Choice tool it will be the McContent object. - * - * If the toolContentObject should not be null - if the toolContentId supplied in the call to - * getToolOutputDefinitions(Long toolContentId) does not match to any existing content, the content - * should be the tool's default tool content. - * - * @param toolContentObject - * @return SortedMap of ToolOutputDefinitions where the key is the name from each definition - * @throws ToolException - */ - public abstract SortedMap getToolOutputDefinitions(Object toolContentObject) throws ToolException; + private MessageService toolMessageService; + private ILoadedMessageSourceService loadedMessageSourceService; + private String languageFilename; + private MessageSource msgSource = null; // derived from toolMessageService, loadedMessageSourceService, languageFilename + protected final String KEY_PREFIX = "output.desc."; + protected final String CONDITION_NAME_SEPARATOR = "#"; - /** Tool specific toolMessageService, such as the forumMessageService in the Forum tool */ - private MessageService getToolMessageService() { - return toolMessageService; - } + /** + * Create a map of the tool output definitions, suitable for returning from + * the method getToolOutputDefinitions() in the ToolContentManager + * interface. The class for the toolContentObject will be unique to each + * tool e.g. for Multiple Choice tool it will be the McContent object. + * + * If the toolContentObject should not be null - if the toolContentId + * supplied in the call to getToolOutputDefinitions(Long toolContentId) does + * not match to any existing content, the content should be the tool's + * default tool content. + * + * @param toolContentObject + * @return SortedMap of ToolOutputDefinitions where the key is the name from + * each definition + * @throws ToolException + */ + public abstract SortedMap getToolOutputDefinitions(Object toolContentObject) + throws ToolException; - public void setToolMessageService(MessageService toolMessageService) { - this.toolMessageService = toolMessageService; - } + /** + * Tool specific toolMessageService, such as the forumMessageService in the + * Forum tool + */ + private MessageService getToolMessageService() { + return toolMessageService; + } + public void setToolMessageService(MessageService toolMessageService) { + this.toolMessageService = toolMessageService; + } - /** Set the common loadedMessageSourceService, based on the bean defined in the common Spring context. - * If toolMessageService is not set, then the languageFilename - * and loadedMessageSourceService should be set. */ - private ILoadedMessageSourceService getLoadedMessageSourceService() { - return loadedMessageSourceService; - } + /** + * Set the common loadedMessageSourceService, based on the bean defined in + * the common Spring context. If toolMessageService is not set, then the + * languageFilename and loadedMessageSourceService should be set. + */ + private ILoadedMessageSourceService getLoadedMessageSourceService() { + return loadedMessageSourceService; + } - public void setLoadedMessageSourceService( - ILoadedMessageSourceService loadedMessageSourceService) { - this.loadedMessageSourceService = loadedMessageSourceService; - } + public void setLoadedMessageSourceService(ILoadedMessageSourceService loadedMessageSourceService) { + this.loadedMessageSourceService = loadedMessageSourceService; + } - /** Set the filename/path for the tool's I18N files. If toolMessageService is not set, then the languageFilename - * and loadedMessageSourceService should be set. */ - public String getLanguageFilename() { - return languageFilename; - } + /** + * Set the filename/path for the tool's I18N files. If toolMessageService is + * not set, then the languageFilename and loadedMessageSourceService should + * be set. + */ + public String getLanguageFilename() { + return languageFilename; + } - /** Get the filename and path for the tool's I18N files. */ - public void setLanguageFilename(String languageFilename) { - this.languageFilename = languageFilename; - } + /** Get the filename and path for the tool's I18N files. */ + public void setLanguageFilename(String languageFilename) { + this.languageFilename = languageFilename; + } - /** - * Get the I18N description for this key. If the tool has supplied a messageService, then this - * is used to look up the key and hence get the text. Otherwise if the tool has supplied a I18N - * languageFilename then it is accessed via the shared toolActMessageService. If neither are supplied or - * the key is not found, then any "." in the name are converted to space and this is used as the return value. - * - * This is normally used to get the description for a definition, in whic case the key should be in the format - * output.desc.[definition name], key = definition name and addPrefix = true. For example a - * definition name of "learner.mark" becomes output.desc.learner.mark. - * - * If you want to use this to get an arbitrary string from the I18N files, then set addPrefix = false and the - * output.desc will not be added to the beginning. - */ - protected String getI18NText(String key, boolean addPrefix) { - String translatedText = null; + /** + * Get the I18N description for this key. If the tool has supplied a + * messageService, then this is used to look up the key and hence get the + * text. Otherwise if the tool has supplied a I18N languageFilename then it + * is accessed via the shared toolActMessageService. If neither are supplied + * or the key is not found, then any "." in the name are converted to space + * and this is used as the return value. + * + * This is normally used to get the description for a definition, in whic + * case the key should be in the format output.desc.[definition name], key = + * definition name and addPrefix = true. For example a definition name of + * "learner.mark" becomes output.desc.learner.mark. + * + * If you want to use this to get an arbitrary string from the I18N files, + * then set addPrefix = false and the output.desc will not be added to the + * beginning. + */ + protected String getI18NText(String key, boolean addPrefix) { + String translatedText = null; - MessageSource tmpMsgSource = getMsgSource(); - if ( tmpMsgSource != null ) { - if ( addPrefix ) key = KEY_PREFIX + key; - Locale locale = LocaleContextHolder.getLocale(); - try { - translatedText = tmpMsgSource.getMessage(key,null,locale); - } catch ( NoSuchMessageException e ) { - log.warn("Unable to internationalise the text for key "+key+" as no matching key found in the msgSource"); - } - } else { - log.warn("Unable to internationalise the text for key "+key+" as no matching key found in the msgSource. The tool's OutputDefinition factory needs to set either (a) messageSource or (b) loadedMessageSourceService and languageFilename."); - } - - if ( translatedText == null || translatedText.length() == 0 ) { - translatedText = key.replace('.', ' '); - } - - return translatedText; + MessageSource tmpMsgSource = getMsgSource(); + if (tmpMsgSource != null) { + if (addPrefix) + key = KEY_PREFIX + key; + Locale locale = LocaleContextHolder.getLocale(); + try { + translatedText = tmpMsgSource.getMessage(key, null, locale); + } catch (NoSuchMessageException e) { + log.warn("Unable to internationalise the text for key " + key + + " as no matching key found in the msgSource"); + } + } else { + log + .warn("Unable to internationalise the text for key " + + key + + " as no matching key found in the msgSource. The tool's OutputDefinition factory needs to set either (a) messageSource or (b) loadedMessageSourceService and languageFilename."); } - /** - * Get the MsgSource, combining getToolMessageService() and getLoadedMessageSourceService(). Caches the result so it only needs to be calculated once (most tools will require - * more than one call to this code! - */ - private MessageSource getMsgSource() { - if ( msgSource == null ) { - if ( getToolMessageService() != null ) { - msgSource = getToolMessageService().getMessageSource(); - } - if ( msgSource == null && getLoadedMessageSourceService() != null && getLanguageFilename() != null) { - msgSource = getLoadedMessageSourceService().getMessageService(getLanguageFilename()); - } - } - return msgSource; + if (translatedText == null || translatedText.length() == 0) { + translatedText = key.replace('.', ' '); } - /** Generic method for building a tool output definition. It will get the definition's description - * from the I18N file using the getDescription() method. - * Only use if the other buildBlahDefinitions do not suit your needs. */ - protected ToolOutputDefinition buildDefinition(String definitionName, OutputType type, Object startValue, Object endValue, Object complexValue, Boolean showConditionNameOnly) { - ToolOutputDefinition definition = new ToolOutputDefinition(); - definition.setName(definitionName); - definition.setDescription(getI18NText(definitionName, true)); - definition.setType(type); - definition.setStartValue( startValue ); - definition.setEndValue( endValue ); - definition.setComplexDefinition( complexValue ); - definition.setShowConditionNameOnly( showConditionNameOnly ); - return definition; - } + return translatedText; + } - /** Build a tool definition designed for a range of integer values. - * It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_LONG. */ - protected ToolOutputDefinition buildRangeDefinition(String definitionName, Long startValue, Long endValue) { - return buildDefinition(definitionName, OutputType.OUTPUT_LONG, startValue, endValue, null, Boolean.FALSE); + /** + * Get the MsgSource, combining getToolMessageService() and + * getLoadedMessageSourceService(). Caches the result so it only needs to be + * calculated once (most tools will require more than one call to this code! + */ + private MessageSource getMsgSource() { + if (msgSource == null) { + if (getToolMessageService() != null) { + msgSource = getToolMessageService().getMessageSource(); + } + if (msgSource == null && getLoadedMessageSourceService() != null && getLanguageFilename() != null) { + msgSource = getLoadedMessageSourceService().getMessageService(getLanguageFilename()); + } } - - /** Build a tool definition designed for a range of string values. - * It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_LONG. */ - protected ToolOutputDefinition buildRangeDefinition(String definitionName, String startValue, String endValue) { - return buildDefinition(definitionName, OutputType.OUTPUT_STRING, startValue, endValue, null, Boolean.FALSE); - } + return msgSource; + } - /** Build a tool definition designed for a single double value, which is likely to be a statistic number of - * questions answered - * It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_LONG. */ - protected ToolOutputDefinition buildLongOutputDefinition(String definitionName) { - return buildDefinition(definitionName, OutputType.OUTPUT_LONG, null, null, null, Boolean.FALSE); - } + /** + * Generic method for building a tool output definition. It will get the + * definition's description from the I18N file using the getDescription() + * method. Only use if the other buildBlahDefinitions do not suit your + * needs. + */ + protected ToolOutputDefinition buildDefinition(String definitionName, OutputType type, Object startValue, + Object endValue, Object complexValue, Boolean showConditionNameOnly) { + ToolOutputDefinition definition = new ToolOutputDefinition(); + definition.setName(definitionName); + definition.setDescription(getI18NText(definitionName, true)); + definition.setType(type); + definition.setStartValue(startValue); + definition.setEndValue(endValue); + definition.setComplexDefinition(complexValue); + definition.setShowConditionNameOnly(showConditionNameOnly); + return definition; + } - /** Build a tool definition designed for a single double value, which is likely to be a statistic such as average - * number of posts. - * It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_DOUBLE. */ - protected ToolOutputDefinition buildDoubleOutputDefinition(String definitionName) { - return buildDefinition(definitionName, OutputType.OUTPUT_DOUBLE, null, null, null, Boolean.FALSE); - } + /** + * Wrapper method for build definition to set the isDefaultGradebookMark + * flag + */ + protected ToolOutputDefinition buildDefinition(String definitionName, OutputType type, Object startValue, + Object endValue, Object complexValue, Boolean showConditionNameOnly, Boolean isDefaultGradebookMark) { + ToolOutputDefinition definition = this.buildDefinition(definitionName, type, startValue, endValue, + complexValue, showConditionNameOnly); + definition.setIsDefaultGradebookMark(isDefaultGradebookMark); + return definition; + } - /** Build a tool definition designed for a single boolean value, which is likely to be a test such as - * user has answered all questions correctly. It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_BOOLEAN. A Boolean tool definition should have default condition name for the - * true and false conditions. The code will automatically look for two strings in the I18N file - * output.desc..true and output.desc..false */ - protected ToolOutputDefinition buildBooleanOutputDefinition(String definitionName) { - ToolOutputDefinition definition = buildDefinition(definitionName, OutputType.OUTPUT_BOOLEAN, null, null, null, Boolean.FALSE); + /** + * Build a tool definition designed for a range of integer values. It will + * get the definition's description from the I18N file using the + * getDescription() method and set the type to OUTPUT_LONG. + */ + protected ToolOutputDefinition buildRangeDefinition(String definitionName, Long startValue, Long endValue) { + return buildDefinition(definitionName, OutputType.OUTPUT_LONG, startValue, endValue, null, Boolean.FALSE); + } - List defaultConditions = new ArrayList(); - defaultConditions.add(new BranchCondition(null, null, new Integer(1), definitionName, - getI18NText(definitionName+".true", true), - OutputType.OUTPUT_BOOLEAN.toString(), null, null, Boolean.TRUE.toString())); + /** + * Build a tool definition designed for a range of string values. It will + * get the definition's description from the I18N file using the + * getDescription() method and set the type to OUTPUT_LONG. + */ + protected ToolOutputDefinition buildRangeDefinition(String definitionName, String startValue, String endValue) { + return buildDefinition(definitionName, OutputType.OUTPUT_STRING, startValue, endValue, null, Boolean.FALSE); + } - defaultConditions.add(new BranchCondition(null, null, new Integer(2), definitionName, - getI18NText(definitionName+".false", true), - OutputType.OUTPUT_BOOLEAN.toString(), null, null, Boolean.FALSE.toString())); + /** + * Wrapper for buildRangeDefinition so you can set isDefaultGradebookMark + */ + protected ToolOutputDefinition buildRangeDefinition(String definitionName, Long startValue, Long endValue, + Boolean isDefaultGradebookMark) { + return buildDefinition(definitionName, OutputType.OUTPUT_LONG, startValue, endValue, null, Boolean.FALSE, + isDefaultGradebookMark); + } - definition.setDefaultConditions(defaultConditions); - - return definition; - } - - /** Build a tool definition designed for a set of boolean conditions. It will get the definition's description from the - * I18N file using the getDescription() method and set the type to OUTPUT_SET_BOOLEAN. The tool's factory should then - * set up a series of conditions, each of type OUTPUT_BOOLEAN. Sets showConditionNameOnly to true so that the user - * in authoring doesn't see the internal definitions, just the condition name. - */ - protected ToolOutputDefinition buildBooleanSetOutputDefinition(String definitionName) { - ToolOutputDefinition definition = buildDefinition(definitionName, OutputType.OUTPUT_SET_BOOLEAN, null, null, null, Boolean.TRUE); - List defaultConditions = new ArrayList(); - definition.setDefaultConditions(defaultConditions); - return definition; - } - + /** + * Wrapper for buildRangeDefinition so you can set isDefaultGradebookMark + */ + protected ToolOutputDefinition buildRangeDefinition(String definitionName, String startValue, String endValue, + Boolean isDefaultGradebookMark) { + return buildDefinition(definitionName, OutputType.OUTPUT_STRING, startValue, endValue, null, Boolean.FALSE, + isDefaultGradebookMark); + } - /** Build a tool definition designed for a single String value. - * It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_STRING. */ - protected ToolOutputDefinition buildStringOutputDefinition(String definitionName) { - return buildDefinition(definitionName, OutputType.OUTPUT_STRING, null, null, null, Boolean.FALSE); - } + /** + * Build a tool definition designed for a single double value, which is + * likely to be a statistic number of questions answered It will get the + * definition's description from the I18N file using the getDescription() + * method and set the type to OUTPUT_LONG. + */ + protected ToolOutputDefinition buildLongOutputDefinition(String definitionName) { + return buildDefinition(definitionName, OutputType.OUTPUT_LONG, null, null, null, Boolean.FALSE); + } - /** Build a tool definition for a complex value output. - * It will get the definition's description from the I18N file using the getDescription() method and - * set the type to OUTPUT_COMPLEX. */ - protected ToolOutputDefinition buildComplexOutputDefinition(String definitionName) { - return buildDefinition(definitionName, OutputType.OUTPUT_COMPLEX, null, null, null, Boolean.FALSE); - } + /** + * Build a tool definition designed for a single double value, which is + * likely to be a statistic such as average number of posts. It will get the + * definition's description from the I18N file using the getDescription() + * method and set the type to OUTPUT_DOUBLE. + */ + protected ToolOutputDefinition buildDoubleOutputDefinition(String definitionName) { + return buildDefinition(definitionName, OutputType.OUTPUT_DOUBLE, null, null, null, Boolean.FALSE); + } - /** - * Build a condition name based on a definition name. For user customised conditions, the - * conditions name MUST start with the definition name for Flash to be able to match conditions to definition - * in the authoring interface, but then each condition name needs to be unique, hence "uniquePart". - * @param definitionName: Must not be null - * @param uniquePart: May be null if the condition names are to be the same as the definition name. - * @return combined string - */ - protected String buildConditionName(String definitionName, String uniquePart) { - return uniquePart != null && uniquePart.length() > 0 ? definitionName + CONDITION_NAME_SEPARATOR + uniquePart : definitionName; - } + /** + * Build a tool definition designed for a single boolean value, which is + * likely to be a test such as user has answered all questions correctly. It + * will get the definition's description from the I18N file using the + * getDescription() method and set the type to OUTPUT_BOOLEAN. A Boolean + * tool definition should have default condition name for the true and false + * conditions. The code will automatically look for two strings in the I18N + * file output.desc..true and output.desc..false + */ + protected ToolOutputDefinition buildBooleanOutputDefinition(String definitionName) { + ToolOutputDefinition definition = buildDefinition(definitionName, OutputType.OUTPUT_BOOLEAN, null, null, null, + Boolean.FALSE); - /** - * Given a condition name built with buildConditionName, split is back into its definition name and unique part. - * @param conditionName: Must not be null - * @return String[definition name, unique part] - */ - protected String[] splitConditionName(String conditionName) { - int index = conditionName.indexOf(CONDITION_NAME_SEPARATOR); - if ( index > -1 ) { - if ( index+1 defaultConditions = new ArrayList(); + defaultConditions.add(new BranchCondition(null, null, new Integer(1), definitionName, getI18NText( + definitionName + ".true", true), OutputType.OUTPUT_BOOLEAN.toString(), null, null, Boolean.TRUE + .toString())); + + defaultConditions.add(new BranchCondition(null, null, new Integer(2), definitionName, getI18NText( + definitionName + ".false", true), OutputType.OUTPUT_BOOLEAN.toString(), null, null, Boolean.FALSE + .toString())); + + definition.setDefaultConditions(defaultConditions); + + return definition; + } + + /** + * Build a tool definition designed for a set of boolean conditions. It will + * get the definition's description from the I18N file using the + * getDescription() method and set the type to OUTPUT_SET_BOOLEAN. The + * tool's factory should then set up a series of conditions, each of type + * OUTPUT_BOOLEAN. Sets showConditionNameOnly to true so that the user in + * authoring doesn't see the internal definitions, just the condition name. + */ + protected ToolOutputDefinition buildBooleanSetOutputDefinition(String definitionName) { + ToolOutputDefinition definition = buildDefinition(definitionName, OutputType.OUTPUT_SET_BOOLEAN, null, null, + null, Boolean.TRUE); + List defaultConditions = new ArrayList(); + definition.setDefaultConditions(defaultConditions); + return definition; + } + + /** + * Build a tool definition designed for a single String value. It will get + * the definition's description from the I18N file using the + * getDescription() method and set the type to OUTPUT_STRING. + */ + protected ToolOutputDefinition buildStringOutputDefinition(String definitionName) { + return buildDefinition(definitionName, OutputType.OUTPUT_STRING, null, null, null, Boolean.FALSE); + } + + /** + * Build a tool definition for a complex value output. It will get the + * definition's description from the I18N file using the getDescription() + * method and set the type to OUTPUT_COMPLEX. + */ + protected ToolOutputDefinition buildComplexOutputDefinition(String definitionName) { + return buildDefinition(definitionName, OutputType.OUTPUT_COMPLEX, null, null, null, Boolean.FALSE); + } + + /** + * Build a condition name based on a definition name. For user customised + * conditions, the conditions name MUST start with the definition name for + * Flash to be able to match conditions to definition in the authoring + * interface, but then each condition name needs to be unique, hence + * "uniquePart". + * + * @param definitionName: + * Must not be null + * @param uniquePart: + * May be null if the condition names are to be the same as + * the definition name. + * @return combined string + */ + protected String buildConditionName(String definitionName, String uniquePart) { + return uniquePart != null && uniquePart.length() > 0 ? definitionName + CONDITION_NAME_SEPARATOR + uniquePart + : definitionName; + } + + /** + * Given a condition name built with buildConditionName, split is back into + * its definition name and unique part. + * + * @param conditionName: + * Must not be null + * @return String[definition name, unique part] + */ + protected String[] splitConditionName(String conditionName) { + int index = conditionName.indexOf(CONDITION_NAME_SEPARATOR); + if (index > -1) { + if (index + 1 < conditionName.length()) + return new String[] { conditionName.substring(0, index), conditionName.substring(index + 1) }; + else + return new String[] { conditionName.substring(0, index), "" }; + } else { + return new String[] { conditionName, "" }; } + } } Index: lams_common/src/java/org/lamsfoundation/lams/tool/ToolOutputDefinition.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/tool/ToolOutputDefinition.java,v diff -u -r1.4.6.1 -r1.4.6.2 --- lams_common/src/java/org/lamsfoundation/lams/tool/ToolOutputDefinition.java 20 Apr 2009 04:37:37 -0000 1.4.6.1 +++ lams_common/src/java/org/lamsfoundation/lams/tool/ToolOutputDefinition.java 20 Apr 2009 05:14:45 -0000 1.4.6.2 @@ -59,6 +59,7 @@ private Object endValue; private Object complexDefinition; private Boolean showConditionNameOnly; + private Boolean isDefaultGradebookMark; private List defaultConditions; /** @@ -186,4 +187,19 @@ this.showConditionNameOnly = showConditionNameOnly; } + /** + * If set, this flag makes the current tool output definition the default + * output to go straight to gradebook marks when the user completes an + * activity. There should only be one of these per tool. + * + * @return + */ + public Boolean isDefaultGradebookMark() { + return isDefaultGradebookMark; + } + + public void setIsDefaultGradebookMark(Boolean isDefaultGradebookMark) { + this.isDefaultGradebookMark = isDefaultGradebookMark; + } + } Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/MCOutputFactory.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/MCOutputFactory.java,v diff -u -r1.4 -r1.4.6.1 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/MCOutputFactory.java 6 Aug 2008 23:53:12 -0000 1.4 +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/MCOutputFactory.java 20 Apr 2009 05:14:46 -0000 1.4.6.1 @@ -23,11 +23,8 @@ /* $Id$ */ package org.lamsfoundation.lams.tool.mc.service; -import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; @@ -40,140 +37,140 @@ import org.lamsfoundation.lams.tool.mc.pojos.McQueUsr; import org.lamsfoundation.lams.tool.mc.pojos.McSession; import org.lamsfoundation.lams.tool.mc.pojos.McUsrAttempt; -import org.lamsfoundation.lams.tool.mc.web.LearningUtil; public class MCOutputFactory extends OutputFactory { - protected static final String OUTPUT_NAME_LEARNER_MARK = "learner.mark"; - protected static final String OUTPUT_NAME_LEARNER_ALL_CORRECT = "learner.all.correct"; - - /** - * @see org.lamsfoundation.lams.tool.OutputDefinitionFactory#getToolOutputDefinitions(java.lang.Object) - */ - public SortedMap getToolOutputDefinitions(Object toolContentObject) { - - TreeMap definitionMap = new TreeMap(); - ToolOutputDefinition definition = buildBooleanOutputDefinition(OUTPUT_NAME_LEARNER_ALL_CORRECT); - definitionMap.put(OUTPUT_NAME_LEARNER_ALL_CORRECT, definition); + protected static final String OUTPUT_NAME_LEARNER_MARK = "learner.mark"; + protected static final String OUTPUT_NAME_LEARNER_ALL_CORRECT = "learner.all.correct"; - if ( toolContentObject != null ) { - McContent content = (McContent) toolContentObject; - - definition = buildRangeDefinition(OUTPUT_NAME_LEARNER_MARK, - new Long(0), - new Long ( content.getTotalMarksPossible().longValue() ) ); - definitionMap.put(OUTPUT_NAME_LEARNER_MARK, definition); - } else { - log.error("Unable to build content based output definitions for Multiple Choice as no tool content object supplied. Only including the definitions that do not need any content."); - } + /** + * @see org.lamsfoundation.lams.tool.OutputDefinitionFactory#getToolOutputDefinitions(java.lang.Object) + */ + public SortedMap getToolOutputDefinitions(Object toolContentObject) { - return definitionMap; + TreeMap definitionMap = new TreeMap(); + ToolOutputDefinition definition = buildBooleanOutputDefinition(OUTPUT_NAME_LEARNER_ALL_CORRECT); + definitionMap.put(OUTPUT_NAME_LEARNER_ALL_CORRECT, definition); + + if (toolContentObject != null) { + McContent content = (McContent) toolContentObject; + + definition = buildRangeDefinition(OUTPUT_NAME_LEARNER_MARK, new Long(0), new Long(content + .getTotalMarksPossible().longValue()), true); + definitionMap.put(OUTPUT_NAME_LEARNER_MARK, definition); + } else { + log + .error("Unable to build content based output definitions for Multiple Choice as no tool content object supplied. Only including the definitions that do not need any content."); } - public SortedMap getToolOutput(List names, IMcService mcService, Long toolSessionId, Long learnerId) { - - TreeMap output = new TreeMap(); + return definitionMap; + } - McSession session = mcService.findMcSessionById(toolSessionId); - if ( session != null ) { + public SortedMap getToolOutput(List names, IMcService mcService, Long toolSessionId, + Long learnerId) { - McQueUsr queUser = mcService.getMcUserBySession(learnerId, session.getUid()); - if ( queUser != null ) { - - if ( names == null || names.contains(OUTPUT_NAME_LEARNER_MARK) ) { - output.put(OUTPUT_NAME_LEARNER_MARK, getLearnerMark(queUser) ); - } - if ( names == null || names.contains(OUTPUT_NAME_LEARNER_ALL_CORRECT) ) { - output.put(OUTPUT_NAME_LEARNER_ALL_CORRECT, getLearnerAllCorrect(mcService, queUser) ); - } - } - } - - return output; - } + TreeMap output = new TreeMap(); - public ToolOutput getToolOutput(String name, IMcService mcService, Long toolSessionId, Long learnerId) { - if ( name != null ) { - McSession session = mcService.findMcSessionById(toolSessionId); - if ( session != null ) { - McQueUsr queUser = mcService.getMcUserBySession(learnerId, session.getUid()); - - if ( queUser != null ) { - if ( name.equals(OUTPUT_NAME_LEARNER_MARK) ) { - return getLearnerMark(queUser); - } else if ( name.equals(OUTPUT_NAME_LEARNER_ALL_CORRECT) ){ - return getLearnerAllCorrect(mcService, queUser); - } - } - } + McSession session = mcService.findMcSessionById(toolSessionId); + if (session != null) { + + McQueUsr queUser = mcService.getMcUserBySession(learnerId, session.getUid()); + if (queUser != null) { + + if (names == null || names.contains(OUTPUT_NAME_LEARNER_MARK)) { + output.put(OUTPUT_NAME_LEARNER_MARK, getLearnerMark(queUser)); } - return null; + if (names == null || names.contains(OUTPUT_NAME_LEARNER_ALL_CORRECT)) { + output.put(OUTPUT_NAME_LEARNER_ALL_CORRECT, getLearnerAllCorrect(mcService, queUser)); + } + } } - /** - * Get the mark for a specific user. This gets the mark associated with the last attempt. - * Will always return a ToolOutput object. - */ - private ToolOutput getLearnerMark(McQueUsr queUser) { - Long mark; - if (queUser != null && queUser.getLastAttemptTotalMark() != null) { - mark = queUser.getLastAttemptTotalMark().longValue(); - } else { - mark = new Long(0); + return output; + } + + public ToolOutput getToolOutput(String name, IMcService mcService, Long toolSessionId, Long learnerId) { + if (name != null) { + McSession session = mcService.findMcSessionById(toolSessionId); + if (session != null) { + McQueUsr queUser = mcService.getMcUserBySession(learnerId, session.getUid()); + + if (queUser != null) { + if (name.equals(OUTPUT_NAME_LEARNER_MARK)) { + return getLearnerMark(queUser); + } else if (name.equals(OUTPUT_NAME_LEARNER_ALL_CORRECT)) { + return getLearnerAllCorrect(mcService, queUser); + } } - return new ToolOutput(MCOutputFactory.OUTPUT_NAME_LEARNER_MARK, - getI18NText(MCOutputFactory.OUTPUT_NAME_LEARNER_MARK, true), mark); + } } + return null; + } - /** - * Did the user get the questions all correct. This checks the answers associated with the last attempt. - * Assumes all correct if the mark is equal to the maximum possible mark. - * Will always return a ToolOutput object. - */ - private ToolOutput getLearnerAllCorrect(IMcService mcService, McQueUsr queUser) { - boolean allCorrect = allQuestionsCorrect(mcService, queUser); - return new ToolOutput(MCOutputFactory.OUTPUT_NAME_LEARNER_ALL_CORRECT, - getI18NText(MCOutputFactory.OUTPUT_NAME_LEARNER_ALL_CORRECT, true), allCorrect); + /** + * Get the mark for a specific user. This gets the mark associated with the + * last attempt. Will always return a ToolOutput object. + */ + private ToolOutput getLearnerMark(McQueUsr queUser) { + Long mark; + if (queUser != null && queUser.getLastAttemptTotalMark() != null) { + mark = queUser.getLastAttemptTotalMark().longValue(); + } else { + mark = new Long(0); } + return new ToolOutput(MCOutputFactory.OUTPUT_NAME_LEARNER_MARK, getI18NText( + MCOutputFactory.OUTPUT_NAME_LEARNER_MARK, true), mark); + } - // written to cope with more than one correct option for each question but only tested with - // one correct option for a question. + /** + * Did the user get the questions all correct. This checks the answers + * associated with the last attempt. Assumes all correct if the mark is + * equal to the maximum possible mark. Will always return a ToolOutput + * object. + */ + private ToolOutput getLearnerAllCorrect(IMcService mcService, McQueUsr queUser) { + boolean allCorrect = allQuestionsCorrect(mcService, queUser); + return new ToolOutput(MCOutputFactory.OUTPUT_NAME_LEARNER_ALL_CORRECT, getI18NText( + MCOutputFactory.OUTPUT_NAME_LEARNER_ALL_CORRECT, true), allCorrect); + } + + // written to cope with more than one correct option for each question but only tested with + // one correct option for a question. private boolean allQuestionsCorrect(IMcService mcService, McQueUsr queUser) { - // Build a list of all the correct answers. If we hit any options that are not a correct option - // we can abort as we know there is a wrong answer. - // Otherwise count the number of correct options overall (for comparison later). - long correctlearnerOptions = 0; - List latestAttempts = (List) mcService.getLatestAttemptsForAUser(queUser.getUid()); - for ( McUsrAttempt mcUsrAttempt : latestAttempts ) { - McOptsContent mcOptsContent = mcUsrAttempt.getMcOptionsContent(); - if ( ! mcOptsContent.isCorrectOption() ) { - // wrong answer so no point going any further - return false; - } else { - correctlearnerOptions++; - } - } + // Build a list of all the correct answers. If we hit any options that are not a correct option + // we can abort as we know there is a wrong answer. + // Otherwise count the number of correct options overall (for comparison later). + long correctlearnerOptions = 0; + List latestAttempts = (List) mcService.getLatestAttemptsForAUser(queUser.getUid()); + for (McUsrAttempt mcUsrAttempt : latestAttempts) { + McOptsContent mcOptsContent = mcUsrAttempt.getMcOptionsContent(); + if (!mcOptsContent.isCorrectOption()) { + // wrong answer so no point going any further + return false; + } else { + correctlearnerOptions++; + } + } - // now count the overall number of correct options - long correctOptions = 0; - McContent mcContent = queUser.getMcSession().getMcContent(); - Iterator questionIterator = mcContent.getMcQueContents().iterator(); - while (questionIterator.hasNext()) - { - McQueContent mcQueContent = (McQueContent) questionIterator.next(); - Iterator optionIterator = mcQueContent.getMcOptionsContents().iterator(); - while ( optionIterator.hasNext() ) { - McOptsContent mcOptsContent = (McOptsContent) optionIterator.next(); - if ( mcOptsContent.isCorrectOption() ) { - correctOptions++; - } - } - } + // now count the overall number of correct options + long correctOptions = 0; + McContent mcContent = queUser.getMcSession().getMcContent(); + Iterator questionIterator = mcContent.getMcQueContents().iterator(); + while (questionIterator.hasNext()) { + McQueContent mcQueContent = (McQueContent) questionIterator.next(); + Iterator optionIterator = mcQueContent.getMcOptionsContents().iterator(); + while (optionIterator.hasNext()) { + McOptsContent mcOptsContent = (McOptsContent) optionIterator.next(); + if (mcOptsContent.isCorrectOption()) { + correctOptions++; + } + } + } - // We know the user didn't get everything wrong, but did they answer enough options correctly? - // This case is used when there is more than one correct option for each answer. Simple way, compare counts! - return correctOptions == correctlearnerOptions; + // We know the user didn't get everything wrong, but did they answer enough options correctly? + // This case is used when there is more than one correct option for each answer. Simple way, compare counts! + return correctOptions == correctlearnerOptions; } }