Java tutorial
/********************************************************************************** * * $Id$ * *********************************************************************************** * * Copyright (c) 2005, 2006, 2007, 2008, 2009 The Sakai Foundation, The MIT Corporation * * 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.gradebook.business.impl; import java.math.BigDecimal; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.hibernate.TransientObjectException; import org.sakaiproject.component.gradebook.GradebookServiceHibernateImpl; import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException; import org.sakaiproject.service.gradebook.shared.ConflictingSpreadsheetNameException; import org.sakaiproject.service.gradebook.shared.GradebookService; import org.sakaiproject.service.gradebook.shared.MultipleAssignmentSavingException; import org.sakaiproject.service.gradebook.shared.StaleObjectModificationException; import org.sakaiproject.tool.gradebook.AbstractGradeRecord; import org.sakaiproject.tool.gradebook.Assignment; import org.sakaiproject.tool.gradebook.AssignmentGradeRecord; import org.sakaiproject.tool.gradebook.Category; import org.sakaiproject.tool.gradebook.Comment; import org.sakaiproject.tool.gradebook.CourseGrade; import org.sakaiproject.tool.gradebook.CourseGradeRecord; import org.sakaiproject.tool.gradebook.GradableObject; import org.sakaiproject.tool.gradebook.Gradebook; import org.sakaiproject.tool.gradebook.GradingEvent; import org.sakaiproject.tool.gradebook.GradingEvents; import org.sakaiproject.tool.gradebook.LetterGradePercentMapping; import org.sakaiproject.tool.gradebook.Spreadsheet; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException; /** synchronize from external application*/ import org.sakaiproject.tool.gradebook.business.GbSynchronizer; import org.sakaiproject.tool.gradebook.business.GradebookManager; import org.sakaiproject.thread_local.cover.ThreadLocalManager; /** * Manages Gradebook persistence via hibernate. * * Note that many of these methods are duplicates of those in the gradebook service API code. */ public abstract class GradebookManagerHibernateImpl extends GradebookServiceHibernateImpl implements GradebookManager { private static final Log log = LogFactory.getLog(GradebookManagerHibernateImpl.class); // Special logger for data contention analysis. private static final Log logData = LogFactory .getLog(GradebookManagerHibernateImpl.class.getName() + ".GB_DATA"); /** synchronize from external application*/ GbSynchronizer synchronizer = null; @Override public void removeAssignment(final Long assignmentId) throws StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Assignment asn = (Assignment) session.load(Assignment.class, assignmentId); Gradebook gradebook = asn.getGradebook(); asn.setRemoved(true); session.update(asn); /** synchronize from external application*/ if ((synchronizer != null) && (!synchronizer.isProjectSite())) { synchronizer.deleteLegacyAssignment(asn.getName()); } if (log.isInfoEnabled()) log.info("Assignment " + asn.getName() + " has been removed from " + gradebook); return null; } }; getHibernateTemplate().execute(hc); } @Override public List getAssignmentGradeRecords(final Assignment assignment, final Collection studentUids) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { if (studentUids == null || studentUids.size() == 0) { if (log.isInfoEnabled()) log.info("Returning no grade records for an empty collection of student UIDs"); return new ArrayList(); } else if (assignment.isRemoved()) { return new ArrayList(); } Query q = session.createQuery( "from AssignmentGradeRecord as agr where agr.gradableObject.id=:gradableObjectId order by agr.pointsEarned"); q.setLong("gradableObjectId", assignment.getId().longValue()); List records = filterGradeRecordsByStudents(q.list(), studentUids); return records; } }; return (List) getHibernateTemplate().execute(hc); } @Override public CourseGradeRecord getPointsEarnedCourseGradeRecords(final CourseGrade courseGrade, final String studentUid) { Set<String> oneStudent = new HashSet<String>(1); oneStudent.add(studentUid); List<CourseGradeRecord> list = getPointsEarnedCourseGradeRecords(courseGrade, oneStudent); for (CourseGradeRecord cgr : list) { return cgr; } return null; } @Override public List getPointsEarnedCourseGradeRecordsWithStats(final CourseGrade courseGrade, final Collection studentUids) { // Get good class-wide statistics by including all students, whether // the caller is specifically interested in their grade records or not. Long gradebookId = courseGrade.getGradebook().getId(); Set allStudentUids = getAllStudentUids(getGradebookUid(gradebookId)); List courseGradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, allStudentUids); courseGrade.calculateStatistics(courseGradeRecords, allStudentUids.size()); // Filter out the grade records which weren't specified. courseGradeRecords = filterGradeRecordsByStudents(courseGradeRecords, studentUids); return courseGradeRecords; } @Override public void addToGradeRecordMap(Map gradeRecordMap, List gradeRecords) { for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { AbstractGradeRecord gradeRecord = (AbstractGradeRecord) iter.next(); if (gradeRecord instanceof AssignmentGradeRecord) { ((AssignmentGradeRecord) gradeRecord).setUserAbleToView(true); } String studentUid = gradeRecord.getStudentId(); Map studentMap = (Map) gradeRecordMap.get(studentUid); if (studentMap == null) { studentMap = new HashMap(); gradeRecordMap.put(studentUid, studentMap); } studentMap.put(gradeRecord.getGradableObject().getId(), gradeRecord); } } @Override public void addToGradeRecordMap(Map gradeRecordMap, List gradeRecords, Map studentIdItemIdFunctionMap) { for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { AbstractGradeRecord gradeRecord = (AbstractGradeRecord) iter.next(); String studentUid = gradeRecord.getStudentId(); Map studentMap = (Map) gradeRecordMap.get(studentUid); if (studentMap == null) { studentMap = new HashMap(); gradeRecordMap.put(studentUid, studentMap); } Long itemId = gradeRecord.getGradableObject().getId(); // check to see if this item is included in the items that the current user is able to view/grade Map itemIdFunctionMap = (Map) studentIdItemIdFunctionMap.get(studentUid); if (gradeRecord instanceof AssignmentGradeRecord) { if (itemIdFunctionMap != null && itemIdFunctionMap.get(itemId) != null) { ((AssignmentGradeRecord) gradeRecord).setUserAbleToView(true); } else { ((AssignmentGradeRecord) gradeRecord).setUserAbleToView(false); ((AssignmentGradeRecord) gradeRecord).setLetterEarned(null); ((AssignmentGradeRecord) gradeRecord).setPointsEarned(null); ((AssignmentGradeRecord) gradeRecord).setPercentEarned(null); } studentMap.put(itemId, gradeRecord); } else { studentMap.put(itemId, gradeRecord); } } } @Override public void addToCategoryResultMap(Map categoryResultMap, List categories, Map gradeRecordMap, Map enrollmentMap) { if (gradeRecordMap == null || gradeRecordMap.isEmpty()) return; for (Iterator stuIter = enrollmentMap.keySet().iterator(); stuIter.hasNext();) { String studentUid = (String) stuIter.next(); Map studentMap = (Map) gradeRecordMap.get(studentUid); if (studentMap != null) { for (Iterator iter = categories.iterator(); iter.hasNext();) { Object obj = iter.next(); if (!(obj instanceof Category)) { continue; } Category category = (Category) obj; List categoryAssignments = category.getAssignmentList(); if (categoryAssignments == null) { continue; } List gradeRecords = new ArrayList(); for (Iterator assignmentsIter = categoryAssignments.iterator(); assignmentsIter.hasNext();) { Assignment assignment = (Assignment) assignmentsIter.next(); AbstractGradeRecord gradeRecord = (AbstractGradeRecord) studentMap.get(assignment.getId()); gradeRecords.add(gradeRecord); } applyDropScores(gradeRecords); category.calculateStatisticsPerStudent(gradeRecords, studentUid); Map studentCategoryMap = (Map) categoryResultMap.get(studentUid); if (studentCategoryMap == null) { studentCategoryMap = new HashMap(); categoryResultMap.put(studentUid, studentCategoryMap); } Map stats = new HashMap(); stats.put("studentAverageScore", category.getAverageScore()); stats.put("studentAverageTotalPoints", category.getAverageTotalPoints()); stats.put("studentMean", category.getMean()); stats.put("studentTotalPointsEarned", category.getTotalPointsEarned()); stats.put("studentTotalPointsPossible", category.getTotalPointsPossible()); stats.put("category", category); studentCategoryMap.put(category.getId(), stats); } } } } @Override public AssignmentGradeRecord getAssignmentGradeRecordById(Long id) { AssignmentGradeRecord agr = (AssignmentGradeRecord) getHibernateTemplate().load(AssignmentGradeRecord.class, id); AssignmentGradeRecord agrCalculated = new AssignmentGradeRecord(); if (agr != null) { List assignRecordsFromDB = new ArrayList(); assignRecordsFromDB.add(agr); List agrs = this.convertPointsToLetterGrade(agr.getAssignment(), agr.getAssignment().getGradebook(), assignRecordsFromDB); agrs = this.convertPointsToPercentage(agr.getAssignment(), agr.getAssignment().getGradebook(), agrs); if (agrs.get(0) != null) { agrCalculated = (AssignmentGradeRecord) agrs.get(0); } } return agrCalculated; } @Override public Comment getCommentById(Long id) { return (Comment) getHibernateTemplate().load(Comment.class, id); } @Override public AssignmentGradeRecord getAssignmentGradeRecordForAssignmentForStudent(final Assignment assignment, final String studentUid) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { if (studentUid == null) { if (log.isInfoEnabled()) log.info("Returning no grade records for a null student UID"); return new ArrayList(); } else if (assignment.isRemoved()) { return new ArrayList(); } Query q = session.createQuery( "from AssignmentGradeRecord as agr where agr.gradableObject.id=:gradableObjectId " + "and agr.studentId=:student"); q.setLong("gradableObjectId", assignment.getId().longValue()); q.setString("student", studentUid); return q.list(); } }; List results = (List) getHibernateTemplate().execute(hc); if (results.size() > 0) { return (AssignmentGradeRecord) results.get(0); } else { return new AssignmentGradeRecord(); } } @Override public List getAllAssignmentGradeRecordsConverted(Long gradebookId, Collection studentUids) { List allAssignRecordsFromDB = getAllAssignmentGradeRecords(gradebookId, studentUids); Gradebook gradebook = getGradebook(gradebookId); if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_POINTS) return allAssignRecordsFromDB; else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { return convertPointsToPercentage(gradebook, allAssignRecordsFromDB); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { return convertPointsToLetterGrade(gradebook, allAssignRecordsFromDB); } return null; } /** * @return Returns set of student UIDs who were given scores higher than the assignment's value. */ @Override public Set updateAssignmentGradeRecords(final Assignment assignment, final Collection gradeRecordsFromCall) throws StaleObjectModificationException { // If no grade records are sent, don't bother doing anything with the db if (gradeRecordsFromCall.size() == 0) { log.debug("updateAssignmentGradeRecords called for zero grade records"); return new HashSet(); } if (logData.isDebugEnabled()) logData.debug("BEGIN: Update " + gradeRecordsFromCall.size() + " scores for gradebook=" + assignment.getGradebook().getUid() + ", assignment=" + assignment.getName()); HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Date now = new Date(); String graderId = authn.getUserUid(); Set studentsWithUpdatedAssignmentGradeRecords = new HashSet(); Set studentsWithExcessiveScores = new HashSet(); /** synchronize from external application*/ if (synchronizer != null) { boolean isUpdateAll = Boolean.TRUE.equals(ThreadLocalManager.get("iquiz_update_all")); boolean isIquizCall = Boolean.TRUE.equals(ThreadLocalManager.get("iquiz_call")); boolean isStudentView = Boolean.TRUE.equals(ThreadLocalManager.get("iquiz_student_view")); Map iquizAssignmentMap = null; List legacyUpdates = new ArrayList(); Map convertedEidUidRecordMap = null; convertedEidUidRecordMap = synchronizer.convertEidUid(gradeRecordsFromCall); if (!isUpdateAll && synchronizer != null && !synchronizer.isProjectSite()) { iquizAssignmentMap = synchronizer.getLegacyAssignmentWithStats(assignment.getName()); } Map recordsFromCLDb = null; if (synchronizer != null && isIquizCall && isUpdateAll) { recordsFromCLDb = synchronizer.getPersistentRecords(assignment.getId()); } for (Iterator iter = gradeRecordsFromCall.iterator(); iter.hasNext();) { AssignmentGradeRecord gradeRecordFromCall = (AssignmentGradeRecord) iter.next(); boolean updated = false; if (isIquizCall && synchronizer != null) { gradeRecordFromCall = synchronizer.convertIquizRecordToUid(gradeRecordFromCall, convertedEidUidRecordMap, isUpdateAll, graderId); } else { gradeRecordFromCall.setGraderId(graderId); gradeRecordFromCall.setDateRecorded(now); } try { /** sychronize - add condition for null value */ if (gradeRecordFromCall != null) { if (gradeRecordFromCall.getId() == null && isIquizCall && isUpdateAll && recordsFromCLDb != null) { AssignmentGradeRecord returnedPersistentItem = (AssignmentGradeRecord) recordsFromCLDb .get(gradeRecordFromCall.getStudentId()); if (returnedPersistentItem != null && returnedPersistentItem.getPointsEarned() != null && gradeRecordFromCall.getPointsEarned() != null && !returnedPersistentItem.getPointsEarned() .equals(gradeRecordFromCall.getPointsEarned())) { graderId = gradeRecordFromCall.getGraderId(); updated = true; returnedPersistentItem.setGraderId(gradeRecordFromCall.getGraderId()); returnedPersistentItem .setPointsEarned(gradeRecordFromCall.getPointsEarned()); returnedPersistentItem .setDateRecorded(gradeRecordFromCall.getDateRecorded()); session.saveOrUpdate(returnedPersistentItem); } else if (returnedPersistentItem == null) { graderId = gradeRecordFromCall.getGraderId(); updated = true; session.saveOrUpdate(gradeRecordFromCall); } } else { updated = true; session.saveOrUpdate(gradeRecordFromCall); } } if (!isUpdateAll && !isStudentView && synchronizer != null && !synchronizer.isProjectSite()) { Object updateIquizRecord = synchronizer.getNeededUpdateIquizRecord(assignment, gradeRecordFromCall); if (updateIquizRecord != null) legacyUpdates.add(updateIquizRecord); } } catch (TransientObjectException e) { // It's possible that a previously unscored student // was scored behind the current user's back before // the user saved the new score. This translates // that case into an optimistic locking failure. if (log.isInfoEnabled()) log.info( "An optimistic locking failure occurred while attempting to add a new assignment grade record"); throw new StaleObjectModificationException(e); } // Check for excessive (AKA extra credit) scoring. /** synchronize - add condition for null value*/ if (gradeRecordFromCall != null && updated == true) { if (gradeRecordFromCall.getPointsEarned() != null && !assignment.getUngraded() && gradeRecordFromCall.getPointsEarned() .compareTo(assignment.getPointsPossible()) > 0) { studentsWithExcessiveScores.add(gradeRecordFromCall.getStudentId()); } logAssignmentGradingEvent(gradeRecordFromCall, graderId, assignment, session); studentsWithUpdatedAssignmentGradeRecords.add(gradeRecordFromCall.getStudentId()); } /** synchronize external records */ if (legacyUpdates.size() > 0 && synchronizer != null) { synchronizer.updateLegacyGradeRecords(assignment.getName(), legacyUpdates); } } } else { for (Iterator iter = gradeRecordsFromCall.iterator(); iter.hasNext();) { AssignmentGradeRecord gradeRecordFromCall = (AssignmentGradeRecord) iter.next(); gradeRecordFromCall.setGraderId(graderId); gradeRecordFromCall.setDateRecorded(now); try { session.saveOrUpdate(gradeRecordFromCall); } catch (TransientObjectException e) { // It's possible that a previously unscored student // was scored behind the current user's back before // the user saved the new score. This translates // that case into an optimistic locking failure. if (log.isInfoEnabled()) log.info( "An optimistic locking failure occurred while attempting to add a new assignment grade record"); throw new StaleObjectModificationException(e); } // Check for excessive (AKA extra credit) scoring. if (gradeRecordFromCall.getPointsEarned() != null && !assignment.getUngraded() && gradeRecordFromCall.getPointsEarned() .compareTo(assignment.getPointsPossible()) > 0) { studentsWithExcessiveScores.add(gradeRecordFromCall.getStudentId()); } // Log the grading event, and keep track of the students with saved/updated grades logAssignmentGradingEvent(gradeRecordFromCall, graderId, assignment, session); studentsWithUpdatedAssignmentGradeRecords.add(gradeRecordFromCall.getStudentId()); } } if (logData.isDebugEnabled()) logData.debug("Updated " + studentsWithUpdatedAssignmentGradeRecords.size() + " assignment score records"); return studentsWithExcessiveScores; } }; Set studentsWithExcessiveScores = (Set) getHibernateTemplate().execute(hc); if (logData.isDebugEnabled()) logData.debug("END: Update " + gradeRecordsFromCall.size() + " scores for gradebook=" + assignment.getGradebook().getUid() + ", assignment=" + assignment.getName()); return studentsWithExcessiveScores; } /** * * @return Returns set of Assignments given scores higher than the assignment's value. */ private Set updateStudentGradeRecords(final Collection gradeRecordsFromCall, final String studentId) throws StaleObjectModificationException, IllegalArgumentException { if (studentId == null) { throw new IllegalArgumentException( "no studentId passed to GradebookManagerHibernateImpl.updateStudentGradeRecords"); } // If no grade records are sent, don't bother doing anything with the db if (gradeRecordsFromCall.size() == 0) { log.debug("updateStudentGradeRecords called for zero grade records"); return new HashSet(); } if (logData.isDebugEnabled()) logData.debug("BEGIN: Update " + gradeRecordsFromCall.size()); HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Date now = new Date(); String graderId = authn.getUserUid(); Set studentsWithUpdatedAssignmentGradeRecords = new HashSet(); Set assignmentsWithExcessiveScores = new HashSet(); /** synchronize from external application*/ if (synchronizer != null) { boolean isUpdateAll = Boolean.TRUE.equals(ThreadLocalManager.get("iquiz_update_all")); boolean isIquizCall = Boolean.TRUE.equals(ThreadLocalManager.get("iquiz_call")); boolean isStudentView = Boolean.TRUE.equals(ThreadLocalManager.get("iquiz_student_view")); List legacyUpdates = new ArrayList(); Map convertedEidUidRecordMap = synchronizer.convertEidUid(gradeRecordsFromCall); Map recordsFromCLDb = null; if (synchronizer != null && isIquizCall && isUpdateAll) { recordsFromCLDb = synchronizer.getPersistentRecordsForStudent(studentId); } for (Iterator iter = gradeRecordsFromCall.iterator(); iter.hasNext();) { AssignmentGradeRecord gradeRecordFromCall = (AssignmentGradeRecord) iter.next(); Assignment assignment = null; if (gradeRecordFromCall != null) { assignment = gradeRecordFromCall.getAssignment(); } boolean updated = false; if (isIquizCall && synchronizer != null) { gradeRecordFromCall = synchronizer.convertIquizRecordToUid(gradeRecordFromCall, convertedEidUidRecordMap, isUpdateAll, graderId); } else { gradeRecordFromCall.setGraderId(graderId); gradeRecordFromCall.setDateRecorded(now); } try { /** sychronize - add condition for null value */ if (gradeRecordFromCall != null) { if (gradeRecordFromCall.getId() == null && isIquizCall && isUpdateAll && recordsFromCLDb != null) { AssignmentGradeRecord returnedPersistentItem = (AssignmentGradeRecord) recordsFromCLDb .get(gradeRecordFromCall.getGradableObject().getId()); if (returnedPersistentItem != null && returnedPersistentItem.getPointsEarned() != null && gradeRecordFromCall.getPointsEarned() != null && !returnedPersistentItem.getPointsEarned() .equals(gradeRecordFromCall.getPointsEarned())) { graderId = gradeRecordFromCall.getGraderId(); updated = true; returnedPersistentItem.setGraderId(gradeRecordFromCall.getGraderId()); returnedPersistentItem .setPointsEarned(gradeRecordFromCall.getPointsEarned()); returnedPersistentItem .setDateRecorded(gradeRecordFromCall.getDateRecorded()); session.saveOrUpdate(returnedPersistentItem); } else if (returnedPersistentItem == null) { graderId = gradeRecordFromCall.getGraderId(); updated = true; session.saveOrUpdate(gradeRecordFromCall); } } else { updated = true; session.saveOrUpdate(gradeRecordFromCall); } } if (assignment != null && !isUpdateAll && !isStudentView && synchronizer != null && !synchronizer.isProjectSite()) { Object updateIquizRecord = synchronizer.getNeededUpdateIquizRecord(assignment, gradeRecordFromCall); if (updateIquizRecord != null) legacyUpdates.add(updateIquizRecord); } } catch (TransientObjectException e) { // It's possible that a previously unscored student // was scored behind the current user's back before // the user saved the new score. This translates // that case into an optimistic locking failure. if (log.isInfoEnabled()) log.info( "An optimistic locking failure occurred while attempting to add a new assignment grade record"); throw new StaleObjectModificationException(e); } // Check for excessive (AKA extra credit) scoring. /** synchronize - add condition for null value*/ if (gradeRecordFromCall != null && updated == true && assignment != null) { if (gradeRecordFromCall.getPointsEarned() != null && !assignment.getUngraded() && gradeRecordFromCall.getPointsEarned() .compareTo(assignment.getPointsPossible()) > 0) { assignmentsWithExcessiveScores.add(assignment); } // Log the grading event, and keep track of the students with saved/updated grades logAssignmentGradingEvent(gradeRecordFromCall, graderId, assignment, session); studentsWithUpdatedAssignmentGradeRecords.add(gradeRecordFromCall.getStudentId()); } /** synchronize external records */ if (legacyUpdates.size() > 0 && synchronizer != null && assignment != null) { synchronizer.updateLegacyGradeRecords(assignment.getName(), legacyUpdates); } } } else { for (Iterator iter = gradeRecordsFromCall.iterator(); iter.hasNext();) { AssignmentGradeRecord gradeRecordFromCall = (AssignmentGradeRecord) iter.next(); Assignment assignment = gradeRecordFromCall.getAssignment(); Double pointsPossible = assignment.getPointsPossible(); gradeRecordFromCall.setGraderId(graderId); gradeRecordFromCall.setDateRecorded(now); try { session.saveOrUpdate(gradeRecordFromCall); } catch (TransientObjectException e) { // It's possible that a previously unscored student // was scored behind the current user's back before // the user saved the new score. This translates // that case into an optimistic locking failure. if (log.isInfoEnabled()) log.info( "An optimistic locking failure occurred while attempting to add a new assignment grade record"); throw new StaleObjectModificationException(e); } // Check for excessive (AKA extra credit) scoring. if (gradeRecordFromCall.getPointsEarned() != null && !assignment.getUngraded() && gradeRecordFromCall.getPointsEarned().compareTo(pointsPossible) > 0) { assignmentsWithExcessiveScores.add(assignment); } // Log the grading event, and keep track of the students with saved/updated grades logAssignmentGradingEvent(gradeRecordFromCall, graderId, assignment, session); studentsWithUpdatedAssignmentGradeRecords.add(gradeRecordFromCall.getStudentId()); } } if (logData.isDebugEnabled()) logData.debug("Updated " + studentsWithUpdatedAssignmentGradeRecords.size() + " assignment score records"); return assignmentsWithExcessiveScores; } }; Set assignmentsWithExcessiveScores = (Set) getHibernateTemplate().execute(hc); if (logData.isDebugEnabled()) logData.debug("END: Update " + gradeRecordsFromCall.size()); return assignmentsWithExcessiveScores; } @Override public Set updateAssignmentGradesAndComments(Assignment assignment, Collection gradeRecords, Collection comments) throws StaleObjectModificationException { //Set studentsWithExcessiveScores = updateAssignmentGradeRecords(assignment, gradeRecords); Gradebook gradebook = getGradebook(assignment.getGradebook().getId()); Set studentsWithExcessiveScores = updateAssignmentGradeRecords(assignment, gradeRecords, gradebook.getGrade_type()); updateComments(comments); return studentsWithExcessiveScores; } @Override public void updateComments(final Collection comments) throws StaleObjectModificationException { final Date now = new Date(); final String graderId = authn.getUserUid(); // Unlike the complex grade update logic, this method assumes that // the client has done the work of filtering out any unchanged records // and isn't interested in throwing an optimistic locking exception for untouched records // which were changed by other sessions. HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { for (Iterator iter = comments.iterator(); iter.hasNext();) { Comment comment = (Comment) iter.next(); comment.setGraderId(graderId); comment.setDateRecorded(now); session.saveOrUpdate(comment); } return null; } }; try { getHibernateTemplate().execute(hc); } catch (DataIntegrityViolationException e) { // If a student hasn't yet received a comment for this // assignment, and two graders try to save a new comment record at the // same time, the database should report a unique constraint violation. // Since that's similar to the conflict between two graders who // are trying to update an existing comment record at the same // same time, this method translates the exception into an // optimistic locking failure. if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to update comments"); throw new StaleObjectModificationException(e); } } /** */ @Override public void updateCourseGradeRecords(final CourseGrade courseGrade, final Collection gradeRecordsFromCall) throws StaleObjectModificationException { if (gradeRecordsFromCall.size() == 0) { log.debug("updateCourseGradeRecords called with zero grade records to update"); return; } if (logData.isDebugEnabled()) logData.debug("BEGIN: Update " + gradeRecordsFromCall.size() + " course grades for gradebook=" + courseGrade.getGradebook().getUid()); HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { for (Iterator iter = gradeRecordsFromCall.iterator(); iter.hasNext();) { session.evict(iter.next()); } Date now = new Date(); String graderId = authn.getUserUid(); int numberOfUpdatedGrades = 0; for (Iterator iter = gradeRecordsFromCall.iterator(); iter.hasNext();) { // The modified course grade record CourseGradeRecord gradeRecordFromCall = (CourseGradeRecord) iter.next(); gradeRecordFromCall.setGraderId(graderId); gradeRecordFromCall.setDateRecorded(now); try { session.saveOrUpdate(gradeRecordFromCall); session.flush(); } catch (StaleObjectStateException sose) { if (log.isInfoEnabled()) log.info( "An optimistic locking failure occurred while attempting to update course grade records"); throw new StaleObjectModificationException(sose); } // Log the grading event session.save(new GradingEvent(courseGrade, graderId, gradeRecordFromCall.getStudentId(), gradeRecordFromCall.getEnteredGrade())); numberOfUpdatedGrades++; } if (logData.isDebugEnabled()) logData.debug("Changed " + numberOfUpdatedGrades + " course grades for gradebook=" + courseGrade.getGradebook().getUid()); return null; } }; try { getHibernateTemplate().execute(hc); if (logData.isDebugEnabled()) logData.debug("END: Update " + gradeRecordsFromCall.size() + " course grades for gradebook=" + courseGrade.getGradebook().getUid()); } catch (DataIntegrityViolationException e) { // It's possible that a previously ungraded student // was graded behind the current user's back before // the user saved the new grade. This translates // that case into an optimistic locking failure. if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to update course grade records"); throw new StaleObjectModificationException(e); } } @Override public boolean isEnteredAssignmentScores(final Long assignmentId) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { List totalList = (List) session.createQuery( "select agr from AssignmentGradeRecord as agr where agr.gradableObject.id=? and agr.pointsEarned is not null") .setLong(0, assignmentId.longValue()).list(); Integer total = new Integer(totalList.size()); if (log.isDebugEnabled()) log.debug("assignment " + assignmentId + " has " + total + " entered scores"); return total; } }; return ((Integer) getHibernateTemplate().execute(hc)).intValue() > 0; } /** */ @Override public List getStudentGradeRecords(final Long gradebookId, final String studentId) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { return session.createQuery( "from AssignmentGradeRecord as agr where agr.studentId=? and agr.gradableObject.removed=false and agr.gradableObject.gradebook.id=?") .setString(0, studentId).setLong(1, gradebookId.longValue()).list(); } }; return (List) getHibernateTemplate().execute(hc); } @Override public List getStudentGradeRecordsConverted(final Long gradebookId, final String studentId) { List studentGradeRecsFromDB = getStudentGradeRecords(gradebookId, studentId); Gradebook gradebook = getGradebook(gradebookId); if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_POINTS) return studentGradeRecsFromDB; else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { return convertPointsToPercentage(gradebook, studentGradeRecsFromDB); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { return convertPointsToLetterGrade(gradebook, studentGradeRecsFromDB); } return null; } private double getTotalPointsEarnedInternal(final Long gradebookId, final String studentId, final Session session) { double totalPointsEarned = 0; Iterator scoresIter = session.createQuery( "select agr.pointsEarned from AssignmentGradeRecord agr, Assignment asn where agr.gradableObject=asn and agr.studentId=:student and asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0") .setParameter("student", studentId).setParameter("gbid", gradebookId).list().iterator(); while (scoresIter.hasNext()) { Double pointsEarned = (Double) scoresIter.next(); if (pointsEarned != null) { totalPointsEarned += pointsEarned.doubleValue(); } } if (log.isDebugEnabled()) log.debug( "getTotalPointsEarnedInternal for studentId=" + studentId + " returning " + totalPointsEarned); return totalPointsEarned; } /** * * @param studentId * @param gradebook * @param categories * @param gradeRecsthe AssignmentGradeRecords for the given student * @param countedAssigns - the Assignments in this gradebook that are counted toward the course grade. * use {@link #getCountedAssignments(Session, Long)} to retrieve this list * @return the total points earned that count toward the course grade. * a List is returned with two elements: * [1] is (Double) totalPointsEarned * [2] is (Double) literalTotalPointsEarned */ abstract List getTotalPointsEarnedInternal(final String studentId, final Gradebook gradebook, final List categories, final List<AssignmentGradeRecord> gradeRecs, List<Assignment> countedAssigns); //for testing public double getTotalPointsEarnedInternal(final Long gradebookId, final String studentId, final Gradebook gradebook, final List categories) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { double totalPointsEarned = 0; Iterator scoresIter = session.createQuery( "select agr.pointsEarned, asn from AssignmentGradeRecord agr, Assignment asn where agr.gradableObject=asn and agr.studentId=:student and asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0") .setParameter("student", studentId).setParameter("gbid", gradebookId).list().iterator(); List assgnsList = session.createQuery( "from Assignment as asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0") .setParameter("gbid", gradebookId).list(); Map cateScoreMap = new HashMap(); Map cateTotalScoreMap = new HashMap(); Set assignmentsTaken = new HashSet(); while (scoresIter.hasNext()) { Object[] returned = (Object[]) scoresIter.next(); Double pointsEarned = (Double) returned[0]; Assignment go = (Assignment) returned[1]; if (pointsEarned != null) { if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { totalPointsEarned += pointsEarned.doubleValue(); assignmentsTaken.add(go.getId()); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && go != null) { totalPointsEarned += pointsEarned.doubleValue(); assignmentsTaken.add(go.getId()); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && go != null && categories != null) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && go.getCategory() != null && cate.getId().equals(go.getCategory().getId())) { assignmentsTaken.add(go.getId()); if (cateScoreMap.get(cate.getId()) != null) { cateScoreMap.put(cate.getId(), new Double(((Double) cateScoreMap.get(cate.getId())).doubleValue() + pointsEarned.doubleValue())); } else { cateScoreMap.put(cate.getId(), new Double(pointsEarned)); } break; } } } } } if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && categories != null) { Iterator assgnsIter = assgnsList.iterator(); while (assgnsIter.hasNext()) { Assignment asgn = (Assignment) assgnsIter.next(); if (assignmentsTaken.contains(asgn.getId())) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && asgn.getCategory() != null && cate.getId().equals(asgn.getCategory().getId())) { if (cateTotalScoreMap.get(cate.getId()) == null) { cateTotalScoreMap.put(cate.getId(), asgn.getPointsPossible()); } else { cateTotalScoreMap.put(cate.getId(), new Double( ((Double) cateTotalScoreMap.get(cate.getId())).doubleValue() + asgn.getPointsPossible().doubleValue())); } } } } } } if (assignmentsTaken.isEmpty()) totalPointsEarned = -1; if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && cateScoreMap.get(cate.getId()) != null && cateTotalScoreMap.get(cate.getId()) != null) { totalPointsEarned += ((Double) cateScoreMap.get(cate.getId())).doubleValue() * cate.getWeight().doubleValue() / ((Double) cateTotalScoreMap.get(cate.getId())).doubleValue(); } } } if (log.isDebugEnabled()) log.debug("getTotalPointsEarnedInternal for studentId=" + studentId + " returning " + totalPointsEarned); return totalPointsEarned; } }; return (Double) getHibernateTemplate().execute(hc); } @Override public GradingEvents getGradingEvents(final GradableObject gradableObject, final Collection studentIds) { // Don't attempt to run the query if there are no enrollments if (studentIds == null || studentIds.size() == 0) { log.debug("No enrollments were specified. Returning an empty GradingEvents object"); return new GradingEvents(); } HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException, SQLException { List eventsList; if (studentIds.size() <= MAX_NUMBER_OF_SQL_PARAMETERS_IN_LIST) { Query q = session.createQuery( "from GradingEvent as ge where ge.gradableObject=:go and ge.studentId in (:students)"); q.setParameter("go", gradableObject, Hibernate.entity(GradableObject.class)); q.setParameterList("students", studentIds); eventsList = q.list(); } else { Query q = session.createQuery("from GradingEvent as ge where ge.gradableObject=:go"); q.setParameter("go", gradableObject, Hibernate.entity(GradableObject.class)); eventsList = new ArrayList(); for (Iterator iter = q.list().iterator(); iter.hasNext();) { GradingEvent event = (GradingEvent) iter.next(); if (studentIds.contains(event.getStudentId())) { eventsList.add(event); } } } return eventsList; } }; List list = (List) getHibernateTemplate().execute(hc); GradingEvents events = new GradingEvents(); for (Iterator iter = list.iterator(); iter.hasNext();) { GradingEvent event = (GradingEvent) iter.next(); events.addEvent(event); } return events; } @Override public Map getGradingEventsForStudent(final String studentId, final Collection gradableObjects) { if (log.isDebugEnabled()) log.debug("getGradingEventsForStudent called for studentId:" + studentId); Map goEventListMap = new HashMap(); // Don't attempt to run the query if there are no gradableObjects or student id if (gradableObjects == null || gradableObjects.size() == 0) { log.debug("No gb items were specified. Returning an empty GradingEvents object"); return goEventListMap; } if (studentId == null) { log.debug("No student id was specified. Returning an empty GradingEvents object"); return goEventListMap; } for (Iterator goIter = gradableObjects.iterator(); goIter.hasNext();) { GradableObject go = (GradableObject) goIter.next(); goEventListMap.put(go, new ArrayList()); } HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException, SQLException { List eventsList; if (gradableObjects.size() <= MAX_NUMBER_OF_SQL_PARAMETERS_IN_LIST) { Query q = session.createQuery( "from GradingEvent as ge where ge.studentId=:studentId and ge.gradableObject in (:gradableObjects)"); q.setParameterList("gradableObjects", gradableObjects, Hibernate.entity(GradableObject.class)); q.setParameter("studentId", studentId); eventsList = q.list(); } else { Query q = session.createQuery("from GradingEvent as ge where ge.studentId=:studentId"); q.setParameter("studentId", studentId); eventsList = new ArrayList(); for (Iterator iter = q.list().iterator(); iter.hasNext();) { GradingEvent event = (GradingEvent) iter.next(); if (gradableObjects.contains(event.getGradableObject())) { eventsList.add(event); } } } return eventsList; } }; List list = (List) getHibernateTemplate().execute(hc); for (Iterator iter = list.iterator(); iter.hasNext();) { GradingEvent event = (GradingEvent) iter.next(); GradableObject go = event.getGradableObject(); List goEventList = (List) goEventListMap.get(go); if (goEventList != null) { goEventList.add(event); goEventListMap.put(go, goEventList); } else { log.debug("event retrieved by getGradingEventsForStudent not associated with passed go list"); } } return goEventListMap; } /** */ @Override public List getAssignments(final Long gradebookId, final String sortBy, final boolean ascending) { return (List) getHibernateTemplate().execute(new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { List assignments = getAssignments(gradebookId, session); /** synchronize from external application*/ if (synchronizer != null) { synchronizer.synchrornizeAssignments(assignments); assignments = getAssignments(gradebookId, session); } /** end synchronize from external application*/ sortAssignments(assignments, sortBy, ascending); return assignments; } }); } /** */ @Override public List getAssignmentsWithStats(final Long gradebookId, final String sortBy, final boolean ascending) { return getAssignmentsWithStats(gradebookId, sortBy, ascending, false); } /** */ public List getAssignmentsWithStats(final Long gradebookId, final String sortBy, final boolean ascending, final boolean includeDroppedScores) { Set studentUids = getAllStudentUids(getGradebookUid(gradebookId)); List<AssignmentGradeRecord> gradeRecords = getAllAssignmentGradeRecords(gradebookId, studentUids); if (!includeDroppedScores) { applyDropScores(gradeRecords); } List assignments = getAssignmentsWithStats(gradebookId, sortBy, ascending, gradeRecords); return assignments; } /** * * @param gradebookId * @param sortBy * @param ascending * @param gradeRecords - use {@link #getAllAssignmentGradeRecords(Long, Collection)} * @return a list of all assignments with stats populated. this method is * helpful to eliminate repeated calls to {@link #getAllAssignmentGradeRecords(Long, Collection)} * if you have already retrieved them */ private List getAssignmentsWithStats(final Long gradebookId, final String sortBy, final boolean ascending, List<AssignmentGradeRecord> gradeRecords) { List assignments = getAssignments(gradebookId); for (Iterator iter = assignments.iterator(); iter.hasNext();) { Assignment assignment = (Assignment) iter.next(); assignment.calculateStatistics(gradeRecords); } sortAssignments(assignments, sortBy, ascending); return assignments; } @Override public List getAssignmentsAndCourseGradeWithStats(final Long gradebookId, final String sortBy, final boolean ascending) { Set studentUids = getAllStudentUids(getGradebookUid(gradebookId)); List assignments = getAssignments(gradebookId); CourseGrade courseGrade = getCourseGrade(gradebookId); Map gradeRecordMap = new HashMap(); List<AssignmentGradeRecord> gradeRecords = getAllAssignmentGradeRecords(gradebookId, studentUids); applyDropScores(gradeRecords); addToGradeRecordMap(gradeRecordMap, gradeRecords); for (Iterator iter = assignments.iterator(); iter.hasNext();) { Assignment assignment = (Assignment) iter.next(); assignment.calculateStatistics(gradeRecords); } List<CourseGradeRecord> courseGradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, studentUids, assignments, gradeRecordMap); courseGrade.calculateStatistics(courseGradeRecords, studentUids.size()); sortAssignments(assignments, sortBy, ascending); // Always put the Course Grade at the end. assignments.add(courseGrade); return assignments; } protected List filterAndPopulateCourseGradeRecordsByStudents(CourseGrade courseGrade, Collection gradeRecords, Collection studentUids) { List filteredRecords = new ArrayList(); Set missingStudents = new HashSet(studentUids); for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { CourseGradeRecord cgr = (CourseGradeRecord) iter.next(); if (studentUids.contains(cgr.getStudentId())) { filteredRecords.add(cgr); missingStudents.remove(cgr.getStudentId()); } } for (Iterator iter = missingStudents.iterator(); iter.hasNext();) { String studentUid = (String) iter.next(); CourseGradeRecord cgr = new CourseGradeRecord(courseGrade, studentUid); filteredRecords.add(cgr); } return filteredRecords; } /** * TODO Remove this method in favor of doing database sorting. * * @param assignments * @param sortBy * @param ascending */ private void sortAssignments(List assignments, String sortBy, boolean ascending) { // WARNING: AZ - this method is duplicated in GradebookManagerHibernateImpl Comparator comp; if (Assignment.SORT_BY_NAME.equals(sortBy)) { comp = GradableObject.nameComparator; } else if (Assignment.SORT_BY_DATE.equals(sortBy)) { comp = GradableObject.dateComparator; } else if (Assignment.SORT_BY_MEAN.equals(sortBy)) { comp = GradableObject.meanComparator; } else if (Assignment.SORT_BY_POINTS.equals(sortBy)) { comp = Assignment.pointsComparator; } else if (Assignment.SORT_BY_RELEASED.equals(sortBy)) { comp = Assignment.releasedComparator; } else if (Assignment.SORT_BY_COUNTED.equals(sortBy)) { comp = Assignment.countedComparator; } else if (Assignment.SORT_BY_EDITOR.equals(sortBy)) { comp = Assignment.gradeEditorComparator; } else if (Assignment.SORT_BY_SORTING.equals(sortBy)) { comp = GradableObject.sortingComparator; } else { comp = GradableObject.defaultComparator; } Collections.sort(assignments, comp); if (!ascending) { Collections.reverse(assignments); } if (log.isDebugEnabled()) { log.debug("sortAssignments: ordering by " + sortBy + " (" + comp + "), ascending=" + ascending); } } /** */ @Override public List getAssignments(Long gradebookId) { return getAssignments(gradebookId, Assignment.DEFAULT_SORT, true); } /** */ @Override public Assignment getAssignmentWithStats(Long assignmentId) { return getAssignmentWithStats(assignmentId, false); } /** */ public Assignment getAssignmentWithStats(Long assignmentId, boolean includeDroppedScores) { Assignment assignment = getAssignment(assignmentId); Long gradebookId = assignment.getGradebook().getId(); Set studentUids = getAllStudentUids(getGradebookUid(gradebookId)); List<AssignmentGradeRecord> gradeRecords = getAssignmentGradeRecords(assignment, studentUids); if (!includeDroppedScores) { applyDropScores(gradeRecords); } assignment.calculateStatistics(gradeRecords); return assignment; } /** */ @Override public void updateAssignment(final Assignment assignment) throws ConflictingAssignmentNameException, StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { updateAssignment(assignment, session); return null; } }; try { /** synchronize from external application*/ String oldTitle = null; if (synchronizer != null) { Assignment assign = getAssignment(assignment.getId()); oldTitle = assign.getName(); } getHibernateTemplate().execute(hc); /** synchronize from external application*/ if (synchronizer != null && oldTitle != null && !synchronizer.isProjectSite()) { synchronizer.updateAssignment(oldTitle, assignment.getName(), assignment.getGradebook().getGrade_type()); } } catch (HibernateOptimisticLockingFailureException holfe) { if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to update an assignment"); throw new StaleObjectModificationException(holfe); } } /** * update category and assignments in same session * for drop scores functionality */ @Override public void updateCategoryAndAssignmentsPointsPossible(final Long gradebookId, final Category category) throws ConflictingAssignmentNameException, StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { updateCategory(category, session); // get assignments for this category Iterator iter = session.createQuery( "select asn from Assignment asn where asn.gradebook.id=:gbid and asn.category=:category and asn.removed = false") .setParameter("gbid", gradebookId).setParameter("category", category).list().iterator(); while (iter.hasNext()) { Assignment assignment = (Assignment) iter.next(); session.evict(assignment); if (assignment.getGradebook().getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { assignment.setUngraded(true); } if (assignment.getUngraded()) assignment.setNotCounted(true); // for drop score categories pointsPossible comes from the category assignment.setPointsPossible(category.getItemValue()); updateAssignment(assignment, session); } return null; } }; try { /** synchronize from external application*/ Map oldTitles = new HashMap(); List assignments = category.getAssignmentList(); if (synchronizer != null) { for (Iterator iter = assignments.iterator(); iter.hasNext();) { Assignment assignment = (Assignment) iter.next(); Assignment assign = getAssignment(assignment.getId()); oldTitles.put(assignment.getId(), assign.getName()); } } getHibernateTemplate().execute(hc); /** synchronize from external application*/ for (Iterator iter = assignments.iterator(); iter.hasNext();) { Assignment assignment = (Assignment) iter.next(); String oldTitle = (String) oldTitles.get(assignment.getId()); assignment.setPointsPossible(category.getItemValue()); if (synchronizer != null && oldTitle != null && !synchronizer.isProjectSite() && !assignment.getUngraded()) { synchronizer.updateAssignment(oldTitle, assignment.getName(), assignment.getGradebook().getGrade_type()); } } } catch (HibernateOptimisticLockingFailureException holfe) { if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to update an assignment"); throw new StaleObjectModificationException(holfe); } } /** * Gets the total number of points possible in a gradebook. */ @Override public double getTotalPoints(final Long gradebookId) { Double totalPoints = (Double) getHibernateTemplate().execute(new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Gradebook gradebook = getGradebook(gradebookId); List cates = getCategoriesWithAssignments(gradebookId); return new Double(getLiteralTotalPointsInternal(gradebookId, session, gradebook, cates)); //return new Double(getTotalPointsInternal(gradebookId, session)); } }); return totalPoints.doubleValue(); } private double getTotalPointsInternal(Long gradebookId, Session session) { double totalPointsPossible = 0; Iterator assignmentPointsIter = session.createQuery( "select asn.pointsPossible from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false") .setParameter("gbid", gradebookId).list().iterator(); while (assignmentPointsIter.hasNext()) { Double pointsPossible = (Double) assignmentPointsIter.next(); totalPointsPossible += pointsPossible.doubleValue(); } return totalPointsPossible; } //for testing public double getTotalPointsInternal(final Long gradebookId, final Gradebook gradebook, final List categories, final String studentId) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { double totalPointsPossible = 0; List assgnsList = session.createQuery( "select asn from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0") .setParameter("gbid", gradebookId).list(); Iterator scoresIter = session.createQuery( "select agr.pointsEarned, asn from AssignmentGradeRecord agr, Assignment asn where agr.gradableObject=asn and agr.studentId=:student and asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and asn.pointsPossible > 0") .setParameter("student", studentId).setParameter("gbid", gradebookId).list().iterator(); Set categoryTaken = new HashSet(); Set assignmentsTaken = new HashSet(); while (scoresIter.hasNext()) { Object[] returned = (Object[]) scoresIter.next(); Double pointsEarned = (Double) returned[0]; Assignment go = (Assignment) returned[1]; if (pointsEarned != null) { if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { assignmentsTaken.add(go.getId()); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && go != null) { assignmentsTaken.add(go.getId()); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && go != null && categories != null) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && go.getCategory() != null && cate.getId().equals(go.getCategory().getId())) { assignmentsTaken.add(go.getId()); categoryTaken.add(cate.getId()); break; } } } } } if (!assignmentsTaken.isEmpty()) { if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && categoryTaken.contains(cate.getId())) { totalPointsPossible += cate.getWeight().doubleValue(); } } return totalPointsPossible; } Iterator assignmentIter = assgnsList.iterator(); while (assignmentIter.hasNext()) { Assignment asn = (Assignment) assignmentIter.next(); if (asn != null) { Double pointsPossible = asn.getPointsPossible(); if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY && assignmentsTaken.contains(asn.getId())) { totalPointsPossible += pointsPossible.doubleValue(); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY && assignmentsTaken.contains(asn.getId())) { totalPointsPossible += pointsPossible.doubleValue(); } } } } else totalPointsPossible = -1; return totalPointsPossible; } }; return (Double) getHibernateTemplate().execute(hc); } /** * * @param gradebook * @param categories * @param studentId * @param studentGradeRecs - the AssignmentGradeRecords for the given student * @param countedAssigns - the Assignments in this gradebook that are counted toward the course grade. use {@link #getCountedAssignments(Session, Long)} * @return the total points possible for the given student. if the grade rec is * null or doesn't exist for a counted assignment, then that assignment does not count toward the course grade * for this particular student. */ public abstract double getTotalPointsInternal(final Gradebook gradebook, final List categories, final String studentId, List<AssignmentGradeRecord> studentGradeRecs, List<Assignment> countedAssigns, boolean literalTotal); //for test public double getLiteralTotalPointsInternal(final Long gradebookId, final Gradebook gradebook, final List categories) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { double totalPointsPossible = 0; Iterator assignmentIter = session.createQuery( "select asn from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false") .setParameter("gbid", gradebookId).list().iterator(); while (assignmentIter.hasNext()) { Assignment asn = (Assignment) assignmentIter.next(); if (asn != null) { Double pointsPossible = asn.getPointsPossible(); if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { totalPointsPossible += pointsPossible.doubleValue(); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY) { totalPointsPossible += pointsPossible.doubleValue(); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && categories != null) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && asn.getCategory() != null && cate.getId().equals(asn.getCategory().getId())) { totalPointsPossible += pointsPossible.doubleValue(); break; } } } } } return totalPointsPossible; } }; return (Double) getHibernateTemplate().execute(hc); } private double getLiteralTotalPointsInternal(final Long gradebookId, Session session, final Gradebook gradebook, final List categories) { double totalPointsPossible = 0; Map<Long, Integer> numAssignments = new HashMap<Long, Integer>(); Iterator assignmentIter = session.createQuery( "select asn from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false and (asn.extraCredit=false or asn.extraCredit is null)") .setParameter("gbid", gradebookId).list().iterator(); while (assignmentIter.hasNext()) { Assignment asn = (Assignment) assignmentIter.next(); if (asn != null) { Double pointsPossible = asn.getPointsPossible(); if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) { if (pointsPossible != null) totalPointsPossible += pointsPossible.doubleValue(); } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY) { if (pointsPossible != null) totalPointsPossible += pointsPossible.doubleValue(); for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && asn.getCategory() != null && cate.getId().equals(asn.getCategory().getId())) { Integer num = numAssignments.get(cate.getId()); // to calculate totalPointsToDrop, must know the number of assignments for each category if (num == null) { num = new Integer(0); } num++; numAssignments.put(cate.getId(), num); break; } } } else if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && categories != null) { for (int i = 0; i < categories.size(); i++) { Category cate = (Category) categories.get(i); if (cate != null && !cate.isRemoved() && asn.getCategory() != null && cate.getId().equals(asn.getCategory().getId())) { if (pointsPossible != null) totalPointsPossible += pointsPossible.doubleValue(); Integer num = numAssignments.get(cate.getId()); // to calculate totalPointsToDrop, must know the number of assignments for each category if (num == null) { num = new Integer(0); } num++; numAssignments.put(cate.getId(), num); break; } } } } } double totalPointsToDrop = 0; for (int i = 0; i < categories.size(); i++) { Category category = (Category) categories.get(i); if (category != null && !category.isRemoved() && category.isDropScores()) { Double itemValue = category.getItemValue(); Integer dropHighest = category.getDropHighest(); Integer dropLowest = category.getDrop_lowest(); Integer keepHighest = category.getKeepHighest(); Integer assignmentCount = numAssignments.get(category.getId()); if (keepHighest != null && keepHighest > 0) { if (assignmentCount != null && assignmentCount > 0) { dropLowest = assignmentCount - keepHighest; // dropLowest and keepHighest will not occur at the same time if (dropLowest < 0) { dropLowest = 0; } } } if (assignmentCount != null && assignmentCount > (dropLowest + dropHighest)) { totalPointsToDrop += (itemValue * dropHighest); totalPointsToDrop += (itemValue * dropLowest); } } } totalPointsPossible -= totalPointsToDrop; return totalPointsPossible; } // // private double getLiteralTotalPointsInternal(final Long gradebookId, Session session, final Gradebook gradebook, final List categories) // { // double totalPointsPossible = 0; // Iterator assignmentIter = session.createQuery( // "select asn from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false and asn.ungraded=false"). // setParameter("gbid", gradebookId). // list().iterator(); // while (assignmentIter.hasNext()) { // Assignment asn = (Assignment) assignmentIter.next(); // if(asn != null) // { // Double pointsPossible = asn.getPointsPossible(); // // if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY) // { // totalPointsPossible += pointsPossible.doubleValue(); // } // else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY) // { // totalPointsPossible += pointsPossible.doubleValue(); // } // else if(gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY && categories != null) // { // for(int i=0; i<categories.size(); i++) // { // Category cate = (Category) categories.get(i); // if(cate != null && !cate.isRemoved() && asn.getCategory() != null && cate.getId().equals(asn.getCategory().getId())) // { // totalPointsPossible += pointsPossible.doubleValue(); // break; // } // } // } // } // } // return totalPointsPossible; // } @Override public Gradebook getGradebookWithGradeMappings(final Long id) { return (Gradebook) getHibernateTemplate().execute(new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Gradebook gradebook = (Gradebook) session.load(Gradebook.class, id); Hibernate.initialize(gradebook.getGradeMappings()); return gradebook; } }); } /** * * @param spreadsheetId * @return */ @Override public Spreadsheet getSpreadsheet(final Long spreadsheetId) { return (Spreadsheet) getHibernateTemplate().load(Spreadsheet.class, spreadsheetId); } /** * * @param gradebookId * @return */ @Override public List getSpreadsheets(final Long gradebookId) { return (List) getHibernateTemplate().execute(new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { List spreadsheets = getSpreadsheets(gradebookId, session); return spreadsheets; } }); } /** * * @param spreadsheetId */ @Override public void removeSpreadsheet(final Long spreadsheetId) throws StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Spreadsheet spt = (Spreadsheet) session.load(Spreadsheet.class, spreadsheetId); session.delete(spt); if (log.isInfoEnabled()) log.info("Spreadsheet " + spt.getName() + " has been removed from gradebook"); return null; } }; getHibernateTemplate().execute(hc); } /** * * @param spreadsheet */ public void updateSpreadsheet(final Spreadsheet spreadsheet) throws ConflictingAssignmentNameException, StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { // Ensure that we don't have the assignment in the session, since // we need to compare the existing one in the db to our edited assignment session.evict(spreadsheet); Spreadsheet sptFromDb = (Spreadsheet) session.load(Spreadsheet.class, spreadsheet.getId()); List conflictList = ((List) session.createQuery( "select spt from Spreadsheet as spt where spt.name = ? and spt.gradebook = ? and spt.id != ?") .setString(0, spreadsheet.getName()).setEntity(1, spreadsheet.getGradebook()) .setLong(2, spreadsheet.getId().longValue()).list()); int numNameConflicts = conflictList.size(); if (numNameConflicts > 0) { throw new ConflictingAssignmentNameException( "You can not save multiple spreadsheets in a gradebook with the same name"); } session.evict(sptFromDb); session.update(spreadsheet); return null; } }; try { getHibernateTemplate().execute(hc); } catch (HibernateOptimisticLockingFailureException holfe) { if (log.isInfoEnabled()) log.info("An optimistic locking failure occurred while attempting to update a spreadsheet"); throw new StaleObjectModificationException(holfe); } } @Override public Long createSpreadsheet(final Long gradebookId, final String name, final String creator, Date dateCreated, final String content) throws ConflictingSpreadsheetNameException, StaleObjectModificationException { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Gradebook gb = (Gradebook) session.load(Gradebook.class, gradebookId); List conflictList = ((List) session .createQuery("select spt from Spreadsheet as spt where spt.name = ? and spt.gradebook = ? ") .setString(0, name).setEntity(1, gb).list()); int numNameConflicts = conflictList.size(); if (numNameConflicts > 0) { throw new ConflictingSpreadsheetNameException( "You can not save multiple spreadsheets in a gradebook with the same name"); } Spreadsheet spt = new Spreadsheet(); spt.setGradebook(gb); spt.setName(name); spt.setCreator(creator); spt.setDateCreated(new Date()); spt.setContent(content); // Save the new assignment Long id = (Long) session.save(spt); return id; } }; return (Long) getHibernateTemplate().execute(hc); } protected List getSpreadsheets(Long gradebookId, Session session) throws HibernateException { List spreadsheets = session.createQuery("from Spreadsheet as spt where spt.gradebook.id=? ") .setLong(0, gradebookId.longValue()).list(); return spreadsheets; } @Override public List getStudentAssignmentComments(final String studentId, final Long gradebookId) { return (List) getHibernateTemplate().execute(new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { List comments; comments = new ArrayList(); Query q = session.createQuery( "from Comment as c where c.studentId=:studentId and c.gradableObject.gradebook.id=:gradebookId"); q.setParameter("studentId", studentId); q.setParameter("gradebookId", gradebookId); List allComments = q.list(); for (Iterator iter = allComments.iterator(); iter.hasNext();) { Comment comment = (Comment) iter.next(); comments.add(comment); } return comments; } }); } @Override public boolean validateCategoryWeighting(Long gradebookId) { Gradebook gradebook = getGradebook(gradebookId); if (gradebook.getCategory_type() != GradebookService.CATEGORY_TYPE_WEIGHTED_CATEGORY) return true; List cats = getCategories(gradebookId); double weight = 0.0; for (int i = 0; i < cats.size(); i++) { Category cat = (Category) cats.get(i); if (cat != null) { weight += cat.getWeight().doubleValue(); } } if (Math.rint(weight) == 1) return true; else return false; } @Override public Set updateAssignmentGradeRecords(Assignment assignment, Collection gradeRecords, int grade_type) { if (grade_type == GradebookService.GRADE_TYPE_POINTS) return updateAssignmentGradeRecords(assignment, gradeRecords); else if (grade_type == GradebookService.GRADE_TYPE_PERCENTAGE) { Collection convertList = new ArrayList(); for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); Double doubleValue = calculateDoublePointForRecord(agr); if (agr != null && doubleValue != null) { agr.setPointsEarned(doubleValue); convertList.add(agr); } else if (agr != null) { agr.setPointsEarned(null); convertList.add(agr); } } return updateAssignmentGradeRecords(assignment, convertList); } else if (grade_type == GradebookService.GRADE_TYPE_LETTER) { Collection convertList = new ArrayList(); for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); Double doubleValue = calculateDoublePointForLetterGradeRecord(agr); if (agr != null && doubleValue != null) { agr.setPointsEarned(doubleValue); convertList.add(agr); } else if (agr != null) { agr.setPointsEarned(null); convertList.add(agr); } } return updateAssignmentGradeRecords(assignment, convertList); } else return null; } /** * Updates student grade records based upon the grade entry type - * grade will be converted appropriately before update * * @param studentUid * @param gradeRecords * @param grade_type * @return */ @Override public Set updateStudentGradeRecords(Collection gradeRecords, int grade_type, String studentId) { if (grade_type == GradebookService.GRADE_TYPE_POINTS) return updateStudentGradeRecords(gradeRecords, studentId); else if (grade_type == GradebookService.GRADE_TYPE_PERCENTAGE) { Collection convertList = new ArrayList(); for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); Double doubleValue = calculateDoublePointForRecord(agr); if (agr != null && doubleValue != null) { agr.setPointsEarned(doubleValue); convertList.add(agr); } else if (agr != null) { agr.setPointsEarned(null); convertList.add(agr); } } return updateStudentGradeRecords(convertList, studentId); } else if (grade_type == GradebookService.GRADE_TYPE_LETTER) { Collection convertList = new ArrayList(); for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); Double doubleValue = calculateDoublePointForLetterGrade(agr); if (agr != null && doubleValue != null) { agr.setPointsEarned(doubleValue); convertList.add(agr); } else if (agr != null) { agr.setPointsEarned(null); convertList.add(agr); } } return updateStudentGradeRecords(convertList, studentId); } else return null; } private Double calculateDoublePointForRecord(AssignmentGradeRecord gradeRecordFromCall) { Assignment assign = getAssignment(gradeRecordFromCall.getAssignment().getId()); if (gradeRecordFromCall.getPercentEarned() != null) { if (gradeRecordFromCall.getPercentEarned().doubleValue() / 100.0 < 0) { throw new IllegalArgumentException( "percent for record is less than 0 for percentage points in GradebookManagerHibernateImpl.calculateDoublePointForRecord"); } return new Double(assign.getPointsPossible().doubleValue() * (gradeRecordFromCall.getPercentEarned().doubleValue() / 100.0)); } else return null; } private Double calculateDoublePointForLetterGradeRecord(AssignmentGradeRecord gradeRecordFromCall) { Assignment assign = getAssignment(gradeRecordFromCall.getAssignment().getId()); Gradebook gradebook = getGradebook(assign.getGradebook().getId()); if (gradeRecordFromCall.getLetterEarned() != null) { LetterGradePercentMapping lgpm = getLetterGradePercentMapping(gradebook); if (lgpm != null && lgpm.getGradeMap() != null) { Double doublePercentage = lgpm.getValue(gradeRecordFromCall.getLetterEarned()); if (doublePercentage == null) { log.error("percentage for " + gradeRecordFromCall.getLetterEarned() + " is not found in letter grade mapping in GradebookManagerHibernateImpl.calculateDoublePointForLetterGradeRecord"); return null; } return calculateEquivalentPointValueForPercent(assign.getPointsPossible(), doublePercentage); } return null; } else return null; } private Double calculateDoublePointForLetterGrade(AssignmentGradeRecord gradeRecordFromCall) { Assignment assign = getAssignment(gradeRecordFromCall.getAssignment().getId()); if (gradeRecordFromCall.getLetterEarned() != null) { LetterGradePercentMapping lgpm = getLetterGradePercentMapping(assign.getGradebook()); if (lgpm != null && lgpm.getGradeMap() != null) { Double doublePercentage = lgpm.getValue(gradeRecordFromCall.getLetterEarned()); if (doublePercentage == null) { log.error("percentage for " + gradeRecordFromCall.getLetterEarned() + " is not found in letter grade mapping in GradebookManagerHibernateImpl.calculateDoublePointForLetterGrade"); return null; } return calculateEquivalentPointValueForPercent(assign.getPointsPossible(), doublePercentage); } return null; } else return null; } @Override public List getAssignmentGradeRecordsConverted(Assignment assignment, Collection studentUids) { List assignRecordsFromDB = getAssignmentGradeRecords(assignment, studentUids); Gradebook gradebook = getGradebook(assignment.getGradebook().getId()); if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_POINTS) return assignRecordsFromDB; else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { return convertPointsToPercentage(assignment, gradebook, assignRecordsFromDB); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { return convertPointsToLetterGrade(assignment, gradebook, assignRecordsFromDB); } return null; } private List convertPointsToPercentage(Assignment assignment, Gradebook gradebook, List assignRecordsFromDB) { Double pointPossible = assignment.getPointsPossible(); List percentageList = new ArrayList(); if (pointPossible.doubleValue() > 0) { for (int i = 0; i < assignRecordsFromDB.size(); i++) { AssignmentGradeRecord agr = (AssignmentGradeRecord) assignRecordsFromDB.get(i); if (agr != null) { agr.setDateRecorded(agr.getDateRecorded()); agr.setGraderId(agr.getGraderId()); } if (agr != null && agr.getPointsEarned() != null) { agr.setPercentEarned(calculateEquivalentPercent(pointPossible, agr.getPointsEarned())); percentageList.add(agr); } else if (agr != null) { agr.setPercentEarned(null); percentageList.add(agr); } } } return percentageList; } private List convertPointsToLetterGrade(Assignment assignment, Gradebook gradebook, List assignRecordsFromDB) { Double pointPossible = assignment.getPointsPossible(); if (pointPossible.doubleValue() > 0) { List letterGradeList = new ArrayList(); LetterGradePercentMapping lgpm = getLetterGradePercentMapping(assignment.getGradebook()); for (int i = 0; i < assignRecordsFromDB.size(); i++) { AssignmentGradeRecord agr = (AssignmentGradeRecord) assignRecordsFromDB.get(i); if (agr != null) { agr.setDateRecorded(agr.getDateRecorded()); agr.setGraderId(agr.getGraderId()); } if (agr != null && agr.getPointsEarned() != null) { String letterGrade = lgpm .getGrade(calculateEquivalentPercent(pointPossible, agr.getPointsEarned())); agr.setLetterEarned(letterGrade); letterGradeList.add(agr); } else if (agr != null) { agr.setLetterEarned(null); letterGradeList.add(agr); } } return letterGradeList; } return null; } @Override public List getAssignmentsCategoriesAndCourseGradeWithStats(Long gradebookId, String assignmentSort, boolean assignAscending, String categorySort, boolean categoryAscending) { List catAssignCGList = new ArrayList(); Set<String> allStudentUids = getAllStudentUids(getGradebookUid(gradebookId)); List<AssignmentGradeRecord> gradeRecords = getAllAssignmentGradeRecords(gradebookId, allStudentUids); if (assignmentSort == null) { assignmentSort = Assignment.DEFAULT_SORT; } List<Assignment> allAssignments = getAssignmentsWithStats(gradebookId, assignmentSort, assignAscending, gradeRecords); // this method also returns the course grade List categoriesPlusCG = getCategoriesWithStats(gradebookId, assignmentSort, assignAscending, categorySort, categoryAscending, gradeRecords, allAssignments); // we will add assignments, then categories, then course grade (which is included in cate list) if (allAssignments != null) { catAssignCGList.addAll(allAssignments); } if (categoriesPlusCG != null) { catAssignCGList.addAll(categoriesPlusCG); } return catAssignCGList; } /** * * @param gradebookId * @param assignmentSort * @param assignAscending * @param categorySort * @param categoryAscending * @param gradeRecs * @param assignmentsWithStats * @return a list of the Categories with stats populated plus the Course Grade. * this method is useful if you have already retrieved all grade recs and * all assignments with stats to avoid repeated calls */ private List getCategoriesWithStats(Long gradebookId, String assignmentSort, boolean assignAscending, String categorySort, boolean categoryAscending, List<AssignmentGradeRecord> gradeRecs, List<Assignment> assignmentsWithStats) { Set studentUids = getAllStudentUids(getGradebookUid(gradebookId)); return getCategoriesWithStats(gradebookId, assignmentSort, assignAscending, categorySort, categoryAscending, gradeRecs, assignmentsWithStats, studentUids); } private List getCategoriesWithStats(Long gradebookId, String assignmentSort, boolean assignAscending, String categorySort, boolean categoryAscending, List<AssignmentGradeRecord> gradeRecs, List<Assignment> assignmentsWithStats, Set studentUids) { List categories = getCategories(gradebookId); Map cateMap = new HashMap(); for (Iterator iter = assignmentsWithStats.iterator(); iter.hasNext();) { Assignment assign = (Assignment) iter.next(); if (assign != null) { // the assigns already have stats calculated //assign.calculateStatistics(gradeRecs); if (assign.getCategory() != null && cateMap.get(assign.getCategory().getId()) == null) { List assignList = new ArrayList(); assignList.add(assign); cateMap.put(assign.getCategory().getId(), assignList); } else { if (assign.getCategory() != null) { List assignList = (List) cateMap.get(assign.getCategory().getId()); assignList.add(assign); cateMap.put(assign.getCategory().getId(), assignList); } } } } for (Iterator iter = categories.iterator(); iter.hasNext();) { Category cate = (Category) iter.next(); if (cate != null && cateMap.get(cate.getId()) != null) { cate.calculateStatistics((List) cateMap.get(cate.getId())); cate.setAssignmentList((List) cateMap.get(cate.getId())); } } if (categorySort != null) sortCategories(categories, categorySort, categoryAscending); else sortCategories(categories, Category.SORT_BY_NAME, categoryAscending); CourseGrade courseGrade = getCourseGrade(gradebookId); Map gradeRecordMap = new HashMap(); addToGradeRecordMap(gradeRecordMap, gradeRecs); // List<CourseGradeRecord> courseGradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, studentUids, releasedAssignments, gradeRecordMap); List<CourseGradeRecord> courseGradeRecords = getPointsEarnedCourseGradeRecords(courseGrade, studentUids, assignmentsWithStats, gradeRecordMap); courseGrade.calculateStatistics(courseGradeRecords, studentUids.size()); categories.add(courseGrade); return categories; } @Override public List getCategoriesWithStats(Long gradebookId, String assignmentSort, boolean assignAscending, String categorySort, boolean categoryAscending) { return getCategoriesWithStats(gradebookId, assignmentSort, assignAscending, categorySort, categoryAscending, false); } @Override public List getCategoriesWithStats(Long gradebookId, String assignmentSort, boolean assignAscending, String categorySort, boolean categoryAscending, boolean includeDroppedScores) { Set studentUids = getAllStudentUids(getGradebookUid(gradebookId)); return getCategoriesWithStats(gradebookId, assignmentSort, assignAscending, categorySort, categoryAscending, includeDroppedScores, studentUids); } @Override public List getCategoriesWithStats(Long gradebookId, String assignmentSort, boolean assignAscending, String categorySort, boolean categoryAscending, boolean includeDroppedScores, Set studentUids) { List allAssignments; if (assignmentSort == null) { assignmentSort = Assignment.DEFAULT_SORT; } List gradeRecords = getAllAssignmentGradeRecords(gradebookId, studentUids); if (!includeDroppedScores) { applyDropScores(gradeRecords); } allAssignments = getAssignmentsWithStats(gradebookId, assignmentSort, assignAscending, gradeRecords); return getCategoriesWithStats(gradebookId, assignmentSort, assignAscending, categorySort, categoryAscending, gradeRecords, allAssignments, studentUids); } private void sortCategories(List categories, String sortBy, boolean ascending) { Comparator comp; if (Category.SORT_BY_NAME.equals(sortBy)) { comp = Category.nameComparator; } else if (Category.SORT_BY_AVERAGE_SCORE.equals(sortBy)) { comp = Category.averageScoreComparator; } else if (Category.SORT_BY_WEIGHT.equals(sortBy)) { comp = Category.weightComparator; } else { comp = Category.nameComparator; } Collections.sort(categories, comp); if (!ascending) { Collections.reverse(categories); } } @Override public List getAssignmentsWithNoCategory(final Long gradebookId, String assignmentSort, boolean assignAscending) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { List assignments = session.createQuery( "from Assignment as asn where asn.gradebook.id=? and asn.removed=false and asn.category is null") .setLong(0, gradebookId.longValue()).list(); return assignments; } }; List assignList = (List) getHibernateTemplate().execute(hc); if (assignmentSort != null) sortAssignments(assignList, assignmentSort, assignAscending); else sortAssignments(assignList, Assignment.DEFAULT_SORT, assignAscending); return assignList; } @Override public List getAssignmentsWithNoCategoryWithStats(Long gradebookId, String assignmentSort, boolean assignAscending) { Set studentUids = getAllStudentUids(getGradebookUid(gradebookId)); List assignments = getAssignmentsWithNoCategory(gradebookId, assignmentSort, assignAscending); List<AssignmentGradeRecord> gradeRecords = getAllAssignmentGradeRecords(gradebookId, studentUids); applyDropScores(gradeRecords); for (Iterator iter = assignments.iterator(); iter.hasNext();) { Assignment assignment = (Assignment) iter.next(); assignment.calculateStatistics(gradeRecords); } // AZ - fixing bug, sorts based on stats need to be resorted if (assignmentSort != null) { sortAssignments(assignments, assignmentSort, assignAscending); } else { sortAssignments(assignments, Assignment.DEFAULT_SORT, assignAscending); } return assignments; } @Override public void convertGradingEventsConverted(Assignment assign, GradingEvents events, List studentUids, int grade_type) { LetterGradePercentMapping lgpm = new LetterGradePercentMapping(); if (grade_type == GradebookService.GRADE_TYPE_LETTER) { lgpm = getLetterGradePercentMapping(assign.getGradebook()); } for (Iterator iter = studentUids.iterator(); iter.hasNext();) { List gradingEvents = events.getEvents((String) iter.next()); for (Iterator eventIter = gradingEvents.iterator(); eventIter.hasNext();) { GradingEvent ge = (GradingEvent) eventIter.next(); if (ge.getGrade() != null) { if (grade_type == GradebookService.GRADE_TYPE_PERCENTAGE) { ge.setGrade( calculateEquivalentPercent(assign.getPointsPossible(), new Double(ge.getGrade())) .toString()); } else if (grade_type == GradebookService.GRADE_TYPE_LETTER) { String letterGrade = null; if (lgpm != null) { letterGrade = lgpm.getGrade(calculateEquivalentPercent(assign.getPointsPossible(), new Double(ge.getGrade()))); } ge.setGrade(letterGrade); } } } } } @Override public void convertGradingEventsConvertedForStudent(Gradebook gradebook, Map gradableObjectEventListMap, int grade_type) { if (gradableObjectEventListMap == null || gradableObjectEventListMap.isEmpty()) { return; } LetterGradePercentMapping lgpm = new LetterGradePercentMapping(); if (grade_type == GradebookService.GRADE_TYPE_LETTER) { lgpm = getLetterGradePercentMapping(gradebook); } for (Iterator<Map.Entry<GradableObject, List>> goIter = gradableObjectEventListMap.entrySet() .iterator(); goIter.hasNext();) { Map.Entry<GradableObject, List> entry = goIter.next(); GradableObject go = entry.getKey(); if (go instanceof Assignment) { Assignment assign = (Assignment) go; Double pointsPossible = assign.getPointsPossible(); List eventList = (List) gradableObjectEventListMap.get(go); if (eventList != null && eventList.size() > 0) { for (Iterator eventIter = eventList.iterator(); eventIter.hasNext();) { GradingEvent ge = (GradingEvent) eventIter.next(); if (ge.getGrade() != null) { if (grade_type == GradebookService.GRADE_TYPE_PERCENTAGE) { ge.setGrade(calculateEquivalentPercent(pointsPossible, new Double(ge.getGrade())) .toString()); } else if (grade_type == GradebookService.GRADE_TYPE_LETTER) { String letterGrade = null; if (lgpm != null) { letterGrade = lgpm.getGrade( calculateEquivalentPercent(pointsPossible, new Double(ge.getGrade()))); } ge.setGrade(letterGrade); } } } } } } } @Override public boolean checkStuendsNotSubmitted(Gradebook gradebook) { Set studentUids = getAllStudentUids(getGradebookUid(gradebook.getId())); if (gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_NO_CATEGORY || gradebook.getCategory_type() == GradebookService.CATEGORY_TYPE_ONLY_CATEGORY) { List records = getAllAssignmentGradeRecords(gradebook.getId(), studentUids); List assigns = getAssignments(gradebook.getId(), Assignment.DEFAULT_SORT, true); List filteredAssigns = new ArrayList(); for (Iterator iter = assigns.iterator(); iter.hasNext();) { Assignment assignment = (Assignment) iter.next(); if (assignment.isCounted() && !assignment.getUngraded()) filteredAssigns.add(assignment); } List filteredRecords = new ArrayList(); for (Iterator iter = records.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); if (!agr.isCourseGradeRecord() && agr.getAssignment().isCounted() && !agr.getAssignment().getUngraded()) { if (agr.getPointsEarned() == null) return true; filteredRecords.add(agr); } } if (filteredRecords.size() < (filteredAssigns.size() * studentUids.size())) return true; return false; } else { List assigns = getAssignments(gradebook.getId(), Assignment.DEFAULT_SORT, true); List records = getAllAssignmentGradeRecords(gradebook.getId(), studentUids); Set filteredAssigns = new HashSet(); for (Iterator iter = assigns.iterator(); iter.hasNext();) { Assignment assign = (Assignment) iter.next(); if (assign != null && assign.isCounted() && !assign.getUngraded()) { if (assign.getCategory() != null && !assign.getCategory().isRemoved()) { filteredAssigns.add(assign.getId()); } } } List filteredRecords = new ArrayList(); for (Iterator iter = records.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); if (filteredAssigns.contains(agr.getAssignment().getId()) && !agr.isCourseGradeRecord()) { if (agr.getPointsEarned() == null) return true; filteredRecords.add(agr); } } if (filteredRecords.size() < filteredAssigns.size() * studentUids.size()) return true; return false; } } @Override public void fillInZeroForNullGradeRecords(Gradebook gradebook) { finalizeNullGradeRecords(gradebook); } @Override public void convertGradePointsForUpdatedTotalPoints(Gradebook gradebook, Assignment assignment, Double newTotal, List studentUids) { if (newTotal == null || assignment == null || gradebook == null) { throw new IllegalArgumentException("null values found in convertGradePointsForUpdatedTotalPoints."); } if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE && assignment.getPointsPossible() != null) { List records = getAssignmentGradeRecordsConverted(assignment, studentUids); for (Iterator iter = records.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); if (agr != null && agr.getPercentEarned() != null) { agr.setPointsEarned(calculateEquivalentPointValueForPercent(newTotal, agr.getPercentEarned())); } } updateAssignmentGradeRecords(assignment, records); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER && assignment.getPointsPossible() != null) { List records = getAssignmentGradeRecordsConverted(assignment, studentUids); LetterGradePercentMapping lgpm = getLetterGradePercentMapping(gradebook); for (Iterator iter = records.iterator(); iter.hasNext();) { AssignmentGradeRecord agr = (AssignmentGradeRecord) iter.next(); if (agr != null && agr.getLetterEarned() != null) { Double doublePercentage = lgpm.getValue(agr.getLetterEarned()); if (doublePercentage != null) { agr.setPointsEarned(calculateEquivalentPointValueForPercent(newTotal, doublePercentage)); } else { log.error("No equivalent % mapping for letter grade: " + agr.getLetterEarned() + " in method convertGradePointsForTotalUpdatedPoints"); } } } updateAssignmentGradeRecords(assignment, records); } } @Override protected Long saveNewAssignment(final Long gradebookId, final Long categoryId, final Assignment asn) throws ConflictingAssignmentNameException { Long result = super.saveNewAssignment(gradebookId, categoryId, asn); syncAssignment(asn.getName()); return result; } private void syncAssignment(String asnName) { /** synchronize from external application */ if (synchronizer != null && !synchronizer.isProjectSite()) { synchronizer.addLegacyAssignment(asnName); } } /** synchronize from external application */ public void setSynchronizer(GbSynchronizer synchronizer) { this.synchronizer = synchronizer; } @Override public void createAssignments(Long gradebookId, List assignList) throws MultipleAssignmentSavingException { List assignIds = new ArrayList(); try { for (Iterator iter = assignList.iterator(); iter.hasNext();) { Assignment assign = (Assignment) iter.next(); if (assign.getCategory() == null) { assignIds.add(createAssignment(gradebookId, assign.getName(), assign.getPointsPossible(), assign.getDueDate(), assign.isNotCounted(), assign.isReleased(), assign.isExtraCredit())); } else assignIds.add(createAssignmentForCategory(gradebookId, assign.getCategory().getId(), assign.getName(), assign.getPointsPossible(), assign.getDueDate(), assign.isNotCounted(), assign.isReleased(), assign.isExtraCredit())); } } catch (Exception e) { for (Iterator iter = assignIds.iterator(); iter.hasNext();) { removeAssignment((Long) iter.next()); } throw new MultipleAssignmentSavingException( "Errors occur while trying to saving multiple assignment items in createAssignments -- " + e.getMessage()); } } @Override public boolean checkValidName(final Long gradebookId, final Assignment assignment) { HibernateCallback hc = new HibernateCallback() { @Override public Object doInHibernate(Session session) throws HibernateException { Gradebook gb = (Gradebook) session.load(Gradebook.class, gradebookId); List conflictList = ((List) session.createQuery( "select go from GradableObject as go where go.name = ? and go.gradebook = ? and go.removed=false") .setString(0, assignment.getName()).setEntity(1, gb).list()); int numNameConflicts = conflictList.size(); return new Integer(numNameConflicts); } }; Integer conflicts = (Integer) getHibernateTemplate().execute(hc); if (conflicts.intValue() > 0) return false; else return true; } private void logAssignmentGradingEvent(AssignmentGradeRecord gradeRecord, String graderId, Assignment assignment, Session session) { if (gradeRecord == null || assignment == null) { throw new IllegalArgumentException( "null gradeRecord or assignment passed to logAssignmentGradingEvent"); } // Log the grading event, and keep track of the students with saved/updated grades // we need to log what the user entered depending on the grade entry type Gradebook gradebook = assignment.getGradebook(); String gradeEntry = null; if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_LETTER) { gradeEntry = gradeRecord.getLetterEarned(); } else if (gradebook.getGrade_type() == GradebookService.GRADE_TYPE_PERCENTAGE) { if (gradeRecord.getPercentEarned() != null) gradeEntry = gradeRecord.getPercentEarned().toString(); } else { if (gradeRecord.getPointsEarned() != null) gradeEntry = gradeRecord.getPointsEarned().toString(); } session.save(new GradingEvent(assignment, graderId, gradeRecord.getStudentId(), gradeEntry)); } }