/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/evaluation/TotalScoreUpdateListener.java $ * $Id: TotalScoreUpdateListener.java 121258 2013-03-15 15:03:36Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.tool.assessment.ui.listener.evaluation; import java.lang.reflect.InvocationTargetException; 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 javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.math.util.MathUtils; import org.sakaiproject.event.cover.EventTrackingService; import org.sakaiproject.tool.assessment.data.dao.grading.AssessmentGradingData; import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc; import org.sakaiproject.tool.assessment.facade.AgentFacade; import org.sakaiproject.tool.assessment.services.GradebookServiceException; import org.sakaiproject.tool.assessment.services.GradingService; import org.sakaiproject.tool.assessment.ui.bean.evaluation.AgentResults; import org.sakaiproject.tool.assessment.ui.bean.evaluation.TotalScoresBean; import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; import org.sakaiproject.tool.assessment.util.TextFormat; /** * <p> * This handles the updating of the Total Score page. * </p> * <p>Description: Action Listener Evaluation Updating Total Score front door</p> * <p>Copyright: Copyright (c) 2004</p> * <p>Organization: Sakai Project</p> * @author Ed Smiley * @version $Id: TotalScoreUpdateListener.java 121258 2013-03-15 15:03:36Z ottenhoff@longsight.com $ */ public class TotalScoreUpdateListener implements ActionListener { private static Log log = LogFactory.getLog(TotalScoreUpdateListener.class); /** * Standard process action method. * @param ae ActionEvent * @throws AbortProcessingException */ public void processAction(ActionEvent ae) throws AbortProcessingException { log.debug("Total Score Update LISTENER."); TotalScoresBean bean = (TotalScoresBean) ContextUtil.lookupBean("totalScores"); log.debug("Calling saveTotalScores."); if (!saveTotalScores(bean)) { throw new RuntimeException("failed to call saveTotalScores."); } } private HashMap prepareAssessmentGradingHash(ArrayList assessmentGradingList){ HashMap map = new HashMap(); for (int i=0; i<assessmentGradingList.size(); i++){ AssessmentGradingData a = (AssessmentGradingData)assessmentGradingList.get(i); map.put(a.getAssessmentGradingId(), a); } return map; } /** * Persist the results from the ActionForm in the total page. * @todo Some of this code will change when we move this to Hibernate persistence. * @param bean TotalScoresBean bean * @return true if successful */ public boolean saveTotalScores(TotalScoresBean bean) { ArrayList assessmentGradingList = bean.getAssessmentGradingList(); HashMap map = prepareAssessmentGradingHash(assessmentGradingList); Collection agents = bean.getAgents(); Iterator iter = agents.iterator(); ArrayList grading = new ArrayList(); boolean hasNumberFormatException = false; StringBuffer idList = new StringBuffer(" "); String err = ""; boolean isAnonymousGrading = false; String applyToUngraded = bean.getApplyToUngraded().trim(); if(applyToUngraded != null && !"".equals(applyToUngraded)){ try{ Double.valueOf(applyToUngraded).doubleValue(); ArrayList allAgents = bean.getAllAgentsDirect(); iter = allAgents.iterator(); while(iter.hasNext()){ AgentResults agentResults = (AgentResults) iter.next(); if (agentResults.getAssessmentGradingId().equals(Long.valueOf(-1)) || agentResults.getSubmittedDate() == null) { agentResults.setTotalOverrideScore(applyToUngraded+""); } } iter = allAgents.iterator(); bean.setApplyToUngraded(""); }catch (Exception e) { FacesContext context = FacesContext.getCurrentInstance(); String err2 = (String) ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.EvaluationMessages", "number_format_error_user_id_apply"); context.addMessage(null, new FacesMessage(err2)); return true; } bean.setApplyToUngraded(""); } if (bean.getPublishedAssessment() != null && bean.getPublishedAssessment().getEvaluationModel() != null && bean.getPublishedAssessment().getEvaluationModel().getAnonymousGrading() != null && bean.getPublishedAssessment().getEvaluationModel().getAnonymousGrading().equals(EvaluationModelIfc.ANONYMOUS_GRADING)) { isAnonymousGrading = true; err = (String) ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.EvaluationMessages", "number_format_error_submission_id"); } else { err = (String) ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.EvaluationMessages", "number_format_error_user_id"); } ArrayList badAdjList = new ArrayList(); while (iter.hasNext()) { AgentResults agentResults = (AgentResults) iter.next(); StringBuilder newScoreString = new StringBuilder(); boolean update = false; try { update = needUpdate(agentResults, map, newScoreString); } catch (NumberFormatException e) { hasNumberFormatException = true; update = false; if (isAnonymousGrading) { badAdjList.add(agentResults.getAssessmentGradingId()); } else { badAdjList.add(agentResults.getAgentEid()); } } if (update){ log.debug("update is true"); Double newScore = new Double(0d); AssessmentGradingData data = new AssessmentGradingData(); try { if (!agentResults.getAssessmentGradingId().equals(Long.valueOf(-1)) ) { // these are students who have submitted for grades. // Add up new score newScore = Double.valueOf(newScoreString.toString()); agentResults.setFinalScore(newScore+""); BeanUtils.copyProperties(data, agentResults); data.setPublishedAssessmentId(bean.getPublishedAssessment().getPublishedAssessmentId()); if ("-".equals(agentResults.getTotalAutoScore())) { data.setTotalAutoScore(Double.valueOf(0d)); } else { data.setTotalAutoScore(Double.valueOf(agentResults.getTotalAutoScore())); } data.setTotalOverrideScore(Double.valueOf(agentResults.getTotalOverrideScore())); data.setFinalScore(Double.valueOf(agentResults.getFinalScore())); data.setIsLate(agentResults.getIsLate()); data.setComments(agentResults.getComments()); data.setGradedBy(AgentFacade.getAgentString()); data.setGradedDate(new Date()); grading.add(data); } else { // these are students who have not submitted for grades and instructor made adjustment to their scores // Add up new score newScore = Double.valueOf(newScoreString.toString()); agentResults.setFinalScore(newScore+""); BeanUtils.copyProperties(data, agentResults); data.setAgentId(agentResults.getIdString()); data.setForGrade(Boolean.FALSE); //data.setStatus(Integer.valueOf(1)); data.setIsLate(Boolean.FALSE); data.setItemGradingSet(new HashSet()); data.setPublishedAssessmentId(bean.getPublishedAssessment().getPublishedAssessmentId()); // tell hibernate this is a new record data.setAssessmentGradingId(Long.valueOf(0)); data.setSubmittedDate(null); data.setTotalAutoScore(Double.valueOf(0d)); data.setTotalOverrideScore(Double.valueOf(agentResults.getTotalOverrideScore())); data.setFinalScore(Double.valueOf(agentResults.getFinalScore())); data.setComments(agentResults.getComments()); data.setGradedBy(AgentFacade.getAgentString()); data.setGradedDate(new Date()); // note that I am not sure if we should set this people as late or what? grading.add(data); } } catch (IllegalAccessException e) { log.error("IllegalAccessException: " + e); return false; } catch (InvocationTargetException e) { log.error("InvocationTargetException: " + e); return false; } } } if (hasNumberFormatException) { if (bean.getPublishedAssessment() != null && bean.getPublishedAssessment().getEvaluationModel() != null && bean.getPublishedAssessment().getEvaluationModel().getAnonymousGrading() != null && bean.getPublishedAssessment().getEvaluationModel().getAnonymousGrading().equals(EvaluationModelIfc.ANONYMOUS_GRADING)) { err = (String) ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.EvaluationMessages", "number_format_error_submission_id"); } else { err = (String) ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.EvaluationMessages", "number_format_error_user_id"); } for (int i = 0; i < badAdjList.size(); i++) { idList.append(badAdjList.get(i)); if (i != badAdjList.size() - 1) { idList.append(", "); } } idList.append("."); FacesContext context = FacesContext.getCurrentInstance(); context.addMessage(null, new FacesMessage(err + idList.toString())); } GradingService delegate = new GradingService(); try { delegate.saveTotalScores(grading, bean.getPublishedAssessment()); StringBuffer logString = new StringBuffer(); logString.append("gradedBy="); logString.append(AgentFacade.getAgentString()); logString.append(", publishedAssessmentId="); logString.append(bean.getPublishedAssessment().getPublishedAssessmentId()); EventTrackingService.post(EventTrackingService.newEvent("sam.total.score.update", "siteId=" + AgentFacade.getCurrentSiteId() + ", " + logString.toString(), true)); log.debug("Saved total scores."); } catch (GradebookServiceException ge) { FacesContext context = FacesContext.getCurrentInstance(); String error=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AuthorMessages", "gradebook_exception_error"); context.addMessage(null, new FacesMessage(error)); // scores are saved in Samigo, still return true, but display error to user. return true; } return true; } private boolean needUpdate(AgentResults agentResults, HashMap map, StringBuilder newScoreString) throws NumberFormatException{ boolean update = true; String newComments = TextFormat.convertPlaintextToFormattedTextNoHighUnicode(log, agentResults.getComments()); agentResults.setComments(newComments); log.debug("newComments = " + newComments); double totalAutoScore = 0; if (agentResults.getTotalAutoScore()!=null && !("").equals(agentResults.getTotalAutoScore())){ try{ totalAutoScore = Double.valueOf(agentResults.getTotalAutoScore()).doubleValue(); } catch (NumberFormatException e){ totalAutoScore = 0; } } double totalOverrideScore = 0; Boolean newIsLate = agentResults.getIsLate(); // if the duedate were postpond, we need to adjust this // we will check if there is change of grade. if so, add up new score // else skip AssessmentGradingData old = (AssessmentGradingData)map.get(agentResults.getAssessmentGradingId()); if (old != null){ if (agentResults.getTotalOverrideScore()!=null && !("").equals(agentResults.getTotalOverrideScore())){ try{ totalOverrideScore = Double.valueOf(agentResults.getTotalOverrideScore()).doubleValue(); } catch (NumberFormatException e){ log.warn("Adj has wrong input type" + e); throw e; } } double newScore = totalAutoScore + totalOverrideScore; newScoreString.append(Double.valueOf(newScore)); double oldScore = 0; if (old.getFinalScore()!=null){ oldScore = old.getFinalScore().doubleValue(); } Boolean oldIsLate=old.getIsLate(); String oldComments = old.getComments(); log.debug("***oldScore = " + oldScore); log.debug("***newScore = " + newScore); log.debug("***oldIsLate = " + oldIsLate); log.debug("***newIsLate = " + newIsLate); log.debug("***oldComments = " + oldComments); log.debug("***newComments = " + newComments); if (MathUtils.equalsIncludingNaN(oldScore, newScore, 0.0001) && newIsLate.equals(oldIsLate) && ((newComments!=null && newComments.equals(oldComments)) || (newComments==null && oldComments==null) // following condition will happen when there is no comments (null) and user clicks on SubmissionId. // getComments() in AgentResults calls Validator.check(comments, "") so the null comment gets set to "" // there is nothing updated. update flag should be false || ((newComments!=null && newComments.equals("")) && oldComments==null)) ) { update = false; } } else{ // no assessmentGradingData exists boolean noOverrideScore = false; boolean noComment = false; String score = agentResults.getTotalOverrideScore(); if (score != null) { if (!("").equals(score.trim()) && !("-").equals(score.trim())) { try{ totalOverrideScore = Double.valueOf(agentResults.getTotalOverrideScore()).doubleValue(); noOverrideScore = false; } catch (NumberFormatException e){ log.warn("Adj has wrong input type" + e); throw e; } } else { noOverrideScore = true; totalAutoScore = 0; } } else { noOverrideScore = true; totalAutoScore = 0; } double newScore = totalAutoScore + totalOverrideScore; newScoreString.append(Double.valueOf(newScore)); if ("".equals(agentResults.getComments().trim())) noComment = true; if (noOverrideScore && noComment) update = false; } return update; } }