Fisheye: Tag 1.2 refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/tool/OutputDefinitionFactory.java'. Fisheye: No comparison available. Pass `N' to diff? 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 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_common/src/java/org/lamsfoundation/lams/tool/OutputFactory.java 21 Sep 2007 06:52:09 -0000 1.1 @@ -0,0 +1,234 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id: OutputFactory.java,v 1.1 2007/09/21 06:52:09 fmalikoff Exp $ */ +package org.lamsfoundation.lams.tool; + +import java.util.List; +import java.util.Locale; +import java.util.SortedMap; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.util.ILoadedMessageSourceService; +import org.lamsfoundation.lams.util.MessageService; + +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 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 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. + * + * Example definitions for tool factories: + * + * + * org.lamsfoundation.lams.tool.mc.ApplicationResources + * + * + * + * + * + * + */ +public abstract class OutputFactory { + + protected Logger log = Logger.getLogger(OutputFactory.class); + + private MessageService toolMessageService; + + private ILoadedMessageSourceService loadedMessageSourceService; + private String languageFilename; + protected final String KEY_PREFIX = "output.desc."; + + /** 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; + + /** Tool specific toolMessageService, such as the forumMessageService in the Forum tool */ + public 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. */ + public ILoadedMessageSourceService getLoadedMessageSourceService() { + return 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; + } + + /** 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 definitionName. If the tool has supplied a messageService, then this + * is used to look up the key and hence get the description. 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 description. + * + * The key must be in the format output.desc.[definition name]. For example a + * definition name of "learner.mark" becomes output.desc.learner.mark. + */ + protected String getDescription(String definitionName) { + MessageSource msgSource = null; + if ( getToolMessageService() != null ) { + msgSource = getToolMessageService().getMessageSource(); + } + if ( msgSource == null && getLoadedMessageSourceService() != null && getLanguageFilename() != null) { + msgSource = getLoadedMessageSourceService().getMessageService(getLanguageFilename()); + } + if ( msgSource == null ) { + log.warn("Unable to internationalise the description for the output definition "+definitionName+" as no MessageSource is available. "+ + "The tool's OutputDefinition factory needs to set either (a) messageSource or (b) loadedMessageSourceService and languageFilename."); + } + + String description = null; + if ( msgSource != null ) { + String key = KEY_PREFIX + definitionName; + Locale locale = LocaleContextHolder.getLocale(); + try { + description = msgSource.getMessage(key,null,locale); + } catch ( NoSuchMessageException e ) { + } + } + if ( description == null || description.length() == 0 ) { + description = definitionName.replace('.', ' '); + } + + return description; + } + + /** 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) { + ToolOutputDefinition definition = new ToolOutputDefinition(); + definition.setName(definitionName); + definition.setDescription(getDescription(definitionName)); + definition.setType(type); + definition.setStartValue( startValue ); + definition.setEndValue( endValue ); + definition.setComplexDefinition( complexValue ); + return definition; + } + + //The mark for a user's last attempt at answering the question(s). + /** 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); + } + + /** 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); + } + + /** 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); + } + + /** 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); + } + + /** 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. */ + protected ToolOutputDefinition buildBooleanOutputDefinition(String definitionName) { + return buildDefinition(definitionName, OutputType.OUTPUT_BOOLEAN, null, null, null); + } + + /** 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); + } + + /** 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); + } + +} Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/forumApplicationContext.xml =================================================================== RCS file: /usr/local/cvsroot/lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/forumApplicationContext.xml,v diff -u -r1.16 -r1.17 --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/forumApplicationContext.xml 22 Aug 2007 07:07:00 -0000 1.16 +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/forumApplicationContext.xml 21 Sep 2007 06:53:37 -0000 1.17 @@ -66,7 +66,7 @@ - + @@ -110,7 +110,7 @@ - + Fisheye: Tag 1.3 refers to a dead (removed) revision in file `lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumOutputDefinitionFactory.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumOutputFactory.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumOutputFactory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumOutputFactory.java 21 Sep 2007 06:53:37 -0000 1.1 @@ -0,0 +1,83 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id: ForumOutputFactory.java,v 1.1 2007/09/21 06:53:37 fmalikoff Exp $ */ +package org.lamsfoundation.lams.tool.forum.service; + +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.lamsfoundation.lams.tool.OutputFactory; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.exception.ToolException; + +/** + * Creates the output definitions for forum. Eventually there will be a definition + * that outputs some or all of the forum queries, but for now there are just a couple of + * simple definitions so that we can try various features of the tool output based + * branching. + */ +public class ForumOutputFactory extends OutputFactory { + + /** The number of posts the learner has made in one forum activity. */ + protected final static String OUTPUT_NAME_LEARNER_NUM_POSTS = "learner.number.of.posts"; + + /** + * @see org.lamsfoundation.lams.tool.OutputDefinitionFactory#getToolOutputDefinitions(java.lang.Object) + */ + public SortedMap getToolOutputDefinitions( + Object toolContentObject) throws ToolException { + TreeMap definitionMap = new TreeMap(); + + ToolOutputDefinition definition = buildLongOutputDefinition(OUTPUT_NAME_LEARNER_NUM_POSTS); + definitionMap.put(OUTPUT_NAME_LEARNER_NUM_POSTS, definition); + + return definitionMap; + } + + public SortedMap getToolOutput(List names, IForumService forumService, + Long toolSessionId, Long learnerId) { + + TreeMap map = new TreeMap(); + if ( names == null || names.contains(OUTPUT_NAME_LEARNER_NUM_POSTS)) { + map.put(OUTPUT_NAME_LEARNER_NUM_POSTS,getNumPosts(forumService, learnerId, toolSessionId)); + } + return map; + + } + + public ToolOutput getToolOutput(String name, IForumService forumService, Long toolSessionId, Long learnerId) { + + if ( name != null && name.equals(OUTPUT_NAME_LEARNER_NUM_POSTS)) { + return getNumPosts(forumService, learnerId, toolSessionId); + } + return null; + + } + + private ToolOutput getNumPosts(IForumService forumService, Long learnerId, Long toolSessionId) { + int num = forumService.getTopicsNum(learnerId, toolSessionId); + return new ToolOutput(OUTPUT_NAME_LEARNER_NUM_POSTS, "", new Long(num)); + } +} Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java,v diff -u -r1.86 -r1.87 --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java 5 Sep 2007 08:06:59 -0000 1.86 +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java 21 Sep 2007 06:53:36 -0000 1.87 @@ -127,7 +127,7 @@ private IExportToolContentService exportContentService; private IUserManagementService userManagementService; private ICoreNotebookService coreNotebookService; - private ForumOutputDefinitionFactory forumOuputDefinitionFactory; + private ForumOutputFactory forumOutputFactory; //--------------------------------------------------------------------- // Inversion of Control Methods - Method injection @@ -144,13 +144,13 @@ this.messageService = messageService; } - public ForumOutputDefinitionFactory getForumOuputDefinitionFactory() { - return forumOuputDefinitionFactory; + public ForumOutputFactory getForumOutputFactory() { + return forumOutputFactory; } - public void setForumOuputDefinitionFactory( - ForumOutputDefinitionFactory forumOuputDefinitionFactory) { - this.forumOuputDefinitionFactory = forumOuputDefinitionFactory; + public void setForumOutputFactory( + ForumOutputFactory forumOutputFactory) { + this.forumOutputFactory = forumOutputFactory; } public Forum updateForum(Forum forum) throws PersistenceException { @@ -790,7 +790,7 @@ if ( forum == null ) { forum = getDefaultForum(); } - return getForumOuputDefinitionFactory().getToolOutputDefinitions(forum); + return getForumOutputFactory().getToolOutputDefinitions(forum); } @@ -850,13 +850,7 @@ public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { - TreeMap map = new TreeMap(); - if ( names == null || names.contains(ForumOutputDefinitionFactory.OUTPUT_NAME_LEARNER_NUM_POSTS)) { - log.error("Forum getToolOutput(): Not implemented properly yet - just returning 0"); - ToolOutput output = new ToolOutput(ForumOutputDefinitionFactory.OUTPUT_NAME_LEARNER_NUM_POSTS, "", new Long(0)); - map.put(ForumOutputDefinitionFactory.OUTPUT_NAME_LEARNER_NUM_POSTS,output); - } - return map; + return forumOutputFactory.getToolOutput(names, this, toolSessionId, learnerId); } @@ -866,12 +860,7 @@ */ public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { - if ( ForumOutputDefinitionFactory.OUTPUT_NAME_LEARNER_NUM_POSTS.equals(name) ) { - log.error("Forum getToolOutput(): Not implemented properly yet - just returning 0"); - return new ToolOutput(ForumOutputDefinitionFactory.OUTPUT_NAME_LEARNER_NUM_POSTS, "", new Long(0)); - } - - return null; + return forumOutputFactory.getToolOutput(name, this, toolSessionId, learnerId); } /* (non-Javadoc) Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/mcApplicationContext.xml =================================================================== RCS file: /usr/local/cvsroot/lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/mcApplicationContext.xml,v diff -u -r1.16 -r1.17 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/mcApplicationContext.xml 22 Aug 2007 07:07:14 -0000 1.16 +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/mcApplicationContext.xml 21 Sep 2007 06:52:48 -0000 1.17 @@ -70,7 +70,7 @@ - + org.lamsfoundation.lams.tool.mc.ApplicationResources @@ -93,7 +93,7 @@ - + Fisheye: Tag 1.4 refers to a dead (removed) revision in file `lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/MCOutputDefinitionFactory.java'. Fisheye: No comparison available. Pass `N' to diff? 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 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/MCOutputFactory.java 21 Sep 2007 06:52:48 -0000 1.1 @@ -0,0 +1,163 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +/* $Id: MCOutputFactory.java,v 1.1 2007/09/21 06:52:48 fmalikoff Exp $ */ +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; + +import org.lamsfoundation.lams.tool.OutputFactory; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.mc.pojos.McContent; +import org.lamsfoundation.lams.tool.mc.pojos.McOptsContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueContent; +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); + + 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."); + } + + return definitionMap; + } + + public SortedMap getToolOutput(List names, IMcService mcService, Long toolSessionId, Long learnerId) { + + McSession session = mcService.findMcSessionById(toolSessionId); + McQueUsr queUser = mcService.getMcUserBySession(learnerId, session.getUid()); + + TreeMap output = new TreeMap(); + 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; + } + + public ToolOutput getToolOutput(String name, IMcService mcService, Long toolSessionId, Long learnerId) { + if ( name != null ) { + McSession session = mcService.findMcSessionById(toolSessionId); + McQueUsr queUser = mcService.getMcUserBySession(learnerId, session.getUid()); + + if ( name.equals(OUTPUT_NAME_LEARNER_MARK) ) { + return getLearnerMark(queUser); + } else if ( name.equals(OUTPUT_NAME_LEARNER_ALL_CORRECT) ){ + return getLearnerAllCorrect(mcService, queUser); + } + } + return null; + } + + /** + * 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 = queUser != null ? queUser.getLastAttemptTotalMark() : new Long(0); + return new ToolOutput(MCOutputFactory.OUTPUT_NAME_LEARNER_MARK, + getDescription(MCOutputFactory.OUTPUT_NAME_LEARNER_MARK), mark); + } + + /** + * 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, + getDescription(MCOutputFactory.OUTPUT_NAME_LEARNER_ALL_CORRECT), 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++; + } + } + + // 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; + } + +} Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McServicePOJO.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McServicePOJO.java,v diff -u -r1.99 -r1.100 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McServicePOJO.java 10 Sep 2007 04:25:07 -0000 1.99 +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/service/McServicePOJO.java 21 Sep 2007 06:52:47 -0000 1.100 @@ -120,7 +120,7 @@ private IMcUserDAO mcUserDAO; private IMcUsrAttemptDAO mcUsrAttemptDAO; private IMcUploadedFileDAO mcUploadedFileDAO; - private MCOutputDefinitionFactory mcOutputDefinitionFactory; + private MCOutputFactory mcOutputFactory; private IAuditService auditService; private IUserManagementService userManagementService; @@ -1560,7 +1560,7 @@ long defaultToolContentId = getToolDefaultContentIdBySignature(MY_SIGNATURE); content = retrieveMc(defaultToolContentId); } - return getMcOutputDefinitionFactory().getToolOutputDefinitions(content); + return getMcOutputFactory().getToolOutputDefinitions(content); } @@ -1823,16 +1823,7 @@ public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { - TreeMap output = new TreeMap(); - if ( names == null || names.contains(MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK) ) { - McSession session = findMcSessionById(toolSessionId); - McQueUsr queUser = getMcUserBySession(learnerId, session.getUid()); - Long mark = queUser != null ? queUser.getLastAttemptTotalMark() : new Long(0); - ToolOutput toolOutput = new ToolOutput(MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK, - MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK, mark); - output.put(MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK, toolOutput); - } - return output; + return mcOutputFactory.getToolOutput(names, this, toolSessionId, learnerId); } /** @@ -1841,14 +1832,7 @@ */ public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { - if ( name != null && name.equals(MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK) ) { - McSession session = findMcSessionById(toolSessionId); - McQueUsr queUser = getMcUserBySession(learnerId, session.getUid()); - Long mark = queUser != null ? queUser.getLastAttemptTotalMark() : new Long(0); - return new ToolOutput(MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK, - MCOutputDefinitionFactory.OUTPUT_NAME_LEARNER_MARK, mark); - } - return null; + return mcOutputFactory.getToolOutput(name, this, toolSessionId, learnerId); } @@ -2236,13 +2220,13 @@ this.exportContentService = exportContentService; } - public MCOutputDefinitionFactory getMcOutputDefinitionFactory() { - return mcOutputDefinitionFactory; + public MCOutputFactory getMcOutputFactory() { + return mcOutputFactory; } - public void setMcOutputDefinitionFactory( - MCOutputDefinitionFactory mcOutputDefinitionFactory) { - this.mcOutputDefinitionFactory = mcOutputDefinitionFactory; + public void setMcOutputFactory( + MCOutputFactory mcOutputFactory) { + this.mcOutputFactory = mcOutputFactory; } Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/LearningUtil.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/LearningUtil.java,v diff -u -r1.48 -r1.49 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/LearningUtil.java 15 Aug 2007 03:54:49 -0000 1.48 +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/LearningUtil.java 21 Sep 2007 06:52:48 -0000 1.49 @@ -22,12 +22,17 @@ /* $$Id$$ */ package org.lamsfoundation.lams.tool.mc.web; +import java.util.ArrayList; +import java.util.Collection; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; @@ -104,236 +109,31 @@ logger.debug("ending saveFormRequestData:"); } - - - - /** - * calculateWeights(Map mapLeanerAssessmentResults, Map mapQuestionWeights) + + /** A question is correct if the number of correct options and the number of checked options is the same, + * plus all the checked options appears in the correct options list. * - * @param mapLeanerAssessmentResults - * @param mapQuestionWeights - * @return int - */ - public static int calculateWeights(Map mapLeanerAssessmentResults, Map mapQuestionWeights) - { - logger.debug("starting calculate weights..."); - logger.debug("mapLeanerAssessmentResults : " + mapLeanerAssessmentResults); - logger.debug("mapQuestionWeights : " + mapQuestionWeights); - - int totalUserWeight=0; - Iterator itLearnerAssessmentMap = mapLeanerAssessmentResults.entrySet().iterator(); - while (itLearnerAssessmentMap.hasNext()) - { - Map.Entry pairs = (Map.Entry)itLearnerAssessmentMap.next(); - logger.debug("using the pair: " + pairs.getKey() + " = " + pairs.getValue()); - - Iterator itWeightsMap = mapQuestionWeights.entrySet().iterator(); - while (itWeightsMap.hasNext()) - { - Map.Entry pairsWeight = (Map.Entry)itWeightsMap.next(); - logger.debug("using the weight pair: " + pairsWeight.getKey() + " = " + pairsWeight.getValue()); - if (pairs.getKey().toString().equals(pairsWeight.getKey().toString())) - { - logger.debug("equal question found " + pairsWeight.getKey() + " = " + pairsWeight.getValue() + " and " + pairs.getValue()); - - if (pairs.getValue().toString().equalsIgnoreCase("true")) - { - logger.debug("equal question found " + pairsWeight.getKey() + " is a correct answer."); - int weight= new Integer(pairsWeight.getValue().toString()).intValue(); - logger.debug("weight: " + weight); - - totalUserWeight=totalUserWeight + weight; - } - } - } - } - logger.debug("totalUserWeight: " + totalUserWeight); - return totalUserWeight; - } - - /** - * conversts correct options list to correct options map - * buildMapCorrectOptions(List correctOptions) - * - * @param correctOptions - * @return Map - */ - public static Map buildMapCorrectOptions(List correctOptions) - { - Map mapCorrectOptions= new TreeMap(new McComparator()); - Iterator correctOptionsIterator=correctOptions.iterator(); - Long mapIndex=new Long(1); - while (correctOptionsIterator.hasNext()) - { - McOptsContent mcOptsContent=(McOptsContent)correctOptionsIterator.next(); - if (mcOptsContent != null) - { - mapCorrectOptions.put(mapIndex.toString(),mcOptsContent.getMcQueOptionText()); - mapIndex=new Long(mapIndex.longValue()+1); - } - } - logger.debug("mapCorrectOptions : " + mapCorrectOptions); - return mapCorrectOptions; - } - - - /** - * Map buildMapCorrectOptionUids(List correctOptions) - * - * @param correctOptions - * @return - */ - public static Map buildMapCorrectOptionUids(List correctOptions) - { - Map mapCorrectOptionUids= new TreeMap(new McComparator()); - Iterator correctOptionsIterator=correctOptions.iterator(); - Long mapIndex=new Long(1); - while (correctOptionsIterator.hasNext()) - { - McOptsContent mcOptsContent=(McOptsContent)correctOptionsIterator.next(); - if (mcOptsContent != null) - { - mapCorrectOptionUids.put(mapIndex.toString(),mcOptsContent.getUid().toString()); - mapIndex=new Long(mapIndex.longValue()+1); - } - } - logger.debug("mapCorrectOptionUids : " + mapCorrectOptionUids); - return mapCorrectOptionUids; - } - - - /** - * Map compare(Map mapGeneralCorrectOptions,Map mapGeneralCheckedOptionsContent) - * * @param mapGeneralCorrectOptions - * @param mapGeneralCheckedOptionsContent + * @param checkedOptionsUIDs * @return */ - public static Map compare(Map mapGeneralCorrectOptions,Map mapGeneralCheckedOptionsContent) - { - logger.debug("incoming mapGeneralCorrectOptions : " + mapGeneralCorrectOptions); - logger.debug("incoming mapGeneralCheckedOptionsContent : " + mapGeneralCheckedOptionsContent); + public static boolean isQuestionCorrect(Collection correctOptions, Collection checkedOptionIds) { + + if ( logger.isDebugEnabled() ) { + logger.debug("performing isQuestionCorrect correctOptions: " + correctOptions + " checkedOptionIds: " + checkedOptionIds); + } - Map mapLeanerAssessmentResults= new TreeMap(new McComparator()); - - if (mapGeneralCheckedOptionsContent == null) - return mapLeanerAssessmentResults; - - Iterator itMap = mapGeneralCorrectOptions.entrySet().iterator(); - boolean compareResult= false; - while (itMap.hasNext()) { - compareResult= false; - Map.Entry pairs = (Map.Entry)itMap.next(); - - Iterator itCheckedMap = mapGeneralCheckedOptionsContent.entrySet().iterator(); - while (itCheckedMap.hasNext()) - { - compareResult= false; - Map.Entry checkedPairs = (Map.Entry)itCheckedMap.next(); - if (pairs.getKey().toString().equals(checkedPairs.getKey().toString())) - { - Map mapCorrectOptions=(Map) pairs.getValue(); - Map mapCheckedOptions=(Map) checkedPairs.getValue(); - - boolean isEqual=compareMapItems(mapCorrectOptions, mapCheckedOptions); - boolean isEqualCross=compareMapsItemsCross(mapCorrectOptions, mapCheckedOptions); - - compareResult= isEqual && isEqualCross; - mapLeanerAssessmentResults.put(pairs.getKey(), new Boolean(compareResult).toString()); - } - } - } - logger.debug("constructed mapLeanerAssessmentResults: " + mapLeanerAssessmentResults); - return mapLeanerAssessmentResults; - } - - /** - * boolean compareMapItems(Map mapCorrectOptions, Map mapCheckedOptions) - * - * @param mapCorrectOptions - * @param mapCheckedOptions - * @return - */ - public static boolean compareMapItems(Map mapCorrectOptions, Map mapCheckedOptions) - { - logger.debug("performing compareMaps"); - logger.debug("mapCorrectOptions: " + mapCorrectOptions); - logger.debug("mapCheckedOptions: " + mapCheckedOptions); - - Iterator itMap = mapCorrectOptions.entrySet().iterator(); - boolean response=false; - while (itMap.hasNext()) - { - Map.Entry pairs = (Map.Entry)itMap.next(); - logger.debug("pairs.getValue(): " + pairs.getValue()); - boolean optionExists=optionExists(pairs.getValue().toString(), mapCheckedOptions); - logger.debug("optionExists: " + optionExists); - - if (optionExists == false) - { - return false; - } - } - return true; - } - - - /** - * compareMapsCross(Map mapCorrectOptions, Map mapCheckedOptions) - * - * @param mapCorrectOptions - * @param mapCheckedOptions - * @return boolean - */ - public static boolean compareMapsItemsCross(Map mapCorrectOptions, Map mapCheckedOptions) - { - logger.debug("performing compareMapsCross"); - logger.debug("mapCorrectOptions: " + mapCorrectOptions); - logger.debug("mapCheckedOptions: " + mapCheckedOptions); - - Iterator itMap = mapCheckedOptions.entrySet().iterator(); - boolean response=false; - while (itMap.hasNext()) - { - Map.Entry pairs = (Map.Entry)itMap.next(); - logger.debug("pairs.getValue(): " + pairs.getValue()); - boolean optionExists=optionExists(pairs.getValue().toString(), mapCorrectOptions); - logger.debug("optionExists: " + optionExists); - - if (optionExists == false) - { - return false; - } - } - return true; - } - - - /** - * optionExists(String optionValue, Map generalMap) - * - * @param optionValue - * @param generalMap - * @return boolean - */ - public static boolean optionExists(String optionValue, Map generalMap) - { - logger.debug("performing optionExists: " + optionValue); - logger.debug("generalMap: " + generalMap); - - Iterator itMap = generalMap.entrySet().iterator(); - while (itMap.hasNext()) - { - Map.Entry pairsChecked = (Map.Entry)itMap.next(); - logger.debug("pairsChecked: " + pairsChecked); - - if (pairsChecked.getValue().toString().equals(optionValue.toString())) - return true; - } + if ( correctOptions.size() == checkedOptionIds.size() ) { + for ( McOptsContent mcOptsContent : correctOptions ) { + String optionId = mcOptsContent.getUid().toString(); + if ( !checkedOptionIds.contains(optionId) ) + return false; + } + return true; + } return false; } - - + /** * McQueUsr getUser(HttpServletRequest request, IMcService mcService, String toolSessionId) * @@ -692,143 +492,7 @@ } - /** - * int getHighestMark(Map mapQuestionMarks, boolean mapExcluded) - * - * @param mapQuestionMarks - * @param mapExcluded - * @return - */ - public static int getHighestMark(Map mapQuestionMarks, boolean mapExcluded) - { - logger.debug("mapExcluded: " + mapExcluded); - - if ((mapQuestionMarks.size() == 1) && (!mapExcluded)) - { - logger.debug("using map with 1 question only"); - /*the only alternative is 100*/ - return 100; - } - - logger.debug("continue excluding map"); - Iterator itMap = mapQuestionMarks.entrySet().iterator(); - int highestMark=0; - while (itMap.hasNext()) - { - Map.Entry pair = (Map.Entry)itMap.next(); - String mark=pair.getValue().toString(); - int intMark=new Integer(mark).intValue(); - - if (intMark > highestMark) - highestMark= intMark; - } - return highestMark; - } - - - - /** - * Map rebuildMarksMapExcludeHighestMark(Map mapQuestionMarks, int highestMark) - * - * @param mapQuestionMarks - * @param highestMark - * @return - */ - public static Map rebuildMarksMapExcludeHighestMark(Map mapQuestionMarks, int highestMark) - { - logger.debug("doing rebuildMarksMapExcludeHighestMark: " + mapQuestionMarks); - logger.debug("using highestMark: " + highestMark); - - Map mapMarksExcludeHighestMark= new TreeMap(new McComparator()); - - Iterator itMap = mapQuestionMarks.entrySet().iterator(); - Long mapIndex=new Long(1); - while (itMap.hasNext()) - { - Map.Entry pair = (Map.Entry)itMap.next(); - String mark=pair.getValue().toString(); - int intMark=new Integer(mark).intValue(); - - logger.debug("intMark: " + intMark); - logger.debug("intMark versus highestMark:" + intMark + " versus" + highestMark); - if (intMark != highestMark) - { - mapMarksExcludeHighestMark.put(mapIndex.toString(),mark); - mapIndex=new Long(mapIndex.longValue()+1); - } - else - { - logger.debug("excluding highest weight from the reconstructed map: " + intMark); - } - } - logger.debug("returning mapWeightsExcludeHighestWeight: " + mapMarksExcludeHighestMark); - return mapMarksExcludeHighestMark; - } - - public static boolean isTextMarkup(String text) - { - logger.debug("starting isTextMarkup: " + text); - - int markupSignPos=text.indexOf("<"); - logger.debug("markupSignPos: " + markupSignPos); - - int markupSignPos2=text.indexOf(">"); - logger.debug("markupSignPos2: " + markupSignPos2); - - if ((markupSignPos != -1) && (markupSignPos2) != -1) - { - logger.debug("text has markup in it: " + text); - return true; - } - return false; - } - - /* - public static String getWrappedText(String text, boolean authoring) - { - - logger.debug("starting getWrappedText: " + text); - logger.debug("authoring: " + authoring); - - String newText=""; - int breakPos=50; - - if (authoring) - breakPos=30; - - if (text.length() > breakPos) - { - int counter=0; - while (counter < 100) - { - counter++; - logger.debug("using text: " + text); - - if (text.length() > breakPos) - { - newText += text.substring(0, breakPos+1) + "
" ; - text=text.substring(breakPos+1); - - } - else - { - newText +=text; - break; - } - } - - } - else - { - newText=text; - } - - logger.debug("returning newText: " + newText); - return newText; - } - */ - - /** Gets the various maps used by jsps to display a learner's attempts. + /** Gets the various maps used by jsps to display a learner's attempts. * @return Map[mapFinalAnswersIsContent, mapFinalAnswersContent, mapQueAttempts, mapQueCorrectAttempts, mapQueIncorrectAttempts, mapMarks] */ public static Map[] getAttemptMapsForUser(int intTotalQuestionCount, Long toolContentUID, boolean allowRetries, IMcService mcService, McQueUsr mcQueUsr) { Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java,v diff -u -r1.66 -r1.67 --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java 15 Aug 2007 03:54:50 -0000 1.66 +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java 21 Sep 2007 06:52:48 -0000 1.67 @@ -571,7 +571,7 @@ mcLearnerAnswersDTO.setFeedback(mcQueContent.getFeedback() != null ? mcQueContent.getFeedback() : ""); Map caMap= new TreeMap(new McStringComparator()); - Map caIdsMap= new TreeMap(new McStringComparator()); + Set caIds= new HashSet(); long mapIndex=new Long(1); Iterator listLearnerInputIterator=learnerInput.iterator(); @@ -593,7 +593,7 @@ McOptsContent mcOptsContent= mcQueContent.getOptionsContentByUID(new Long(caUid)); String mapIndexAsString = new Long(mapIndex).toString(); caMap.put(mapIndexAsString, mcOptsContent.getMcQueOptionText()); - caIdsMap.put(mapIndexAsString, caUid ); + caIds.add( caUid ); mapIndex++; if ( log.isDebugEnabled() ) { @@ -603,25 +603,10 @@ } } } - logger.debug("current caMap: " + caMap); - logger.debug("current caIdsMap: " + caIdsMap); mcLearnerAnswersDTO.setCandidateAnswers(caMap); - Long mcQueContentUid= mcQueContent.getUid(); - logger.debug("mcQueContentUid: " + mcQueContentUid); - - List correctOptions=(List) mcService.getPersistedSelectedOptions(mcQueContentUid); - logger.debug("correctOptions: " + correctOptions); - Map mapCorrectOptionUids=LearningUtil.buildMapCorrectOptionUids(correctOptions); - logger.debug("mapCorrectOptionUids: " + mapCorrectOptionUids); - - boolean isEqual=LearningUtil.compareMapItems(mapCorrectOptionUids, caIdsMap); - logger.debug("isEqual: " + isEqual); - boolean isEqualCross=LearningUtil.compareMapsItemsCross(mapCorrectOptionUids, caIdsMap); - logger.debug("isEqualCross: " + isEqualCross); - boolean compareResult= isEqual && isEqualCross; - logger.debug("compareResult: " + compareResult); - + List correctOptions = (List) mcService.getPersistedSelectedOptions(mcQueContent.getUid()); + boolean compareResult = LearningUtil.isQuestionCorrect(correctOptions, caIds); mcLearnerAnswersDTO.setAttemptCorrect(new Boolean(compareResult).toString()); if (compareResult) { @@ -634,10 +619,12 @@ mcLearnerAnswersDTO.setFeedbackIncorrect(mcQueContent.getFeedback()); mcLearnerAnswersDTO.setMark(new Integer(0)); } - logger.debug("assesment complete"); - logger.debug("mark:: " + learnerMarks); - - logger.debug("current mcLearnerAnswersDTO: " + mcLearnerAnswersDTO); + + if ( log.isDebugEnabled() ) { + logger.debug("mark:: " + learnerMarks); + logger.debug("current mcLearnerAnswersDTO: " + mcLearnerAnswersDTO); + } + questionAndCandidateAnswersList.add(mcLearnerAnswersDTO); }//end question iterator