Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java =================================================================== diff -u --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java (revision 0) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java (revision 017c572669294f98c99b694c0cffb46a7e094c24) @@ -0,0 +1,662 @@ +/* *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.tool.mc.web; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.apache.struts.Globals; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.lamsfoundation.lams.tool.mc.McAppConstants; +import org.lamsfoundation.lams.tool.mc.McApplicationException; +import org.lamsfoundation.lams.tool.mc.McComparator; +import org.lamsfoundation.lams.tool.mc.McUtils; +import org.lamsfoundation.lams.tool.mc.pojos.McContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueContent; +import org.lamsfoundation.lams.tool.mc.pojos.McQueUsr; +import org.lamsfoundation.lams.tool.mc.pojos.McUsrAttempt; +import org.lamsfoundation.lams.tool.mc.service.IMcService; +import org.lamsfoundation.lams.web.action.LamsDispatchAction; + +/** + * * @author Ozgur Demirtas + * + *

Action class that controls the logic of tool behavior.

+ * + *

Note that Struts action class only has the responsibility to navigate + * page flow. All database operation should go to service layer and data + * transformation from domain model to struts form bean should go to form + * bean class. This ensure clean and maintainable code. + *

+ * + * SystemException is thrown whenever an known error condition is + * identified. No system exception error handling code should appear in the + * Struts action class as all of them are handled in + * CustomStrutsExceptionHandler. + * + * + + + + + + + + + + + + + + + + + + + * +*/ +public class McLearningAction extends LamsDispatchAction implements McAppConstants +{ + static Logger logger = Logger.getLogger(McLearningAction.class.getName()); + + /** + *

Default struts dispatch method.

+ * + *

It is assuming that progress engine should pass in the tool access + * mode and the tool session id as http parameters.

+ * + * @param mapping An ActionMapping class that will be used by the Action class to tell + * the ActionServlet where to send the end-user. + * + * @param form The ActionForm class that will contain any data submitted + * by the end-user via a form. + * @param request A standard Servlet HttpServletRequest class. + * @param response A standard Servlet HttpServletResponse class. + * @return An ActionForward class that will be returned to the ActionServlet indicating where + * the user is to go next. + * @throws IOException + * @throws ServletException + * @throws McApplicationException the known runtime exception + * + * unspecified(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + + * main content/question content management and workflow logic + * + * if the passed toolContentId exists in the db, we need to get the relevant data into the Map + * if not, create the default Map + */ + public ActionForward unspecified(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + McAuthoringForm mcAuthoringForm = (McAuthoringForm) form; + IMcService mcService =McUtils.getToolService(request); + AuthoringUtil.readData(request, mcAuthoringForm); + mcAuthoringForm.resetUserAction(); + return null; + } + + + /** + * responds to learner activity in learner mode. + * + * ActionForward displayMc(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + * + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + + + * + * ActionForward displayMc(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + * + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws IOException + * @throws ServletException + */ + public ActionForward displayMc(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + logger.debug("displayMc starting.."); + + McLearningForm mcLearningForm = (McLearningForm) form; + IMcService mcService =McUtils.getToolService(request); + + mcLearningForm.resetParameters(); + LearningUtil.readParameters(request, mcLearningForm); + + if (mcLearningForm.getContinueOptionsCombined() != null) + { + setContentInUse(request); + return continueOptionsCombined(mapping, form, request, response); + } + else if (mcLearningForm.getNextOptions() != null) + { + setContentInUse(request); + return getNextOptions(mapping, form, request, response); + } + else if (mcLearningForm.getOptionCheckBoxSelected() != null) + { + setContentInUse(request); + logger.debug("requested selectOptionsCheckBox..."); + mcLearningForm.resetCommands(); + LearningUtil.selectOptionsCheckBox(request,mcLearningForm, mcLearningForm.getQuestionIndex()); + } + else if (mcLearningForm.getRedoQuestions() != null) + { + setContentInUse(request); + return redoQuestions(mapping, form, request, response); + } + else if (mcLearningForm.getRedoQuestionsOk() != null) + { + setContentInUse(request); + logger.debug("requested redoQuestionsOk, user is sure to redo the questions."); + mcLearningForm.resetCommands(); + return redoQuestions(request, mcLearningForm, mapping); + } + else if (mcLearningForm.getViewAnswers() != null) + { + setContentInUse(request); + return viewAnswers(mapping, form, request, response); + } + else if (mcLearningForm.getViewSummary() != null) + { + setContentInUse(request); + return viewSummary(mapping, form, request, response); + } + else if (mcLearningForm.getLearnerFinished() != null) + { + logger.debug("requested learner finished, the learner should be directed to next activity."); + mcLearningForm.resetCommands(); + //fix this + return (mapping.findForward(VIEW_SUMMARY)); + } + + mcLearningForm.resetCommands(); + return (mapping.findForward(LOAD_LEARNER)); + } + + + /** + * responses to learner when they answer all the questions on a single page + * continueOptionsCombined(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward continueOptionsCombined(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + logger.debug("dispatching continueOptionsCombined..."); + McLearningForm mcLearningForm = (McLearningForm) form; + IMcService mcService =McUtils.getToolService(request); + + /* process the answers */ + Map mapGeneralCheckedOptionsContent=(Map) request.getSession().getAttribute(MAP_GENERAL_CHECKED_OPTIONS_CONTENT); + logger.debug("final mapGeneralCheckedOptionsContent: " + mapGeneralCheckedOptionsContent); + + Long toolContentId=(Long) request.getSession().getAttribute(TOOL_CONTENT_ID); + logger.debug("toolContentId: " + toolContentId); + + logger.debug("will assess"); + Integer passMark=(Integer) request.getSession().getAttribute(PASSMARK); + logger.debug("passMark: " + passMark); + + Map mapLeanerAssessmentResults=LearningUtil.assess(request, mapGeneralCheckedOptionsContent, toolContentId); + logger.debug("mapLeanerAssessmentResults: " + mapLeanerAssessmentResults); + logger.debug("assesment complete"); + + int mark=LearningUtil.getMark(mapLeanerAssessmentResults); + logger.debug("mark: " + mark); + request.getSession().setAttribute(LEARNER_MARK, new Integer(mark).toString()); + request.getSession().setAttribute(LEARNER_MARK_ATLEAST, new Integer(mark+1).toString()); + + Map mapQuestionWeights =(Map) request.getSession().getAttribute(MAP_QUESTION_WEIGHTS); + logger.debug("mapQuestionWeights: " + mapQuestionWeights); + + boolean passed=false; + if ((passMark != null) && (passMark.intValue() != 0)) + { + int totalUserWeight=LearningUtil.calculateWeights(mapLeanerAssessmentResults, mapQuestionWeights); + logger.debug("totalUserWeight: " + totalUserWeight); + + if (totalUserWeight < passMark.intValue()) + { + logger.debug("USER FAILED"); + request.getSession().setAttribute(USER_PASSED, new Boolean(false).toString()); + logger.debug("totalUserWeight is less than passmark: " + totalUserWeight + " < " + passMark.intValue()); + passed=false; + } + else + { + logger.debug("USER PASSED"); + request.getSession().setAttribute(USER_PASSED, new Boolean(true).toString()); + passed=true; + } + } + + boolean isUserDefined=LearningUtil.doesUserExists(request); + logger.debug("isUserDefined"); + if (isUserDefined == false) + { + LearningUtil.createUser(request); + logger.debug("created user in the db"); + } + McQueUsr mcQueUsr=LearningUtil.getUser(request); + logger.debug("mcQueUsr: " + mcQueUsr); + + + String highestAttemptOrder=(String)request.getSession().getAttribute(LEARNER_LAST_ATTEMPT_ORDER); + logger.debug("current highestAttemptOrder:" + highestAttemptOrder); + + logger.debug("passed: " + passed); + LearningUtil.createAttempt(request, mcQueUsr, mapGeneralCheckedOptionsContent, mark, passed, new Integer(highestAttemptOrder).intValue(), mapLeanerAssessmentResults); + logger.debug("created user attempt in the db"); + + int intHighestAttemptOrder=new Integer(highestAttemptOrder).intValue()+ 1 ; + logger.debug("updated highestAttemptOrder:" + intHighestAttemptOrder); + request.getSession().setAttribute(LEARNER_LAST_ATTEMPT_ORDER, new Integer(intHighestAttemptOrder).toString()); + + mcLearningForm.resetCommands(); + return (mapping.findForward(INDIVIDUAL_REPORT)); + } + + + /** + * takes the learner to the next set of questions + * continueOptionsCombined(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward getNextOptions(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + logger.debug("dispatching getNextOptions..."); + McLearningForm mcLearningForm = (McLearningForm) form; + IMcService mcService =McUtils.getToolService(request); + + String currentQuestionIndex=(String)request.getSession().getAttribute(CURRENT_QUESTION_INDEX); + logger.debug("currentQuestionIndex:" + currentQuestionIndex); + + String totalQuestionCount=(String)request.getSession().getAttribute(TOTAL_QUESTION_COUNT); + logger.debug("totalQuestionCount:" + totalQuestionCount); + + int intTotalQuestionCount=new Integer(totalQuestionCount).intValue(); + int intCurrentQuestionIndex=new Integer(currentQuestionIndex).intValue(); + + if (intTotalQuestionCount-1 == intCurrentQuestionIndex) + { + logger.debug("totalQuestionCount has been reached :" + totalQuestionCount); + request.getSession().setAttribute(TOTAL_COUNT_REACHED, new Boolean(true).toString()); + } + + mcLearningForm.resetCommands(); + + int newQuestionIndex=new Integer(currentQuestionIndex).intValue() + 1; + request.getSession().setAttribute(CURRENT_QUESTION_INDEX, new Integer(newQuestionIndex).toString()); + logger.debug("updated questionIndex:" + request.getSession().getAttribute(CURRENT_QUESTION_INDEX)); + return (mapping.findForward(LOAD_LEARNER)); + } + + + /** + * allows the learner to take the activity again + * redoQuestions(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward redoQuestions(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + logger.debug("dispatching redoQuestions..."); + McLearningForm mcLearningForm = (McLearningForm) form; + IMcService mcService =McUtils.getToolService(request); + + request.getSession().setAttribute(CURRENT_QUESTION_INDEX, "1"); + request.getSession().setAttribute(TOTAL_COUNT_REACHED, new Boolean(false).toString()); + + McQueUsr mcQueUsr=LearningUtil.getUser(request); + Long queUsrId=mcQueUsr.getUid(); + logger.debug("queUsrId: " + queUsrId); + + int learnerBestMark=LearningUtil.getHighestMark(request, queUsrId); + logger.debug("learnerBestMark: " + learnerBestMark); + request.getSession().setAttribute(LEARNER_BEST_MARK,new Integer(learnerBestMark).toString()); + + mcLearningForm.resetCommands(); + return (mapping.findForward(REDO_QUESTIONS)); + } + + + /** + * allows the learner to view their answer history + * viewAnswers(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward viewAnswers(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + logger.debug("dispatching viewAnswers..."); + McLearningForm mcLearningForm = (McLearningForm) form; + IMcService mcService =McUtils.getToolService(request); + String totalQuestionCount= (String) request.getSession().getAttribute(TOTAL_QUESTION_COUNT); + logger.debug("totalQuestionCount: " + totalQuestionCount); + + Long toolContentUID= (Long) request.getSession().getAttribute(TOOL_CONTENT_UID); + logger.debug("toolContentUID: " + toolContentUID); + + McQueUsr mcQueUsr=LearningUtil.getUser(request); + Long queUsrId=mcQueUsr.getUid(); + logger.debug("queUsrId: " + queUsrId); + + Map mapQueAttempts= new TreeMap(new McComparator()); + Map mapQueCorrectAttempts= new TreeMap(new McComparator()); + Map mapQueIncorrectAttempts= new TreeMap(new McComparator()); + for (int i=1; i<= new Integer(totalQuestionCount).intValue(); i++) + { + logger.debug("doing question with display order: " + i); + McQueContent mcQueContent=mcService.getQuestionContentByDisplayOrder(new Long(i), toolContentUID); + logger.debug("mcQueContent uid: " + mcQueContent.getUid()); + + Map mapAttemptOrderAttempts= new TreeMap(new McComparator()); + Map mapAttemptOrderCorrectAttempts= new TreeMap(new McComparator()); + Map mapAttemptOrderIncorrectAttempts= new TreeMap(new McComparator()); + for (int j=1; j <= MAX_ATTEMPTY_HISTORY ; j++ ) + { + List attemptsByAttemptOrder=mcService.getAttemptByAttemptOrder(queUsrId, mcQueContent.getUid(), new Integer(j)); + logger.debug("attemptsByAttemptOrder: " + j + " is: " + attemptsByAttemptOrder); + + Map mapAttempts= new TreeMap(new McComparator()); + Map mapAttemptsIncorrect= new TreeMap(new McComparator()); + Map mapAttemptsCorrect= new TreeMap(new McComparator()); + Iterator attemptIterator=attemptsByAttemptOrder.iterator(); + Long mapIndex=new Long(1); + while (attemptIterator.hasNext()) + { + McUsrAttempt mcUsrAttempt=(McUsrAttempt)attemptIterator.next(); + + if (mcUsrAttempt.isAttemptCorrect()) + { + mapAttemptsCorrect.put(mapIndex.toString(), mcUsrAttempt.getMcOptionsContent().getMcQueOptionText()); + } + else + { + mapAttemptsIncorrect.put(mapIndex.toString(), mcUsrAttempt.getMcOptionsContent().getMcQueOptionText()); + } + mapAttempts.put(mapIndex.toString(), mcUsrAttempt.getMcOptionsContent().getMcQueOptionText()); + + logger.debug("added attempt with order: " + mcUsrAttempt.getAttemptOrder() + " , option text is: " + mcUsrAttempt.getMcOptionsContent().getMcQueOptionText()); + mapIndex=new Long(mapIndex.longValue()+1); + } + + logger.debug("final mapAttempts is: " + mapAttempts); + if (mapAttempts.size() > 0) + { + mapAttemptOrderAttempts.put(new Integer(j).toString(), mapAttempts); + } + if (mapAttemptsCorrect.size() > 0) + { + mapAttemptOrderCorrectAttempts.put(new Integer(j).toString(), mapAttemptsCorrect); + } + if (mapAttemptsIncorrect.size() > 0) + { + mapAttemptOrderIncorrectAttempts.put(new Integer(j).toString(), mapAttemptsIncorrect); + } + } + + logger.debug("final mapAttemptOrderAttempts is: " + mapAttemptOrderAttempts); + if (mapAttemptOrderAttempts.size() > 0) + { + mapQueAttempts.put(new Integer(i).toString(), mapAttemptOrderAttempts); + } + if (mapAttemptOrderCorrectAttempts.size() > 0) + { + mapQueCorrectAttempts.put(new Integer(i).toString(), mapAttemptOrderCorrectAttempts); + } + if (mapAttemptOrderIncorrectAttempts.size() > 0) + { + mapQueIncorrectAttempts.put(new Integer(i).toString(), mapAttemptOrderIncorrectAttempts); + } + } + request.getSession().setAttribute(MAP_QUE_ATTEMPTS, mapQueAttempts); + request.getSession().setAttribute(MAP_QUE_CORRECT_ATTEMPTS, mapQueCorrectAttempts); + request.getSession().setAttribute(MAP_QUE_INCORRECT_ATTEMPTS, mapQueIncorrectAttempts); + + logger.debug("final mapQueAttempts is: " + mapQueAttempts); + logger.debug("final mapQueCorrectAttempts is: " + mapQueCorrectAttempts); + logger.debug("final mapQueIncorrectAttempts is: " + mapQueIncorrectAttempts); + mcLearningForm.resetCommands(); + return (mapping.findForward(VIEW_ANSWERS)); + } + + + /** + * allows the learner to view all the other learners' activity summary + * viewSummary(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + * + * @param request + * @param form + * @param mapping + * @return ActionForward + */ + public ActionForward viewSummary(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) throws IOException, + ServletException + { + logger.debug("dispatching viewSummary..."); + McLearningForm mcLearningForm = (McLearningForm) form; + IMcService mcService =McUtils.getToolService(request); + + int countSessionComplete=mcService.countSessionComplete(); + int topMark=LearningUtil.getTopMark(request); + int lowestMark=LearningUtil.getLowestMark(request); + int averageMark=LearningUtil.getAverageMark(request); + + logger.debug("countSessionComplete: " + countSessionComplete); + logger.debug("topMark: " + topMark); + logger.debug("lowestMark: " + lowestMark); + logger.debug("averageMark: " + averageMark); + + request.getSession().setAttribute(COUNT_SESSION_COMPLETE, new Integer(countSessionComplete).toString()); + request.getSession().setAttribute(TOP_MARK, new Integer(topMark).toString()); + request.getSession().setAttribute(LOWEST_MARK, new Integer(lowestMark).toString()); + request.getSession().setAttribute(AVERAGE_MARK, new Integer(averageMark).toString()); + + mcLearningForm.resetCommands(); + return (mapping.findForward(RESULTS_SUMMARY)); + } + + + /** + * to indicate that some learners are using the content + * marks the content as used content + * setContentInUse(HttpServletRequest request) + * + * @param request + */ + protected void setContentInUse(HttpServletRequest request) + { + IMcService mcService =McUtils.getToolService(request); + Long toolContentId=(Long)request.getSession().getAttribute(TOOL_CONTENT_ID); + logger.debug("toolContentId:" + toolContentId); + + McContent mcContent=mcService.retrieveMc(toolContentId); + logger.debug("mcContent:" + mcContent); + mcContent.setContentInUse(true); + logger.debug("content has been set to inuse"); + mcService.saveMcContent(mcContent); + } + + + /** + * redoQuestions(HttpServletRequest request, McLearningForm mcLearningForm, ActionMapping mapping) + * + * @param request + * @param mcLearningForm + * @param mapping + * @return + */ + protected ActionForward redoQuestions(HttpServletRequest request, McLearningForm mcLearningForm, ActionMapping mapping) + { + logger.debug("requested redoQuestions..."); + /* reset the checked options MAP */ + Map mapGeneralCheckedOptionsContent= new TreeMap(new McComparator()); + request.getSession().setAttribute(MAP_GENERAL_CHECKED_OPTIONS_CONTENT, mapGeneralCheckedOptionsContent); + mcLearningForm.resetCommands(); + return (mapping.findForward(LOAD_LEARNER)); + } + + /** + * persists error messages to request scope + * @param request + * @param message + */ + public void persistError(HttpServletRequest request, String message) + { + ActionMessages errors= new ActionMessages(); + errors.add(Globals.ERROR_KEY, new ActionMessage(message)); + logger.debug("add " + message +" to ActionMessages:"); + saveErrors(request,errors); + } + +} + \ No newline at end of file