0001: /**********************************************************************************
0002: *
0003: * $Id: GradebookManagerHibernateImpl.java 21205 2007-02-09 20:00:15Z ray@media.berkeley.edu $
0004: *
0005: ***********************************************************************************
0006: *
0007: * Copyright (c) 2005, 2006 The Regents of the University of California, The MIT Corporation
0008: *
0009: * Licensed under the Educational Community License, Version 1.0 (the "License");
0010: * you may not use this file except in compliance with the License.
0011: * You may obtain a copy of the License at
0012: *
0013: * http://www.opensource.org/licenses/ecl1.php
0014: *
0015: * Unless required by applicable law or agreed to in writing, software
0016: * distributed under the License is distributed on an "AS IS" BASIS,
0017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0018: * See the License for the specific language governing permissions and
0019: * limitations under the License.
0020: *
0021: **********************************************************************************/package org.sakaiproject.tool.gradebook.business.impl;
0022:
0023: import java.sql.SQLException;
0024: import java.util.ArrayList;
0025: import java.util.Collection;
0026: import java.util.Collections;
0027: import java.util.Comparator;
0028: import java.util.Date;
0029: import java.util.HashMap;
0030: import java.util.HashSet;
0031: import java.util.Iterator;
0032: import java.util.List;
0033: import java.util.Map;
0034: import java.util.Set;
0035:
0036: import org.apache.commons.logging.Log;
0037: import org.apache.commons.logging.LogFactory;
0038: import org.hibernate.Hibernate;
0039: import org.hibernate.HibernateException;
0040: import org.hibernate.Query;
0041: import org.hibernate.Session;
0042: import org.hibernate.StaleObjectStateException;
0043: import org.hibernate.TransientObjectException;
0044: import org.sakaiproject.component.gradebook.BaseHibernateManager;
0045: import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException;
0046: import org.sakaiproject.service.gradebook.shared.ConflictingSpreadsheetNameException;
0047: import org.sakaiproject.service.gradebook.shared.StaleObjectModificationException;
0048: import org.sakaiproject.tool.gradebook.AbstractGradeRecord;
0049: import org.sakaiproject.tool.gradebook.Assignment;
0050: import org.sakaiproject.tool.gradebook.AssignmentGradeRecord;
0051: import org.sakaiproject.tool.gradebook.Comment;
0052: import org.sakaiproject.tool.gradebook.CourseGrade;
0053: import org.sakaiproject.tool.gradebook.CourseGradeRecord;
0054: import org.sakaiproject.tool.gradebook.GradableObject;
0055: import org.sakaiproject.tool.gradebook.Gradebook;
0056: import org.sakaiproject.tool.gradebook.GradingEvent;
0057: import org.sakaiproject.tool.gradebook.GradingEvents;
0058: import org.sakaiproject.tool.gradebook.Spreadsheet;
0059: import org.sakaiproject.tool.gradebook.business.GradebookManager;
0060: import org.springframework.dao.DataIntegrityViolationException;
0061: import org.springframework.orm.hibernate3.HibernateCallback;
0062: import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
0063:
0064: /**
0065: * Manages Gradebook persistence via hibernate.
0066: */
0067: public class GradebookManagerHibernateImpl extends BaseHibernateManager
0068: implements GradebookManager {
0069:
0070: private static final Log log = LogFactory
0071: .getLog(GradebookManagerHibernateImpl.class);
0072:
0073: // Special logger for data contention analysis.
0074: private static final Log logData = LogFactory
0075: .getLog(GradebookManagerHibernateImpl.class.getName()
0076: + ".GB_DATA");
0077:
0078: public void removeAssignment(final Long assignmentId)
0079: throws StaleObjectModificationException {
0080: HibernateCallback hc = new HibernateCallback() {
0081: public Object doInHibernate(Session session)
0082: throws HibernateException {
0083: Assignment asn = (Assignment) session.load(
0084: Assignment.class, assignmentId);
0085: Gradebook gradebook = asn.getGradebook();
0086: asn.setRemoved(true);
0087: session.update(asn);
0088: if (log.isInfoEnabled())
0089: log.info("Assignment " + asn.getName()
0090: + " has been removed from " + gradebook);
0091: return null;
0092: }
0093: };
0094: getHibernateTemplate().execute(hc);
0095: }
0096:
0097: public Gradebook getGradebook(Long id) {
0098: return (Gradebook) getHibernateTemplate().load(Gradebook.class,
0099: id);
0100: }
0101:
0102: public List getAssignmentGradeRecords(final Assignment assignment,
0103: final Collection studentUids) {
0104: HibernateCallback hc = new HibernateCallback() {
0105: public Object doInHibernate(Session session)
0106: throws HibernateException {
0107: if (studentUids == null || studentUids.size() == 0) {
0108: if (log.isInfoEnabled())
0109: log
0110: .info("Returning no grade records for an empty collection of student UIDs");
0111: return new ArrayList();
0112: } else if (assignment.isRemoved()) {
0113: return new ArrayList();
0114: }
0115:
0116: Query q = session
0117: .createQuery("from AssignmentGradeRecord as agr where agr.gradableObject.id=:gradableObjectId order by agr.pointsEarned");
0118: q.setLong("gradableObjectId", assignment.getId()
0119: .longValue());
0120: List records = filterGradeRecordsByStudents(q.list(),
0121: studentUids);
0122: return records;
0123: }
0124: };
0125: return (List) getHibernateTemplate().execute(hc);
0126: }
0127:
0128: public List getPointsEarnedCourseGradeRecords(
0129: final CourseGrade courseGrade, final Collection studentUids) {
0130: HibernateCallback hc = new HibernateCallback() {
0131: public Object doInHibernate(Session session)
0132: throws HibernateException {
0133: if (studentUids == null || studentUids.size() == 0) {
0134: if (log.isInfoEnabled())
0135: log
0136: .info("Returning no grade records for an empty collection of student UIDs");
0137: return new ArrayList();
0138: }
0139:
0140: Query q = session
0141: .createQuery("from CourseGradeRecord as cgr where cgr.gradableObject.id=:gradableObjectId");
0142: q.setLong("gradableObjectId", courseGrade.getId()
0143: .longValue());
0144: List records = filterAndPopulateCourseGradeRecordsByStudents(
0145: courseGrade, q.list(), studentUids);
0146:
0147: Long gradebookId = courseGrade.getGradebook().getId();
0148: double totalPointsPossible = getTotalPointsInternal(
0149: gradebookId, session);
0150: if (log.isDebugEnabled())
0151: log.debug("Total points = " + totalPointsPossible);
0152:
0153: for (Iterator iter = records.iterator(); iter.hasNext();) {
0154: CourseGradeRecord cgr = (CourseGradeRecord) iter
0155: .next();
0156: double totalPointsEarned = getTotalPointsEarnedInternal(
0157: gradebookId, cgr.getStudentId(), session);
0158: cgr.initNonpersistentFields(totalPointsPossible,
0159: totalPointsEarned);
0160: if (log.isDebugEnabled())
0161: log.debug("Points earned = "
0162: + cgr.getPointsEarned());
0163: }
0164:
0165: return records;
0166: }
0167: };
0168: return (List) getHibernateTemplate().execute(hc);
0169: }
0170:
0171: public List getPointsEarnedCourseGradeRecordsWithStats(
0172: final CourseGrade courseGrade, final Collection studentUids) {
0173: // Get good class-wide statistics by including all students, whether
0174: // the caller is specifically interested in their grade records or not.
0175: Long gradebookId = courseGrade.getGradebook().getId();
0176: Set allStudentUids = getAllStudentUids(getGradebookUid(gradebookId));
0177: List courseGradeRecords = getPointsEarnedCourseGradeRecords(
0178: courseGrade, allStudentUids);
0179: courseGrade.calculateStatistics(courseGradeRecords,
0180: allStudentUids.size());
0181:
0182: // Filter out the grade records which weren't specified.
0183: courseGradeRecords = filterGradeRecordsByStudents(
0184: courseGradeRecords, studentUids);
0185:
0186: return courseGradeRecords;
0187: }
0188:
0189: public void addToGradeRecordMap(Map gradeRecordMap,
0190: List gradeRecords) {
0191: for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) {
0192: AbstractGradeRecord gradeRecord = (AbstractGradeRecord) iter
0193: .next();
0194: String studentUid = gradeRecord.getStudentId();
0195: Map studentMap = (Map) gradeRecordMap.get(studentUid);
0196: if (studentMap == null) {
0197: studentMap = new HashMap();
0198: gradeRecordMap.put(studentUid, studentMap);
0199: }
0200: studentMap.put(gradeRecord.getGradableObject().getId(),
0201: gradeRecord);
0202: }
0203: }
0204:
0205: public List getPointsEarnedCourseGradeRecords(
0206: final CourseGrade courseGrade,
0207: final Collection studentUids, final Collection assignments,
0208: final Map gradeRecordMap) {
0209: HibernateCallback hc = new HibernateCallback() {
0210: public Object doInHibernate(Session session)
0211: throws HibernateException {
0212: if (studentUids == null || studentUids.size() == 0) {
0213: if (log.isInfoEnabled())
0214: log
0215: .info("Returning no grade records for an empty collection of student UIDs");
0216: return new ArrayList();
0217: }
0218:
0219: Query q = session
0220: .createQuery("from CourseGradeRecord as cgr where cgr.gradableObject.id=:gradableObjectId");
0221: q.setLong("gradableObjectId", courseGrade.getId()
0222: .longValue());
0223: List records = filterAndPopulateCourseGradeRecordsByStudents(
0224: courseGrade, q.list(), studentUids);
0225:
0226: Set assignmentsNotCounted = new HashSet();
0227: double totalPointsPossible = 0;
0228: for (Iterator iter = assignments.iterator(); iter
0229: .hasNext();) {
0230: Assignment assignment = (Assignment) iter.next();
0231: if (assignment.isCounted()) {
0232: totalPointsPossible += assignment
0233: .getPointsPossible();
0234: } else {
0235: assignmentsNotCounted.add(assignment.getId());
0236: }
0237: }
0238: if (log.isDebugEnabled())
0239: log.debug("Total points = " + totalPointsPossible);
0240:
0241: for (Iterator iter = records.iterator(); iter.hasNext();) {
0242: CourseGradeRecord cgr = (CourseGradeRecord) iter
0243: .next();
0244: double totalPointsEarned = 0;
0245: Map studentMap = (Map) gradeRecordMap.get(cgr
0246: .getStudentId());
0247: if (studentMap != null) {
0248: Collection studentGradeRecords = studentMap
0249: .values();
0250: for (Iterator gradeRecordIter = studentGradeRecords
0251: .iterator(); gradeRecordIter.hasNext();) {
0252: AssignmentGradeRecord agr = (AssignmentGradeRecord) gradeRecordIter
0253: .next();
0254: if (!assignmentsNotCounted.contains(agr
0255: .getGradableObject().getId())) {
0256: Double pointsEarned = agr
0257: .getPointsEarned();
0258: if (pointsEarned != null) {
0259: totalPointsEarned += pointsEarned
0260: .doubleValue();
0261: }
0262: }
0263: }
0264: }
0265: cgr.initNonpersistentFields(totalPointsPossible,
0266: totalPointsEarned);
0267: if (log.isDebugEnabled())
0268: log.debug("Points earned = "
0269: + cgr.getPointsEarned());
0270: }
0271:
0272: return records;
0273: }
0274: };
0275: return (List) getHibernateTemplate().execute(hc);
0276: }
0277:
0278: /**
0279: */
0280: public List getAllAssignmentGradeRecords(final Long gradebookId,
0281: final Collection studentUids) {
0282: HibernateCallback hc = new HibernateCallback() {
0283: public Object doInHibernate(Session session)
0284: throws HibernateException {
0285: if (studentUids.size() == 0) {
0286: // If there are no enrollments, no need to execute the query.
0287: if (log.isInfoEnabled())
0288: log
0289: .info("No enrollments were specified. Returning an empty List of grade records");
0290: return new ArrayList();
0291: } else {
0292: Query q = session
0293: .createQuery("from AssignmentGradeRecord as agr where agr.gradableObject.removed=false and "
0294: + "agr.gradableObject.gradebook.id=:gradebookId order by agr.pointsEarned");
0295: q.setLong("gradebookId", gradebookId.longValue());
0296: return filterGradeRecordsByStudents(q.list(),
0297: studentUids);
0298: }
0299: }
0300: };
0301: return (List) getHibernateTemplate().execute(hc);
0302: }
0303:
0304: /**
0305: * @return Returns set of student UIDs who were given scores higher than the assignment's value.
0306: */
0307: public Set updateAssignmentGradeRecords(
0308: final Assignment assignment,
0309: final Collection gradeRecordsFromCall)
0310: throws StaleObjectModificationException {
0311: // If no grade records are sent, don't bother doing anything with the db
0312: if (gradeRecordsFromCall.size() == 0) {
0313: log
0314: .debug("updateAssignmentGradeRecords called for zero grade records");
0315: return new HashSet();
0316: }
0317:
0318: if (logData.isDebugEnabled())
0319: logData.debug("BEGIN: Update "
0320: + gradeRecordsFromCall.size()
0321: + " scores for gradebook="
0322: + assignment.getGradebook().getUid()
0323: + ", assignment=" + assignment.getName());
0324:
0325: HibernateCallback hc = new HibernateCallback() {
0326: public Object doInHibernate(Session session)
0327: throws HibernateException {
0328: Date now = new Date();
0329: String graderId = authn.getUserUid();
0330:
0331: Set studentsWithUpdatedAssignmentGradeRecords = new HashSet();
0332: Set studentsWithExcessiveScores = new HashSet();
0333:
0334: for (Iterator iter = gradeRecordsFromCall.iterator(); iter
0335: .hasNext();) {
0336: AssignmentGradeRecord gradeRecordFromCall = (AssignmentGradeRecord) iter
0337: .next();
0338: gradeRecordFromCall.setGraderId(graderId);
0339: gradeRecordFromCall.setDateRecorded(now);
0340: try {
0341: session.saveOrUpdate(gradeRecordFromCall);
0342: } catch (TransientObjectException e) {
0343: // It's possible that a previously unscored student
0344: // was scored behind the current user's back before
0345: // the user saved the new score. This translates
0346: // that case into an optimistic locking failure.
0347: if (log.isInfoEnabled())
0348: log
0349: .info("An optimistic locking failure occurred while attempting to add a new assignment grade record");
0350: throw new StaleObjectModificationException(e);
0351: }
0352:
0353: // Check for excessive (AKA extra credit) scoring.
0354: if (gradeRecordFromCall.getPointsEarned() != null
0355: && gradeRecordFromCall
0356: .getPointsEarned()
0357: .compareTo(
0358: assignment
0359: .getPointsPossible()) > 0) {
0360: studentsWithExcessiveScores
0361: .add(gradeRecordFromCall.getStudentId());
0362: }
0363:
0364: // Log the grading event, and keep track of the students with saved/updated grades
0365: session.save(new GradingEvent(assignment, graderId,
0366: gradeRecordFromCall.getStudentId(),
0367: gradeRecordFromCall.getPointsEarned()));
0368: studentsWithUpdatedAssignmentGradeRecords
0369: .add(gradeRecordFromCall.getStudentId());
0370: }
0371: if (logData.isDebugEnabled())
0372: logData.debug("Updated "
0373: + studentsWithUpdatedAssignmentGradeRecords
0374: .size()
0375: + " assignment score records");
0376:
0377: return studentsWithExcessiveScores;
0378: }
0379: };
0380:
0381: Set studentsWithExcessiveScores = (Set) getHibernateTemplate()
0382: .execute(hc);
0383: if (logData.isDebugEnabled())
0384: logData.debug("END: Update " + gradeRecordsFromCall.size()
0385: + " scores for gradebook="
0386: + assignment.getGradebook().getUid()
0387: + ", assignment=" + assignment.getName());
0388: return studentsWithExcessiveScores;
0389: }
0390:
0391: public Set updateAssignmentGradesAndComments(Assignment assignment,
0392: Collection gradeRecords, Collection comments)
0393: throws StaleObjectModificationException {
0394: Set studentsWithExcessiveScores = updateAssignmentGradeRecords(
0395: assignment, gradeRecords);
0396:
0397: updateComments(comments);
0398:
0399: return studentsWithExcessiveScores;
0400: }
0401:
0402: public void updateComments(final Collection comments)
0403: throws StaleObjectModificationException {
0404: final Date now = new Date();
0405: final String graderId = authn.getUserUid();
0406:
0407: // Unlike the complex grade update logic, this method assumes that
0408: // the client has done the work of filtering out any unchanged records
0409: // and isn't interested in throwing an optimistic locking exception for untouched records
0410: // which were changed by other sessions.
0411: HibernateCallback hc = new HibernateCallback() {
0412: public Object doInHibernate(Session session)
0413: throws HibernateException {
0414: for (Iterator iter = comments.iterator(); iter
0415: .hasNext();) {
0416: Comment comment = (Comment) iter.next();
0417: comment.setGraderId(graderId);
0418: comment.setDateRecorded(now);
0419: session.saveOrUpdate(comment);
0420: }
0421: return null;
0422: }
0423: };
0424: try {
0425: getHibernateTemplate().execute(hc);
0426: } catch (DataIntegrityViolationException e) {
0427: // If a student hasn't yet received a comment for this
0428: // assignment, and two graders try to save a new comment record at the
0429: // same time, the database should report a unique constraint violation.
0430: // Since that's similar to the conflict between two graders who
0431: // are trying to update an existing comment record at the same
0432: // same time, this method translates the exception into an
0433: // optimistic locking failure.
0434: if (log.isInfoEnabled())
0435: log
0436: .info("An optimistic locking failure occurred while attempting to update comments");
0437: throw new StaleObjectModificationException(e);
0438: }
0439: }
0440:
0441: /**
0442: */
0443: public void updateCourseGradeRecords(final CourseGrade courseGrade,
0444: final Collection gradeRecordsFromCall)
0445: throws StaleObjectModificationException {
0446:
0447: if (gradeRecordsFromCall.size() == 0) {
0448: log
0449: .debug("updateCourseGradeRecords called with zero grade records to update");
0450: return;
0451: }
0452:
0453: if (logData.isDebugEnabled())
0454: logData.debug("BEGIN: Update "
0455: + gradeRecordsFromCall.size()
0456: + " course grades for gradebook="
0457: + courseGrade.getGradebook().getUid());
0458:
0459: HibernateCallback hc = new HibernateCallback() {
0460: public Object doInHibernate(Session session)
0461: throws HibernateException {
0462: for (Iterator iter = gradeRecordsFromCall.iterator(); iter
0463: .hasNext();) {
0464: session.evict(iter.next());
0465: }
0466:
0467: Date now = new Date();
0468: String graderId = authn.getUserUid();
0469: int numberOfUpdatedGrades = 0;
0470:
0471: for (Iterator iter = gradeRecordsFromCall.iterator(); iter
0472: .hasNext();) {
0473: // The modified course grade record
0474: CourseGradeRecord gradeRecordFromCall = (CourseGradeRecord) iter
0475: .next();
0476: gradeRecordFromCall.setGraderId(graderId);
0477: gradeRecordFromCall.setDateRecorded(now);
0478: try {
0479: session.saveOrUpdate(gradeRecordFromCall);
0480: session.flush();
0481: } catch (StaleObjectStateException sose) {
0482: if (log.isInfoEnabled())
0483: log
0484: .info("An optimistic locking failure occurred while attempting to update course grade records");
0485: throw new StaleObjectModificationException(sose);
0486: }
0487:
0488: // Log the grading event
0489: session.save(new GradingEvent(courseGrade,
0490: graderId, gradeRecordFromCall
0491: .getStudentId(),
0492: gradeRecordFromCall.getEnteredGrade()));
0493:
0494: numberOfUpdatedGrades++;
0495: }
0496: if (logData.isDebugEnabled())
0497: logData.debug("Changed " + numberOfUpdatedGrades
0498: + " course grades for gradebook="
0499: + courseGrade.getGradebook().getUid());
0500: return null;
0501: }
0502: };
0503: try {
0504: getHibernateTemplate().execute(hc);
0505: if (logData.isDebugEnabled())
0506: logData.debug("END: Update "
0507: + gradeRecordsFromCall.size()
0508: + " course grades for gradebook="
0509: + courseGrade.getGradebook().getUid());
0510: } catch (DataIntegrityViolationException e) {
0511: // It's possible that a previously ungraded student
0512: // was graded behind the current user's back before
0513: // the user saved the new grade. This translates
0514: // that case into an optimistic locking failure.
0515: if (log.isInfoEnabled())
0516: log
0517: .info("An optimistic locking failure occurred while attempting to update course grade records");
0518: throw new StaleObjectModificationException(e);
0519: }
0520: }
0521:
0522: public boolean isEnteredAssignmentScores(final Long assignmentId) {
0523: HibernateCallback hc = new HibernateCallback() {
0524: public Object doInHibernate(Session session)
0525: throws HibernateException {
0526: Integer total = (Integer) session
0527: .createQuery(
0528: "select count(agr) from AssignmentGradeRecord as agr where agr.gradableObject.id=? and agr.pointsEarned is not null")
0529: .setLong(0, assignmentId.longValue())
0530: .uniqueResult();
0531: if (log.isInfoEnabled())
0532: log.info("assignment " + assignmentId + " has "
0533: + total + " entered scores");
0534: return total;
0535: }
0536: };
0537: return ((Integer) getHibernateTemplate().execute(hc))
0538: .intValue() > 0;
0539: }
0540:
0541: /**
0542: */
0543: public List getStudentGradeRecords(final Long gradebookId,
0544: final String studentId) {
0545: HibernateCallback hc = new HibernateCallback() {
0546: public Object doInHibernate(Session session)
0547: throws HibernateException {
0548: return session
0549: .createQuery(
0550: "from AssignmentGradeRecord as agr where agr.studentId=? and agr.gradableObject.removed=false and agr.gradableObject.gradebook.id=?")
0551: .setString(0, studentId).setLong(1,
0552: gradebookId.longValue()).list();
0553: }
0554: };
0555: return (List) getHibernateTemplate().execute(hc);
0556: }
0557:
0558: private double getTotalPointsEarnedInternal(final Long gradebookId,
0559: final String studentId, final Session session) {
0560: double totalPointsEarned = 0;
0561: Iterator scoresIter = session
0562: .createQuery(
0563: "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")
0564: .setParameter("student", studentId).setParameter(
0565: "gbid", gradebookId).list().iterator();
0566: while (scoresIter.hasNext()) {
0567: Double pointsEarned = (Double) scoresIter.next();
0568: if (pointsEarned != null) {
0569: totalPointsEarned += pointsEarned.doubleValue();
0570: }
0571: }
0572: if (log.isDebugEnabled())
0573: log.debug("getTotalPointsEarnedInternal for studentId="
0574: + studentId + " returning " + totalPointsEarned);
0575: return totalPointsEarned;
0576: }
0577:
0578: public CourseGradeRecord getStudentCourseGradeRecord(
0579: final Gradebook gradebook, final String studentId) {
0580: if (logData.isDebugEnabled())
0581: logData
0582: .debug("About to read student course grade for gradebook="
0583: + gradebook.getUid());
0584: return (CourseGradeRecord) getHibernateTemplate().execute(
0585: new HibernateCallback() {
0586: public Object doInHibernate(Session session)
0587: throws HibernateException {
0588: CourseGradeRecord courseGradeRecord = getCourseGradeRecord(
0589: gradebook, studentId, session);
0590: if (courseGradeRecord == null) {
0591: courseGradeRecord = new CourseGradeRecord(
0592: getCourseGrade(gradebook.getId()),
0593: studentId);
0594: }
0595:
0596: // Only take the hit of autocalculating the course grade if no explicit
0597: // grade has been entered.
0598: if (courseGradeRecord.getEnteredGrade() == null) {
0599: // TODO We could easily get everything we need in a single query by using an outer join if we
0600: // weren't mapping the different classes together into single sparsely populated
0601: // tables. When we finally break up the current mungings of Assignment with CourseGrade
0602: // and AssignmentGradeRecord with CourseGradeRecord, redo this section.
0603: double totalPointsPossible = getTotalPointsInternal(
0604: gradebook.getId(), session);
0605: double totalPointsEarned = getTotalPointsEarnedInternal(
0606: gradebook.getId(), studentId,
0607: session);
0608: courseGradeRecord.initNonpersistentFields(
0609: totalPointsPossible,
0610: totalPointsEarned);
0611: }
0612: return courseGradeRecord;
0613: }
0614: });
0615: }
0616:
0617: public GradingEvents getGradingEvents(
0618: final GradableObject gradableObject,
0619: final Collection studentIds) {
0620:
0621: // Don't attempt to run the query if there are no enrollments
0622: if (studentIds == null || studentIds.size() == 0) {
0623: log
0624: .debug("No enrollments were specified. Returning an empty GradingEvents object");
0625: return new GradingEvents();
0626: }
0627:
0628: HibernateCallback hc = new HibernateCallback() {
0629: public Object doInHibernate(Session session)
0630: throws HibernateException, SQLException {
0631: List eventsList;
0632: if (studentIds.size() <= MAX_NUMBER_OF_SQL_PARAMETERS_IN_LIST) {
0633: Query q = session
0634: .createQuery("from GradingEvent as ge where ge.gradableObject=:go and ge.studentId in (:students)");
0635: q.setParameter("go", gradableObject, Hibernate
0636: .entity(GradableObject.class));
0637: q.setParameterList("students", studentIds);
0638: eventsList = q.list();
0639: } else {
0640: Query q = session
0641: .createQuery("from GradingEvent as ge where ge.gradableObject=:go");
0642: q.setParameter("go", gradableObject, Hibernate
0643: .entity(GradableObject.class));
0644: eventsList = new ArrayList();
0645: for (Iterator iter = q.list().iterator(); iter
0646: .hasNext();) {
0647: GradingEvent event = (GradingEvent) iter.next();
0648: if (studentIds.contains(event.getStudentId())) {
0649: eventsList.add(event);
0650: }
0651: }
0652: }
0653: return eventsList;
0654: }
0655: };
0656:
0657: List list = (List) getHibernateTemplate().execute(hc);
0658:
0659: GradingEvents events = new GradingEvents();
0660:
0661: for (Iterator iter = list.iterator(); iter.hasNext();) {
0662: GradingEvent event = (GradingEvent) iter.next();
0663: events.addEvent(event);
0664: }
0665: return events;
0666: }
0667:
0668: /**
0669: */
0670: public List getAssignments(final Long gradebookId,
0671: final String sortBy, final boolean ascending) {
0672: return (List) getHibernateTemplate().execute(
0673: new HibernateCallback() {
0674: public Object doInHibernate(Session session)
0675: throws HibernateException {
0676: List assignments = getAssignments(gradebookId,
0677: session);
0678: sortAssignments(assignments, sortBy, ascending);
0679: return assignments;
0680: }
0681: });
0682: }
0683:
0684: /**
0685: */
0686: public List getAssignmentsWithStats(final Long gradebookId,
0687: final String sortBy, final boolean ascending) {
0688: Set studentUids = getAllStudentUids(getGradebookUid(gradebookId));
0689: List assignments = getAssignments(gradebookId);
0690: List<AssignmentGradeRecord> gradeRecords = getAllAssignmentGradeRecords(
0691: gradebookId, studentUids);
0692: for (Iterator iter = assignments.iterator(); iter.hasNext();) {
0693: Assignment assignment = (Assignment) iter.next();
0694: assignment.calculateStatistics(gradeRecords);
0695: }
0696: sortAssignments(assignments, sortBy, ascending);
0697: return assignments;
0698: }
0699:
0700: public List getAssignmentsAndCourseGradeWithStats(
0701: final Long gradebookId, final String sortBy,
0702: final boolean ascending) {
0703: Set studentUids = getAllStudentUids(getGradebookUid(gradebookId));
0704: List assignments = getAssignments(gradebookId);
0705: CourseGrade courseGrade = getCourseGrade(gradebookId);
0706: Map gradeRecordMap = new HashMap();
0707: List<AssignmentGradeRecord> gradeRecords = getAllAssignmentGradeRecords(
0708: gradebookId, studentUids);
0709: addToGradeRecordMap(gradeRecordMap, gradeRecords);
0710:
0711: for (Iterator iter = assignments.iterator(); iter.hasNext();) {
0712: Assignment assignment = (Assignment) iter.next();
0713: assignment.calculateStatistics(gradeRecords);
0714: }
0715:
0716: List<CourseGradeRecord> courseGradeRecords = getPointsEarnedCourseGradeRecords(
0717: courseGrade, studentUids, assignments, gradeRecordMap);
0718: courseGrade.calculateStatistics(courseGradeRecords, studentUids
0719: .size());
0720:
0721: sortAssignments(assignments, sortBy, ascending);
0722:
0723: // Always put the Course Grade at the end.
0724: assignments.add(courseGrade);
0725:
0726: return assignments;
0727: }
0728:
0729: private List filterAndPopulateCourseGradeRecordsByStudents(
0730: CourseGrade courseGrade, Collection gradeRecords,
0731: Collection studentUids) {
0732: List filteredRecords = new ArrayList();
0733: Set missingStudents = new HashSet(studentUids);
0734: for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) {
0735: CourseGradeRecord cgr = (CourseGradeRecord) iter.next();
0736: if (studentUids.contains(cgr.getStudentId())) {
0737: filteredRecords.add(cgr);
0738: missingStudents.remove(cgr.getStudentId());
0739: }
0740: }
0741: for (Iterator iter = missingStudents.iterator(); iter.hasNext();) {
0742: String studentUid = (String) iter.next();
0743: CourseGradeRecord cgr = new CourseGradeRecord(courseGrade,
0744: studentUid);
0745: filteredRecords.add(cgr);
0746: }
0747: return filteredRecords;
0748: }
0749:
0750: /**
0751: * TODO Remove this method in favor of doing database sorting.
0752: *
0753: * @param assignments
0754: * @param sortBy
0755: * @param ascending
0756: */
0757: private void sortAssignments(List assignments, String sortBy,
0758: boolean ascending) {
0759: Comparator comp;
0760: if (Assignment.SORT_BY_NAME.equals(sortBy)) {
0761: comp = Assignment.nameComparator;
0762: } else if (Assignment.SORT_BY_MEAN.equals(sortBy)) {
0763: comp = Assignment.meanComparator;
0764: } else if (Assignment.SORT_BY_POINTS.equals(sortBy)) {
0765: comp = Assignment.pointsComparator;
0766: } else if (Assignment.releasedComparator.equals(sortBy)) {
0767: comp = Assignment.releasedComparator;
0768: } else {
0769: comp = Assignment.dateComparator;
0770: }
0771: Collections.sort(assignments, comp);
0772: if (!ascending) {
0773: Collections.reverse(assignments);
0774: }
0775: }
0776:
0777: /**
0778: */
0779: public List getAssignments(Long gradebookId) {
0780: return getAssignments(gradebookId, Assignment.DEFAULT_SORT,
0781: true);
0782: }
0783:
0784: /**
0785: */
0786: public Assignment getAssignment(Long assignmentId) {
0787: return (Assignment) getHibernateTemplate().load(
0788: Assignment.class, assignmentId);
0789: }
0790:
0791: /**
0792: */
0793: public Assignment getAssignmentWithStats(Long assignmentId) {
0794: Assignment assignment = getAssignment(assignmentId);
0795: Long gradebookId = assignment.getGradebook().getId();
0796: Set studentUids = getAllStudentUids(getGradebookUid(gradebookId));
0797: List<AssignmentGradeRecord> gradeRecords = getAssignmentGradeRecords(
0798: assignment, studentUids);
0799: assignment.calculateStatistics(gradeRecords);
0800: return assignment;
0801: }
0802:
0803: /**
0804: */
0805: public void updateAssignment(final Assignment assignment)
0806: throws ConflictingAssignmentNameException,
0807: StaleObjectModificationException {
0808: HibernateCallback hc = new HibernateCallback() {
0809: public Object doInHibernate(Session session)
0810: throws HibernateException {
0811: updateAssignment(assignment, session);
0812: return null;
0813: }
0814: };
0815: try {
0816: getHibernateTemplate().execute(hc);
0817: } catch (HibernateOptimisticLockingFailureException holfe) {
0818: if (log.isInfoEnabled())
0819: log
0820: .info("An optimistic locking failure occurred while attempting to update an assignment");
0821: throw new StaleObjectModificationException(holfe);
0822: }
0823: }
0824:
0825: /**
0826: * Gets the total number of points possible in a gradebook.
0827: */
0828: public double getTotalPoints(final Long gradebookId) {
0829: Double totalPoints = (Double) getHibernateTemplate().execute(
0830: new HibernateCallback() {
0831: public Object doInHibernate(Session session)
0832: throws HibernateException {
0833: return new Double(getTotalPointsInternal(
0834: gradebookId, session));
0835: }
0836: });
0837: return totalPoints.doubleValue();
0838: }
0839:
0840: private double getTotalPointsInternal(Long gradebookId,
0841: Session session) {
0842: double totalPointsPossible = 0;
0843: Iterator assignmentPointsIter = session
0844: .createQuery(
0845: "select asn.pointsPossible from Assignment asn where asn.gradebook.id=:gbid and asn.removed=false and asn.notCounted=false")
0846: .setParameter("gbid", gradebookId).list().iterator();
0847: while (assignmentPointsIter.hasNext()) {
0848: Double pointsPossible = (Double) assignmentPointsIter
0849: .next();
0850: totalPointsPossible += pointsPossible.doubleValue();
0851: }
0852: return totalPointsPossible;
0853: }
0854:
0855: public Gradebook getGradebookWithGradeMappings(final Long id) {
0856: return (Gradebook) getHibernateTemplate().execute(
0857: new HibernateCallback() {
0858: public Object doInHibernate(Session session)
0859: throws HibernateException {
0860: Gradebook gradebook = (Gradebook) session.load(
0861: Gradebook.class, id);
0862: Hibernate.initialize(gradebook
0863: .getGradeMappings());
0864: return gradebook;
0865: }
0866: });
0867: }
0868:
0869: /**
0870: *
0871: * @param spreadsheetId
0872: * @return
0873: */
0874: public Spreadsheet getSpreadsheet(final Long spreadsheetId) {
0875: return (Spreadsheet) getHibernateTemplate().load(
0876: Spreadsheet.class, spreadsheetId);
0877: }
0878:
0879: /**
0880: *
0881: * @param gradebookId
0882: * @return
0883: */
0884: public List getSpreadsheets(final Long gradebookId) {
0885: return (List) getHibernateTemplate().execute(
0886: new HibernateCallback() {
0887: public Object doInHibernate(Session session)
0888: throws HibernateException {
0889: List spreadsheets = getSpreadsheets(
0890: gradebookId, session);
0891: return spreadsheets;
0892: }
0893: });
0894: }
0895:
0896: /**
0897: *
0898: * @param spreadsheetId
0899: */
0900: public void removeSpreadsheet(final Long spreadsheetId)
0901: throws StaleObjectModificationException {
0902:
0903: HibernateCallback hc = new HibernateCallback() {
0904: public Object doInHibernate(Session session)
0905: throws HibernateException {
0906: Spreadsheet spt = (Spreadsheet) session.load(
0907: Spreadsheet.class, spreadsheetId);
0908: session.delete(spt);
0909: if (log.isInfoEnabled())
0910: log.info("Spreadsheet " + spt.getName()
0911: + " has been removed from gradebook");
0912:
0913: return null;
0914: }
0915: };
0916: getHibernateTemplate().execute(hc);
0917:
0918: }
0919:
0920: /**
0921: *
0922: * @param spreadsheet
0923: */
0924: public void updateSpreadsheet(final Spreadsheet spreadsheet)
0925: throws ConflictingAssignmentNameException,
0926: StaleObjectModificationException {
0927: HibernateCallback hc = new HibernateCallback() {
0928: public Object doInHibernate(Session session)
0929: throws HibernateException {
0930: // Ensure that we don't have the assignment in the session, since
0931: // we need to compare the existing one in the db to our edited assignment
0932: session.evict(spreadsheet);
0933:
0934: Spreadsheet sptFromDb = (Spreadsheet) session.load(
0935: Spreadsheet.class, spreadsheet.getId());
0936: int numNameConflicts = ((Integer) session
0937: .createQuery(
0938: "select count(spt) from Spreadsheet as spt where spt.name = ? and spt.gradebook = ? and spt.id != ?")
0939: .setString(0, spreadsheet.getName()).setEntity(
0940: 1, spreadsheet.getGradebook()).setLong(
0941: 2, spreadsheet.getId().longValue())
0942: .uniqueResult()).intValue();
0943: if (numNameConflicts > 0) {
0944: throw new ConflictingAssignmentNameException(
0945: "You can not save multiple spreadsheets in a gradebook with the same name");
0946: }
0947:
0948: session.evict(sptFromDb);
0949: session.update(spreadsheet);
0950:
0951: return null;
0952: }
0953: };
0954: try {
0955: getHibernateTemplate().execute(hc);
0956: } catch (HibernateOptimisticLockingFailureException holfe) {
0957: if (log.isInfoEnabled())
0958: log
0959: .info("An optimistic locking failure occurred while attempting to update a spreadsheet");
0960: throw new StaleObjectModificationException(holfe);
0961: }
0962: }
0963:
0964: public Long createSpreadsheet(final Long gradebookId,
0965: final String name, final String creator, Date dateCreated,
0966: final String content)
0967: throws ConflictingSpreadsheetNameException,
0968: StaleObjectModificationException {
0969:
0970: HibernateCallback hc = new HibernateCallback() {
0971: public Object doInHibernate(Session session)
0972: throws HibernateException {
0973: Gradebook gb = (Gradebook) session.load(
0974: Gradebook.class, gradebookId);
0975: int numNameConflicts = ((Integer) session
0976: .createQuery(
0977: "select count(spt) from Spreadsheet as spt where spt.name = ? and spt.gradebook = ? ")
0978: .setString(0, name).setEntity(1, gb)
0979: .uniqueResult()).intValue();
0980: if (numNameConflicts > 0) {
0981: throw new ConflictingSpreadsheetNameException(
0982: "You can not save multiple spreadsheets in a gradebook with the same name");
0983: }
0984:
0985: Spreadsheet spt = new Spreadsheet();
0986: spt.setGradebook(gb);
0987: spt.setName(name);
0988: spt.setCreator(creator);
0989: spt.setDateCreated(new Date());
0990: spt.setContent(content);
0991:
0992: // Save the new assignment
0993: Long id = (Long) session.save(spt);
0994: return id;
0995: }
0996: };
0997:
0998: return (Long) getHibernateTemplate().execute(hc);
0999:
1000: }
1001:
1002: protected List getSpreadsheets(Long gradebookId, Session session)
1003: throws HibernateException {
1004: List spreadsheets = session.createQuery(
1005: "from Spreadsheet as spt where spt.gradebook.id=? ")
1006: .setLong(0, gradebookId.longValue()).list();
1007: return spreadsheets;
1008: }
1009:
1010: public List getComments(final Assignment assignment,
1011: final Collection studentIds) {
1012: if (studentIds.isEmpty()) {
1013: return new ArrayList();
1014: }
1015: return (List) getHibernateTemplate().execute(
1016: new HibernateCallback() {
1017: public Object doInHibernate(Session session)
1018: throws HibernateException {
1019: List comments;
1020: if (studentIds.size() <= MAX_NUMBER_OF_SQL_PARAMETERS_IN_LIST) {
1021: Query q = session
1022: .createQuery("from Comment as c where c.gradableObject=:go and c.studentId in (:studentIds)");
1023: q.setParameter("go", assignment);
1024: q
1025: .setParameterList("studentIds",
1026: studentIds);
1027: comments = q.list();
1028: } else {
1029: comments = new ArrayList();
1030: Query q = session
1031: .createQuery("from Comment as c where c.gradableObject=:go");
1032: q.setParameter("go", assignment);
1033: List allComments = q.list();
1034: for (Iterator iter = allComments.iterator(); iter
1035: .hasNext();) {
1036: Comment comment = (Comment) iter.next();
1037: if (studentIds.contains(comment
1038: .getStudentId())) {
1039: comments.add(comment);
1040: }
1041: }
1042: }
1043: return comments;
1044: }
1045: });
1046: }
1047:
1048: public List getStudentAssignmentComments(final String studentId,
1049: final Long gradebookId) {
1050: return (List) getHibernateTemplate().execute(
1051: new HibernateCallback() {
1052: public Object doInHibernate(Session session)
1053: throws HibernateException {
1054: List comments;
1055: comments = new ArrayList();
1056: Query q = session
1057: .createQuery("from Comment as c where c.studentId=:studentId and c.gradableObject.gradebook.id=:gradebookId");
1058: q.setParameter("studentId", studentId);
1059: q.setParameter("gradebookId", gradebookId);
1060: List allComments = q.list();
1061: for (Iterator iter = allComments.iterator(); iter
1062: .hasNext();) {
1063: Comment comment = (Comment) iter.next();
1064: comments.add(comment);
1065: }
1066: return comments;
1067: }
1068: });
1069: }
1070: }
|