0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/sam/trunk/component/src/java/org/sakaiproject/tool/assessment/services/GradingService.java $
0003: * $Id: GradingService.java 9784 2006-05-22 19:33:28Z daisyf@stanford.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the"License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.tool.assessment.services;
0021:
0022: import java.util.ArrayList;
0023: import java.util.Collection;
0024: import java.util.Date;
0025: import java.util.HashMap;
0026: import java.util.HashSet;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.Set;
0030: import java.util.StringTokenizer;
0031: import java.util.regex.Pattern;
0032: import java.util.regex.Matcher;
0033:
0034: import org.apache.commons.logging.Log;
0035: import org.apache.commons.logging.LogFactory;
0036:
0037: import org.sakaiproject.service.gradebook.shared.GradebookService;
0038: import org.sakaiproject.spring.SpringBeanLocator;
0039: import org.sakaiproject.tool.assessment.data.dao.grading.AssessmentGradingData;
0040: import org.sakaiproject.tool.assessment.data.dao.grading.ItemGradingData;
0041: import org.sakaiproject.tool.assessment.data.dao.grading.MediaData;
0042: import org.sakaiproject.tool.assessment.data.ifc.assessment.AnswerIfc;
0043: import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc;
0044: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemDataIfc;
0045: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemMetaDataIfc;
0046: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemTextIfc;
0047: import org.sakaiproject.tool.assessment.data.ifc.assessment.PublishedAssessmentIfc;
0048: import org.sakaiproject.tool.assessment.data.ifc.grading.AssessmentGradingIfc;
0049: import org.sakaiproject.tool.assessment.data.ifc.grading.ItemGradingIfc;
0050: import org.sakaiproject.tool.assessment.data.ifc.grading.StudentGradingSummaryIfc;
0051: import org.sakaiproject.tool.assessment.data.ifc.shared.TypeIfc;
0052: import org.sakaiproject.tool.assessment.facade.GradebookFacade;
0053: import org.sakaiproject.tool.assessment.facade.TypeFacade;
0054: import org.sakaiproject.tool.assessment.facade.TypeFacadeQueriesAPI;
0055: import org.sakaiproject.tool.assessment.integration.context.IntegrationContextFactory;
0056: import org.sakaiproject.tool.assessment.integration.helper.ifc.GradebookServiceHelper;
0057:
0058: //import org.sakaiproject.tool.assessment.services.assessment.PublishedAssessmentService;
0059:
0060: /**
0061: * The GradingService calls the back end to get/store grading information.
0062: * It also calculates scores for autograded types.
0063: */
0064: public class GradingService {
0065: private static Log log = LogFactory.getLog(GradingService.class);
0066:
0067: /**
0068: * Get all scores for a published assessment from the back end.
0069: */
0070: public ArrayList getTotalScores(String publishedId, String which) {
0071: ArrayList results = null;
0072: try {
0073: results = new ArrayList(PersistenceService.getInstance()
0074: .getAssessmentGradingFacadeQueries()
0075: .getTotalScores(publishedId, which));
0076: } catch (Exception e) {
0077: e.printStackTrace();
0078: }
0079: return results;
0080: }
0081:
0082: /**
0083: * Get all submissions for a published assessment from the back end.
0084: */
0085: public List getAllSubmissions(String publishedId) {
0086: List results = null;
0087: try {
0088: results = PersistenceService.getInstance()
0089: .getAssessmentGradingFacadeQueries()
0090: .getAllSubmissions(publishedId);
0091: } catch (Exception e) {
0092: e.printStackTrace();
0093: }
0094: return results;
0095: }
0096:
0097: public ArrayList getHighestAssessmentGradingList(Long publishedId) {
0098: ArrayList results = null;
0099: try {
0100: results = new ArrayList(PersistenceService.getInstance()
0101: .getAssessmentGradingFacadeQueries()
0102: .getHighestAssessmentGradingList(publishedId));
0103: } catch (Exception e) {
0104: e.printStackTrace();
0105: }
0106: return results;
0107: }
0108:
0109: public List getHighestSubmittedAssessmentGradingList(
0110: Long publishedId) {
0111: ArrayList results = null;
0112: try {
0113: results = new ArrayList(PersistenceService.getInstance()
0114: .getAssessmentGradingFacadeQueries()
0115: .getHighestSubmittedAssessmentGradingList(
0116: publishedId));
0117: } catch (Exception e) {
0118: e.printStackTrace();
0119: }
0120: return results;
0121: }
0122:
0123: public ArrayList getLastAssessmentGradingList(Long publishedId) {
0124: ArrayList results = null;
0125: try {
0126: results = new ArrayList(PersistenceService.getInstance()
0127: .getAssessmentGradingFacadeQueries()
0128: .getLastAssessmentGradingList(publishedId));
0129: } catch (Exception e) {
0130: e.printStackTrace();
0131: }
0132: return results;
0133: }
0134:
0135: public List getLastSubmittedAssessmentGradingList(Long publishedId) {
0136: List results = null;
0137: try {
0138: results = PersistenceService.getInstance()
0139: .getAssessmentGradingFacadeQueries()
0140: .getLastSubmittedAssessmentGradingList(publishedId);
0141: } catch (Exception e) {
0142: e.printStackTrace();
0143: }
0144: return results;
0145: }
0146:
0147: public void saveTotalScores(ArrayList gdataList,
0148: PublishedAssessmentIfc pub) {
0149: //log.debug("**** GradingService: saveTotalScores");
0150: try {
0151: AssessmentGradingData gdata = null;
0152: if (gdataList.size() > 0)
0153: gdata = (AssessmentGradingData) gdataList.get(0);
0154: else
0155: return;
0156:
0157: Integer scoringType = getScoringType(pub);
0158: ArrayList oldList = getAssessmentGradingsByScoringType(
0159: scoringType, gdata.getPublishedAssessmentId());
0160: for (int i = 0; i < gdataList.size(); i++) {
0161: AssessmentGradingData ag = (AssessmentGradingData) gdataList
0162: .get(i);
0163: saveOrUpdateAssessmentGrading(ag);
0164: }
0165:
0166: // no need to notify gradebook if this submission is not for grade
0167: // we only want to notify GB when there are changes
0168: ArrayList newList = getAssessmentGradingsByScoringType(
0169: scoringType, gdata.getPublishedAssessmentId());
0170: ArrayList l = getListForGradebookNotification(newList,
0171: oldList);
0172:
0173: notifyGradebook(l, pub);
0174: //}
0175: } catch (GradebookServiceException ge) {
0176: ge.printStackTrace();
0177: throw ge;
0178: } catch (Exception e) {
0179: e.printStackTrace();
0180: throw new RuntimeException(e);
0181: }
0182:
0183: }
0184:
0185: private ArrayList getListForGradebookNotification(
0186: ArrayList newList, ArrayList oldList) {
0187: ArrayList l = new ArrayList();
0188: HashMap h = new HashMap();
0189: for (int i = 0; i < oldList.size(); i++) {
0190: AssessmentGradingData ag = (AssessmentGradingData) oldList
0191: .get(i);
0192: h.put(ag.getAssessmentGradingId(), ag);
0193: }
0194:
0195: for (int i = 0; i < newList.size(); i++) {
0196: AssessmentGradingData a = (AssessmentGradingData) newList
0197: .get(i);
0198: Object o = h.get(a.getAssessmentGradingId());
0199: if (o == null) { // this does not exist in old list, so include it for update
0200: l.add(a);
0201: } else { // if new is different from old, include it for update
0202: AssessmentGradingData b = (AssessmentGradingData) o;
0203: if ((a.getFinalScore() != null && b.getFinalScore() != null)
0204: && !a.getFinalScore().equals(b.getFinalScore()))
0205: l.add(a);
0206: }
0207: }
0208: return l;
0209: }
0210:
0211: private ArrayList getAssessmentGradingsByScoringType(
0212: Integer scoringType, Long publishedAssessmentId) {
0213: ArrayList l = new ArrayList();
0214: // get the list of highest score
0215: if ((scoringType).equals(EvaluationModelIfc.HIGHEST_SCORE)) {
0216: l = getHighestAssessmentGradingList(publishedAssessmentId);
0217: }
0218: // get the list of last score
0219: else {
0220: l = getLastAssessmentGradingList(publishedAssessmentId);
0221: }
0222: return l;
0223: }
0224:
0225: public Integer getScoringType(PublishedAssessmentIfc pub) {
0226: Integer scoringType = null;
0227: EvaluationModelIfc e = pub.getEvaluationModel();
0228: if (e != null) {
0229: scoringType = e.getScoringType();
0230: }
0231: return scoringType;
0232: }
0233:
0234: private boolean updateGradebook(AssessmentGradingIfc data,
0235: PublishedAssessmentIfc pub) {
0236: // no need to notify gradebook if this submission is not for grade
0237: boolean forGrade = (Boolean.TRUE).equals(data.getForGrade());
0238:
0239: boolean toGradebook = false;
0240: EvaluationModelIfc e = pub.getEvaluationModel();
0241: if (e != null) {
0242: String toGradebookString = e.getToGradeBook();
0243: toGradebook = toGradebookString
0244: .equals(EvaluationModelIfc.TO_DEFAULT_GRADEBOOK
0245: .toString());
0246: }
0247: return (forGrade && toGradebook);
0248: }
0249:
0250: private void notifyGradebook(ArrayList l, PublishedAssessmentIfc pub) {
0251: for (int i = 0; i < l.size(); i++) {
0252: notifyGradebook((AssessmentGradingData) l.get(i), pub);
0253: }
0254: }
0255:
0256: /**
0257: * Get the score information for each item from the assessment score.
0258: */
0259: public HashMap getItemScores(Long publishedId, Long itemId,
0260: String which) {
0261: try {
0262: return (HashMap) PersistenceService.getInstance()
0263: .getAssessmentGradingFacadeQueries().getItemScores(
0264: publishedId, itemId, which);
0265: } catch (Exception e) {
0266: e.printStackTrace();
0267: return new HashMap();
0268: }
0269: }
0270:
0271: /**
0272: * Get the last set of itemgradingdata for a student per assessment
0273: */
0274: public HashMap getLastItemGradingData(String publishedId,
0275: String agentId) {
0276: try {
0277: return (HashMap) PersistenceService.getInstance()
0278: .getAssessmentGradingFacadeQueries()
0279: .getLastItemGradingData(new Long(publishedId),
0280: agentId);
0281: } catch (Exception e) {
0282: e.printStackTrace();
0283: return new HashMap();
0284: }
0285: }
0286:
0287: /**
0288: * Get the grading data for a given submission
0289: */
0290: public HashMap getStudentGradingData(String assessmentGradingId) {
0291: try {
0292: return (HashMap) PersistenceService.getInstance()
0293: .getAssessmentGradingFacadeQueries()
0294: .getStudentGradingData(assessmentGradingId);
0295: } catch (Exception e) {
0296: e.printStackTrace();
0297: return new HashMap();
0298: }
0299: }
0300:
0301: /**
0302: * Get the last submission for a student per assessment
0303: */
0304: public HashMap getSubmitData(String publishedId, String agentId,
0305: Integer scoringoption) {
0306: try {
0307: return (HashMap) PersistenceService.getInstance()
0308: .getAssessmentGradingFacadeQueries().getSubmitData(
0309: new Long(publishedId), agentId,
0310: scoringoption);
0311: } catch (Exception e) {
0312: e.printStackTrace();
0313: return new HashMap();
0314: }
0315: }
0316:
0317: public String getTextForId(Long typeId) {
0318: TypeFacadeQueriesAPI typeFacadeQueries = PersistenceService
0319: .getInstance().getTypeFacadeQueries();
0320: TypeFacade type = typeFacadeQueries.getTypeFacadeById(typeId);
0321: return (type.getKeyword());
0322: }
0323:
0324: public int getSubmissionSizeOfPublishedAssessment(
0325: String publishedAssessmentId) {
0326: try {
0327: return PersistenceService.getInstance()
0328: .getAssessmentGradingFacadeQueries()
0329: .getSubmissionSizeOfPublishedAssessment(
0330: new Long(publishedAssessmentId));
0331: } catch (Exception e) {
0332: e.printStackTrace();
0333: return 0;
0334: }
0335: }
0336:
0337: public HashMap getSubmissionSizeOfAllPublishedAssessments() {
0338: return PersistenceService.getInstance()
0339: .getAssessmentGradingFacadeQueries()
0340: .getSubmissionSizeOfAllPublishedAssessments();
0341: }
0342:
0343: public Long saveMedia(byte[] media, String mimeType) {
0344: return PersistenceService.getInstance()
0345: .getAssessmentGradingFacadeQueries().saveMedia(media,
0346: mimeType);
0347: }
0348:
0349: public Long saveMedia(MediaData mediaData) {
0350: return PersistenceService.getInstance()
0351: .getAssessmentGradingFacadeQueries().saveMedia(
0352: mediaData);
0353: }
0354:
0355: public MediaData getMedia(String mediaId) {
0356: return PersistenceService.getInstance()
0357: .getAssessmentGradingFacadeQueries().getMedia(
0358: new Long(mediaId));
0359: }
0360:
0361: public ArrayList getMediaArray(String itemGradingId) {
0362: return PersistenceService.getInstance()
0363: .getAssessmentGradingFacadeQueries().getMediaArray(
0364: new Long(itemGradingId));
0365: }
0366:
0367: public ArrayList getMediaArray(ItemGradingData i) {
0368: return PersistenceService.getInstance()
0369: .getAssessmentGradingFacadeQueries().getMediaArray(i);
0370: }
0371:
0372: public List getMediaArray(String publishedId, String publishItemId,
0373: String which) {
0374: return PersistenceService.getInstance()
0375: .getAssessmentGradingFacadeQueries().getMediaArray(
0376: new Long(publishedId), new Long(publishItemId),
0377: which);
0378: }
0379:
0380: public ItemGradingData getLastItemGradingDataByAgent(
0381: String publishedItemId, String agentId) {
0382: try {
0383: return PersistenceService.getInstance()
0384: .getAssessmentGradingFacadeQueries()
0385: .getLastItemGradingDataByAgent(
0386: new Long(publishedItemId), agentId);
0387: } catch (Exception e) {
0388: e.printStackTrace();
0389: return null;
0390: }
0391: }
0392:
0393: public ItemGradingData getItemGradingData(
0394: String assessmentGradingId, String publishedItemId) {
0395: try {
0396: return PersistenceService.getInstance()
0397: .getAssessmentGradingFacadeQueries()
0398: .getItemGradingData(new Long(assessmentGradingId),
0399: new Long(publishedItemId));
0400: } catch (Exception e) {
0401: e.printStackTrace();
0402: return null;
0403: }
0404: }
0405:
0406: public AssessmentGradingData load(String assessmentGradingId) {
0407: try {
0408: return PersistenceService.getInstance()
0409: .getAssessmentGradingFacadeQueries().load(
0410: new Long(assessmentGradingId));
0411: } catch (Exception e) {
0412: log.error(e);
0413: throw new RuntimeException(e);
0414: }
0415: }
0416:
0417: public ItemGradingData getItemGrading(String itemGradingId) {
0418: try {
0419: return PersistenceService.getInstance()
0420: .getAssessmentGradingFacadeQueries()
0421: .getItemGrading(new Long(itemGradingId));
0422: } catch (Exception e) {
0423: log.error(e);
0424: throw new Error(e);
0425: }
0426: }
0427:
0428: public AssessmentGradingIfc getLastAssessmentGradingByAgentId(
0429: String publishedAssessmentId, String agentIdString) {
0430: try {
0431: return PersistenceService.getInstance()
0432: .getAssessmentGradingFacadeQueries()
0433: .getLastAssessmentGradingByAgentId(
0434: new Long(publishedAssessmentId),
0435: agentIdString);
0436: } catch (Exception e) {
0437: log.error(e);
0438: throw new RuntimeException(e);
0439: }
0440: }
0441:
0442: public AssessmentGradingData getLastSavedAssessmentGradingByAgentId(
0443: String publishedAssessmentId, String agentIdString) {
0444: try {
0445: return PersistenceService.getInstance()
0446: .getAssessmentGradingFacadeQueries()
0447: .getLastSavedAssessmentGradingByAgentId(
0448: new Long(publishedAssessmentId),
0449: agentIdString);
0450: } catch (Exception e) {
0451: log.error(e);
0452: throw new RuntimeException(e);
0453: }
0454: }
0455:
0456: public AssessmentGradingData getLastSubmittedAssessmentGradingByAgentId(
0457: String publishedAssessmentId, String agentIdString) {
0458: try {
0459: return PersistenceService.getInstance()
0460: .getAssessmentGradingFacadeQueries()
0461: .getLastSubmittedAssessmentGradingByAgentId(
0462: new Long(publishedAssessmentId),
0463: agentIdString);
0464: } catch (Exception e) {
0465: log.error(e);
0466: throw new RuntimeException(e);
0467: }
0468: }
0469:
0470: public void saveItemGrading(ItemGradingIfc item) {
0471: try {
0472: PersistenceService.getInstance()
0473: .getAssessmentGradingFacadeQueries()
0474: .saveItemGrading(item);
0475: } catch (Exception e) {
0476: e.printStackTrace();
0477: }
0478: }
0479:
0480: public void saveOrUpdateAssessmentGrading(
0481: AssessmentGradingIfc assessment) {
0482: try {
0483: /*
0484: // Comment out the whole IF section because the only thing we do here is to
0485: // update the itemGradingSet. However, this update is redundant as it will
0486: // be updated in saveOrUpdateAssessmentGrading(assessment).
0487: if (assessment.getAssessmentGradingId()!=null
0488: && assessment.getAssessmentGradingId().longValue()>0){
0489: //1. if assessmentGrading contain itemGrading, we want to insert/update itemGrading first
0490: Set itemGradingSet = assessment.getItemGradingSet();
0491: Iterator iter = itemGradingSet.iterator();
0492: while (iter.hasNext()) {
0493: ItemGradingData itemGradingData = (ItemGradingData) iter.next();
0494: log.debug("date = " + itemGradingData.getSubmittedDate());
0495: }
0496: // The following line seems redundant. I cannot see a reason why we need to save the itmeGradingSet
0497: // here and then again in following saveOrUpdateAssessmentGrading(assessment). Comment it out.
0498: //saveOrUpdateAll(itemGradingSet);
0499: }
0500: */
0501: // this will update itemGradingSet and assessmentGrading. May as well, otherwise I would have
0502: // to reload assessment again
0503: PersistenceService.getInstance()
0504: .getAssessmentGradingFacadeQueries()
0505: .saveOrUpdateAssessmentGrading(assessment);
0506: } catch (Exception e) {
0507: e.printStackTrace();
0508: }
0509:
0510: }
0511:
0512: // This API only touch SAM_ASSESSMENTGRADING_T. No data gets inserted/updated in SAM_ITEMGRADING_T
0513: public void saveOrUpdateAssessmentGradingOnly(
0514: AssessmentGradingIfc assessment) {
0515: Set origItemGradingSet = assessment.getItemGradingSet();
0516: HashSet h = new HashSet(origItemGradingSet);
0517:
0518: // Clear the itemGradingSet so no data gets inserted/updated in SAM_ITEMGRADING_T;
0519: origItemGradingSet.clear();
0520: int size = assessment.getItemGradingSet().size();
0521: log.debug("before persist to db: size = " + size);
0522: try {
0523: PersistenceService.getInstance()
0524: .getAssessmentGradingFacadeQueries()
0525: .saveOrUpdateAssessmentGrading(assessment);
0526: } catch (Exception e) {
0527: e.printStackTrace();
0528: } finally {
0529: // Restore the original itemGradingSet back
0530: assessment.setItemGradingSet(h);
0531: size = assessment.getItemGradingSet().size();
0532: log.debug("after persist to db: size = " + size);
0533: }
0534: }
0535:
0536: public List getAssessmentGradingIds(String publishedItemId) {
0537: try {
0538: return PersistenceService.getInstance()
0539: .getAssessmentGradingFacadeQueries()
0540: .getAssessmentGradingIds(new Long(publishedItemId));
0541: } catch (Exception e) {
0542: log.error(e);
0543: throw new RuntimeException(e);
0544: }
0545: }
0546:
0547: public AssessmentGradingIfc getHighestAssessmentGrading(
0548: String publishedAssessmentId, String agentId) {
0549: try {
0550: return PersistenceService.getInstance()
0551: .getAssessmentGradingFacadeQueries()
0552: .getHighestAssessmentGrading(
0553: new Long(publishedAssessmentId), agentId);
0554: } catch (Exception e) {
0555: log.error(e);
0556: throw new RuntimeException(e);
0557: }
0558: }
0559:
0560: public AssessmentGradingIfc getHighestSubmittedAssessmentGrading(
0561: String publishedAssessmentId, String agentId) {
0562: try {
0563: return PersistenceService.getInstance()
0564: .getAssessmentGradingFacadeQueries()
0565: .getHighestSubmittedAssessmentGrading(
0566: new Long(publishedAssessmentId), agentId);
0567: } catch (Exception e) {
0568: log.error(e);
0569: throw new RuntimeException(e);
0570: }
0571: }
0572:
0573: public Set getItemGradingSet(String assessmentGradingId) {
0574: try {
0575: return PersistenceService.getInstance()
0576: .getAssessmentGradingFacadeQueries()
0577: .getItemGradingSet(new Long(assessmentGradingId));
0578: } catch (Exception e) {
0579: log.error(e);
0580: throw new RuntimeException(e);
0581: }
0582: }
0583:
0584: public HashMap getAssessmentGradingByItemGradingId(
0585: String publishedAssessmentId) {
0586: try {
0587: return PersistenceService.getInstance()
0588: .getAssessmentGradingFacadeQueries()
0589: .getAssessmentGradingByItemGradingId(
0590: new Long(publishedAssessmentId));
0591: } catch (Exception e) {
0592: log.error(e);
0593: throw new RuntimeException(e);
0594: }
0595: }
0596:
0597: public void updateItemScore(ItemGradingData gdata,
0598: float scoreDifference, PublishedAssessmentIfc pub) {
0599: try {
0600: AssessmentGradingData adata = load(gdata
0601: .getAssessmentGradingId().toString());
0602: adata.setItemGradingSet(getItemGradingSet(adata
0603: .getAssessmentGradingId().toString()));
0604:
0605: Set itemGradingSet = adata.getItemGradingSet();
0606: Iterator iter = itemGradingSet.iterator();
0607: float totalAutoScore = 0;
0608: float totalOverrideScore = adata.getTotalOverrideScore()
0609: .floatValue();
0610: while (iter.hasNext()) {
0611: ItemGradingIfc i = (ItemGradingIfc) iter.next();
0612: if (i.getItemGradingId().equals(
0613: gdata.getItemGradingId())) {
0614: i.setAutoScore(gdata.getAutoScore());
0615: i.setComments(gdata.getComments());
0616: }
0617: if (i.getAutoScore() != null)
0618: totalAutoScore += i.getAutoScore().floatValue();
0619: }
0620:
0621: adata.setTotalAutoScore(new Float(totalAutoScore));
0622: adata.setFinalScore(new Float(totalAutoScore
0623: + totalOverrideScore));
0624: saveOrUpdateAssessmentGrading(adata);
0625: if (scoreDifference != 0) {
0626: notifyGradebookByScoringType(adata, pub);
0627: }
0628: } catch (GradebookServiceException ge) {
0629: ge.printStackTrace();
0630: throw ge;
0631: } catch (Exception e) {
0632: e.printStackTrace();
0633: throw new RuntimeException(e);
0634: }
0635: }
0636:
0637: /**
0638: * Assume this is a new item.
0639: */
0640: public void storeGrades(AssessmentGradingIfc data,
0641: PublishedAssessmentIfc pub, HashMap publishedItemHash,
0642: HashMap publishedItemTextHash, HashMap publishedAnswerHash) {
0643: log.debug("storeGrades: data.getSubmittedDate()"
0644: + data.getSubmittedDate());
0645: storeGrades(data, false, pub, publishedItemHash,
0646: publishedItemTextHash, publishedAnswerHash, true);
0647: }
0648:
0649: /**
0650: * Assume this is a new item.
0651: */
0652: public void storeGrades(AssessmentGradingIfc data,
0653: PublishedAssessmentIfc pub, HashMap publishedItemHash,
0654: HashMap publishedItemTextHash, HashMap publishedAnswerHash,
0655: boolean persistToDB) {
0656: log
0657: .debug("storeGrades (not persistToDB) : data.getSubmittedDate()"
0658: + data.getSubmittedDate());
0659: storeGrades(data, false, pub, publishedItemHash,
0660: publishedItemTextHash, publishedAnswerHash, false);
0661: }
0662:
0663: /**
0664: * This is the big, complicated mess where we take all the items in
0665: * an assessment, store the grading data, auto-grade it, and update
0666: * everything.
0667: *
0668: * If regrade is true, we just recalculate the graded score. If it's
0669: * false, we do everything from scratch.
0670: */
0671: public void storeGrades(AssessmentGradingIfc data, boolean regrade,
0672: PublishedAssessmentIfc pub, HashMap publishedItemHash,
0673: HashMap publishedItemTextHash, HashMap publishedAnswerHash,
0674: boolean persistToDB) throws GradebookServiceException {
0675: log.debug("****x1. regrade =" + regrade + " "
0676: + (new Date()).getTime());
0677: try {
0678: String agent = data.getAgentId();
0679:
0680: // Added persistToDB because if we don't save data to DB later, we shouldn't update the assessment
0681: // submittedDate either. The date should be sync in delivery bean and DB
0682: // This is for DeliveryBean.checkDataIntegrity()
0683: if (!regrade && persistToDB) {
0684: data.setSubmittedDate(new Date());
0685: setIsLate(data, pub);
0686: }
0687: // note that this itemGradingSet is a partial set of answer submitted. it contains only
0688: // newly submitted answers, updated answers and MCMR/FIB/FIN answers ('cos we need the old ones to
0689: // calculate scores for new ones)
0690: Set itemGradingSet = data.getItemGradingSet();
0691: if (itemGradingSet == null)
0692: itemGradingSet = new HashSet();
0693: log.debug("****itemGrading size=" + itemGradingSet.size());
0694: Iterator iter = itemGradingSet.iterator();
0695:
0696: // fibAnswersMap contains a map of HashSet of answers for a FIB item,
0697: // key =itemid, value= HashSet of answers for each item.
0698: // This is used to keep track of answers we have already used for
0699: // mutually exclusive multiple answer type of FIB, such as
0700: // The flag of the US is {red|white|blue},{red|white|blue}, and {red|white|blue}.
0701: // so if the first blank has an answer 'red', the 'red' answer should
0702: // not be included in the answers for the other mutually exclusive blanks.
0703: HashMap fibAnswersMap = new HashMap();
0704:
0705: //change algorithm based on each question (SAK-1930 & IM271559) -cwen
0706: HashMap totalItems = new HashMap();
0707: log.debug("****x2. " + (new Date()).getTime());
0708: while (iter.hasNext()) {
0709: ItemGradingIfc itemGrading = (ItemGradingIfc) iter
0710: .next();
0711: Long itemId = itemGrading.getPublishedItemId();
0712: ItemDataIfc item = (ItemDataIfc) publishedItemHash
0713: .get(itemId);
0714: Long itemType = item.getTypeId();
0715: float autoScore = (float) 0;
0716: if (!regrade) {
0717: itemGrading.setAssessmentGradingId(data
0718: .getAssessmentGradingId());
0719: //itemGrading.setSubmittedDate(new Date());
0720: itemGrading.setAgentId(agent);
0721: itemGrading.setOverrideScore(new Float(0));
0722: // note that totalItems & fibAnswersMap would be modified by the following method
0723: autoScore = getScoreByQuestionType(itemGrading,
0724: item, itemType, publishedItemTextHash,
0725: totalItems, fibAnswersMap,
0726: publishedAnswerHash);
0727: log.debug("**!regrade, autoScore=" + autoScore);
0728: if (!(TypeIfc.MULTIPLE_CORRECT).equals(itemType))
0729: totalItems.put(itemId, new Float(autoScore));
0730: } else {
0731: autoScore = itemGrading.getAutoScore().floatValue();
0732: //overridescore - cwen
0733: if (itemGrading.getOverrideScore() != null) {
0734: autoScore += itemGrading.getOverrideScore()
0735: .floatValue();
0736: }
0737:
0738: if (!totalItems.containsKey(itemId)
0739: && !(TypeIfc.MULTIPLE_CORRECT)
0740: .equals(itemType)) {
0741: totalItems.put(itemId, new Float(autoScore));
0742: } else {
0743: float accumelateScore = ((Float) totalItems
0744: .get(itemId)).floatValue();
0745: accumelateScore += autoScore;
0746: if (!(TypeIfc.MULTIPLE_CORRECT)
0747: .equals(itemType))
0748: totalItems.put(itemId, new Float(
0749: accumelateScore));
0750: }
0751: }
0752: itemGrading.setAutoScore(new Float(autoScore));
0753: }
0754:
0755: log.debug("****x3. " + (new Date()).getTime());
0756: // the following procedure ensure total score awarded per question is no less than 0
0757: // this probably only applies to MCMR question type - daisyf
0758: iter = itemGradingSet.iterator();
0759: while (iter.hasNext()) {
0760: ItemGradingIfc itemGrading = (ItemGradingIfc) iter
0761: .next();
0762: Long itemId = itemGrading.getPublishedItemId();
0763: //float autoScore = (float) 0;
0764:
0765: float eachItemScore = ((Float) totalItems.get(itemId))
0766: .floatValue();
0767: if (eachItemScore < 0) {
0768: itemGrading.setAutoScore(new Float(0));
0769: }
0770: }
0771: log.debug("****x4. " + (new Date()).getTime());
0772:
0773: // save#1: this itemGrading Set is a partial set of answers submitted. it contains new answers and
0774: // updated old answers and FIB answers ('cos we need the old answer to calculate the score for new
0775: // ones). we need to be cheap, we don't want to update record that hasn't been
0776: // changed. Yes, assessmentGrading's total score will be out of sync at this point, I am afraid. It
0777: // would be in sync again once the whole method is completed sucessfully.
0778: if (persistToDB) {
0779: saveOrUpdateAll(itemGradingSet);
0780: }
0781: log.debug("****x5. " + (new Date()).getTime());
0782:
0783: // save#2: now, we need to get the full set so we can calculate the total score accumulate for the
0784: // whole assessment.
0785: Set fullItemGradingSet = getItemGradingSet(data
0786: .getAssessmentGradingId().toString());
0787: float totalAutoScore = getTotalAutoScore(fullItemGradingSet);
0788: data.setTotalAutoScore(new Float(totalAutoScore));
0789: //log.debug("**#1 total AutoScore"+totalAutoScore);
0790: data.setFinalScore(new Float(totalAutoScore
0791: + data.getTotalOverrideScore().floatValue()));
0792: log.debug("****x6. " + (new Date()).getTime());
0793: } catch (GradebookServiceException ge) {
0794: ge.printStackTrace();
0795: throw ge;
0796: } catch (Exception e) {
0797: e.printStackTrace();
0798: throw new RuntimeException(e);
0799: }
0800:
0801: // save#3: itemGradingSet has been saved above so just need to update assessmentGrading
0802: // therefore setItemGradingSet as empty first - daisyf
0803: // however, if we do not persit to DB, we want to keep itemGradingSet with data for later use
0804: // Because if itemGradingSet is not saved to DB, we cannot go to DB to get it. We have to
0805: // get it through data.
0806: if (persistToDB) {
0807: data.setItemGradingSet(new HashSet());
0808: saveOrUpdateAssessmentGrading(data);
0809: }
0810: log.debug("****x7. " + (new Date()).getTime());
0811:
0812: notifyGradebookByScoringType(data, pub);
0813: log.debug("****x8. " + (new Date()).getTime());
0814: //log.debug("**#2 total AutoScore"+data.getTotalAutoScore());
0815: }
0816:
0817: private float getTotalAutoScore(Set itemGradingSet) {
0818: //log.debug("*** no. of itemGrading="+itemGradingSet.size());
0819: float totalAutoScore = 0;
0820: Iterator iter = itemGradingSet.iterator();
0821: while (iter.hasNext()) {
0822: ItemGradingIfc i = (ItemGradingIfc) iter.next();
0823: //log.debug(i.getItemGradingId()+"->"+i.getAutoScore());
0824: if (i.getAutoScore() != null)
0825: totalAutoScore += i.getAutoScore().floatValue();
0826: }
0827: return totalAutoScore;
0828: }
0829:
0830: private void notifyGradebookByScoringType(
0831: AssessmentGradingIfc data, PublishedAssessmentIfc pub) {
0832: Integer scoringType = pub.getEvaluationModel().getScoringType();
0833: if (updateGradebook(data, pub)) {
0834: AssessmentGradingIfc d = data; // data is the last submission
0835: // need to decide what to tell gradebook
0836: if ((scoringType).equals(EvaluationModelIfc.HIGHEST_SCORE))
0837: d = getHighestAssessmentGrading(pub
0838: .getPublishedAssessmentId().toString(), data
0839: .getAgentId());
0840: notifyGradebook(d, pub);
0841: }
0842: }
0843:
0844: private float getScoreByQuestionType(ItemGradingIfc itemGrading,
0845: ItemDataIfc item, Long itemType,
0846: HashMap publishedItemTextHash, HashMap totalItems,
0847: HashMap fibAnswersMap, HashMap publishedAnswerHash) {
0848: //float score = (float) 0;
0849: float initScore = (float) 0;
0850: float autoScore = (float) 0;
0851: float accumelateScore = (float) 0;
0852: Long itemId = item.getItemId();
0853: int type = itemType.intValue();
0854: switch (type) {
0855: case 1: // MC Single Correct
0856: case 3: // MC Survey
0857: case 4: // True/False
0858: autoScore = getAnswerScore(itemGrading, publishedAnswerHash);
0859: //overridescore
0860: if (itemGrading.getOverrideScore() != null)
0861: autoScore += itemGrading.getOverrideScore()
0862: .floatValue();
0863: totalItems.put(itemId, new Float(autoScore));
0864: break;
0865:
0866: case 2: // MC Multiple Correct
0867: ItemTextIfc itemText = (ItemTextIfc) publishedItemTextHash
0868: .get(itemGrading.getPublishedItemTextId());
0869: ArrayList answerArray = itemText.getAnswerArray();
0870: int correctAnswers = 0;
0871: if (answerArray != null) {
0872: for (int i = 0; i < answerArray.size(); i++) {
0873: AnswerIfc a = (AnswerIfc) answerArray.get(i);
0874: if (a.getIsCorrect().booleanValue())
0875: correctAnswers++;
0876: }
0877: }
0878: initScore = getAnswerScore(itemGrading, publishedAnswerHash);
0879: if (initScore > 0)
0880: autoScore = initScore / correctAnswers;
0881: else
0882: autoScore = (getTotalCorrectScore(itemGrading,
0883: publishedAnswerHash) / correctAnswers)
0884: * ((float) -1);
0885:
0886: //overridescore?
0887: if (itemGrading.getOverrideScore() != null)
0888: autoScore += itemGrading.getOverrideScore()
0889: .floatValue();
0890: if (!totalItems.containsKey(itemId)) {
0891: totalItems.put(itemId, new Float(autoScore));
0892: //log.debug("****0. first answer score = "+autoScore);
0893: } else {
0894: accumelateScore = ((Float) totalItems.get(itemId))
0895: .floatValue();
0896: //log.debug("****1. before adding new score = "+accumelateScore);
0897: //log.debug("****2. this answer score = "+autoScore);
0898: accumelateScore += autoScore;
0899: //log.debug("****3. add 1+2 score = "+accumelateScore);
0900: totalItems.put(itemId, new Float(accumelateScore));
0901: //log.debug("****4. what did we put in = "+((Float)totalItems.get(itemId)).floatValue());
0902: }
0903: break;
0904:
0905: case 9: // Matching
0906: initScore = getAnswerScore(itemGrading, publishedAnswerHash);
0907: if (initScore > 0)
0908: autoScore = initScore
0909: / ((float) item.getItemTextSet().size());
0910: //overridescore?
0911: if (itemGrading.getOverrideScore() != null)
0912: autoScore += itemGrading.getOverrideScore()
0913: .floatValue();
0914:
0915: if (!totalItems.containsKey(itemId))
0916: totalItems.put(itemId, new Float(autoScore));
0917: else {
0918: accumelateScore = ((Float) totalItems.get(itemId))
0919: .floatValue();
0920: accumelateScore += autoScore;
0921: totalItems.put(itemId, new Float(accumelateScore));
0922: }
0923: break;
0924:
0925: case 8: // FIB
0926: autoScore = getFIBScore(itemGrading, fibAnswersMap, item,
0927: publishedAnswerHash)
0928: / (float) ((ItemTextIfc) item.getItemTextSet()
0929: .toArray()[0]).getAnswerSet().size();
0930: //overridescore - cwen
0931: if (itemGrading.getOverrideScore() != null)
0932: autoScore += itemGrading.getOverrideScore()
0933: .floatValue();
0934:
0935: if (!totalItems.containsKey(itemId))
0936: totalItems.put(itemId, new Float(autoScore));
0937: else {
0938: accumelateScore = ((Float) totalItems.get(itemId))
0939: .floatValue();
0940: accumelateScore += autoScore;
0941: totalItems.put(itemId, new Float(accumelateScore));
0942: }
0943: break;
0944: case 11: // FIN
0945: autoScore = getFINScore(itemGrading, item,
0946: publishedAnswerHash)
0947: / (float) ((ItemTextIfc) item.getItemTextSet()
0948: .toArray()[0]).getAnswerSet().size();
0949: //overridescore - cwen
0950: if (itemGrading.getOverrideScore() != null)
0951: autoScore += itemGrading.getOverrideScore()
0952: .floatValue();
0953:
0954: if (!totalItems.containsKey(itemId))
0955: totalItems.put(itemId, new Float(autoScore));
0956: else {
0957: accumelateScore = ((Float) totalItems.get(itemId))
0958: .floatValue();
0959: accumelateScore += autoScore;
0960: totalItems.put(itemId, new Float(accumelateScore));
0961: }
0962: break;
0963:
0964: case 5: // SAQ
0965: case 6: // file upload
0966: case 7: // audio recording
0967: //overridescore - cwen
0968: if (itemGrading.getOverrideScore() != null)
0969: autoScore += itemGrading.getOverrideScore()
0970: .floatValue();
0971: if (!totalItems.containsKey(itemId))
0972: totalItems.put(itemId, new Float(autoScore));
0973: else {
0974: accumelateScore = ((Float) totalItems.get(itemId))
0975: .floatValue();
0976: accumelateScore += autoScore;
0977: totalItems.put(itemId, new Float(accumelateScore));
0978: }
0979: break;
0980: }
0981: return autoScore;
0982: }
0983:
0984: /**
0985: * This grades multiple choice and true false questions. Since
0986: * multiple choice/multiple select has a separate ItemGradingIfc for
0987: * each choice, they're graded the same way the single choice are.
0988: * Choices should be given negative score values if one wants them
0989: * to lose points for the wrong choice.
0990: */
0991: public float getAnswerScore(ItemGradingIfc data,
0992: HashMap publishedAnswerHash) {
0993: AnswerIfc answer = (AnswerIfc) publishedAnswerHash.get(data
0994: .getPublishedAnswerId());
0995: if (answer == null || answer.getScore() == null)
0996: return (float) 0;
0997: if (answer.getIsCorrect() == null
0998: || !answer.getIsCorrect().booleanValue())
0999: return (float) 0;
1000: return answer.getScore().floatValue();
1001: }
1002:
1003: public void notifyGradebook(AssessmentGradingIfc data,
1004: PublishedAssessmentIfc pub)
1005: throws GradebookServiceException {
1006: // If the assessment is published to the gradebook, make sure to update the scores in the gradebook
1007: String toGradebook = pub.getEvaluationModel().getToGradeBook();
1008:
1009: GradebookService g = null;
1010: boolean integrated = IntegrationContextFactory.getInstance()
1011: .isIntegrated();
1012: if (integrated) {
1013: g = (GradebookService) SpringBeanLocator
1014: .getInstance()
1015: .getBean(
1016: "org.sakaiproject.service.gradebook.GradebookService");
1017: }
1018:
1019: GradebookServiceHelper gbsHelper = IntegrationContextFactory
1020: .getInstance().getGradebookServiceHelper();
1021:
1022: if (gbsHelper.gradebookExists(
1023: GradebookFacade.getGradebookUId(), g)
1024: && toGradebook
1025: .equals(EvaluationModelIfc.TO_DEFAULT_GRADEBOOK
1026: .toString())) {
1027: if (log.isDebugEnabled())
1028: log
1029: .debug("Attempting to update a score in the gradebook");
1030:
1031: // add retry logic to resolve deadlock problem while sending grades to gradebook
1032:
1033: int retryCount = PersistenceService.getInstance()
1034: .getRetryCount().intValue();
1035: while (retryCount > 0) {
1036: try {
1037: /* for testing the catch block
1038: if (retryCount >2)
1039: throw new Exception();
1040: */
1041: gbsHelper.updateExternalAssessmentScore(data, g);
1042: retryCount = 0;
1043: } catch (Exception e) {
1044: log.warn("problem sending grades to gradebook: "
1045: + e.getMessage());
1046: log
1047: .warn("retrying...sending grades to gradebook. ");
1048: //String errorMessage = e.getMessage();
1049: log.warn("retry....");
1050: retryCount--;
1051: try {
1052: int deadlockInterval = PersistenceService
1053: .getInstance().getDeadlockInterval()
1054: .intValue();
1055: Thread.sleep(deadlockInterval);
1056: } catch (InterruptedException ex) {
1057: log.warn(ex.getMessage());
1058: }
1059: if (retryCount == 0) {
1060: // after retries, still failed updating gradebook
1061: log
1062: .warn("After all retries, still failed ... Now throw error to UI");
1063: throw new GradebookServiceException(e);
1064: }
1065: }
1066: }
1067:
1068: ////
1069:
1070: /*
1071: try {
1072: gbsHelper.updateExternalAssessmentScore(data, g);
1073: } catch (Exception e) {
1074: // Got GradebookException from gradebook tool
1075: e.printStackTrace();
1076: throw new GradebookServiceException(e);
1077:
1078: }
1079: */
1080: } else {
1081: if (log.isDebugEnabled())
1082: log.debug("Not updating the gradebook. toGradebook = "
1083: + toGradebook);
1084: }
1085: }
1086:
1087: /**
1088: * This grades Fill In Blank questions. (see SAK-1685)
1089:
1090: * There will be two valid cases for scoring when there are multiple fill
1091: * in blanks in a question:
1092:
1093: * Case 1- There are different sets of answers (a set can contain one or more
1094: * item) for each blank (e.g. The {dog|coyote|wolf} howls and the {lion|cougar}
1095: * roars.) In this case each blank is tested for correctness independently.
1096:
1097: * Case 2-There is the same set of answers for each blank: e.g. The flag of the US
1098: * is {red|white|blue},{red|white|blue}, and {red|white|blue}.
1099:
1100: * These are the only two valid types of questions. When authoring, it is an
1101: * ERROR to include:
1102:
1103: * (1) a mixture of independent answer and common answer blanks
1104: * (e.g. The {dog|coyote|wolf} howls at the {red|white|blue}, {red|white|blue},
1105: * and {red|white|blue} flag.)
1106:
1107: * (2) more than one set of blanks with a common answer ((e.g. The US flag
1108: * is {red|white|blue}, {red|white|blue}, and {red|white|blue} and the Italian
1109: * flag is {red|white|greem}, {red|white|greem}, and {red|white|greem}.)
1110:
1111: * These two invalid questions specifications should be authored as two
1112: * separate questions.
1113:
1114: Here are the definition and 12 cases I came up with (lydia, 01/2006):
1115:
1116: single answers : roses are {red} and vilets are {blue}
1117: multiple answers : {dogs|cats} have 4 legs
1118: multiple answers , mutually exclusive, all answers must be identical, can be in diff. orders : US flag has {red|blue|white} and {red |white|blue} and {blue|red|white} colors
1119: multiple answers , mutually non-exclusive : {dogs|cats} have 4 legs and {dogs|cats} can be pets.
1120: wildcard uses * to mean one of more characters
1121:
1122:
1123: -. wildcard single answer, case sensitive
1124: -. wildcard single answer, case insensitive
1125: -. single answer, no wildcard , case sensitive
1126: -. single answer, no wildcard , case insensitive
1127: -. multiple answer, mutually non-exclusive, no wildcard , case sensitive
1128: -. multiple answer, mutually non-exclusive, no wildcard , case in sensitive
1129: -. multiple answer, mutually non-exclusive, wildcard , case sensitive
1130: -. multiple answer, mutually non-exclusive, wildcard , case insensitive
1131: -. multiple answer, mutually exclusive, no wildcard , case sensitive
1132: -. multiple answer, mutually exclusive, no wildcard , case in sensitive
1133: -. multiple answer, mutually exclusive, wildcard , case sensitive
1134: -. multiple answer, mutually exclusive, wildcard , case insensitive
1135:
1136: */
1137:
1138: public float getFIBScore(ItemGradingIfc data, HashMap fibmap,
1139: ItemDataIfc itemdata, HashMap publishedAnswerHash) {
1140: String studentanswer = "";
1141: boolean matchresult = false;
1142:
1143: if (data.getPublishedAnswerId() == null) {
1144: return (float) 0;
1145: }
1146:
1147: String answertext = ((AnswerIfc) publishedAnswerHash.get(data
1148: .getPublishedAnswerId())).getText();
1149: Long itemId = itemdata.getItemId();
1150:
1151: String casesensitive = itemdata
1152: .getItemMetaDataByLabel(ItemMetaDataIfc.CASE_SENSITIVE_FOR_FIB);
1153: String mutuallyexclusive = itemdata
1154: .getItemMetaDataByLabel(ItemMetaDataIfc.MUTUALLY_EXCLUSIVE_FOR_FIB);
1155: //Set answerSet = new HashSet();
1156:
1157: float totalScore = (float) 0;
1158:
1159: if (answertext != null) {
1160: StringTokenizer st = new StringTokenizer(answertext, "|");
1161: while (st.hasMoreTokens()) {
1162: String answer = st.nextToken().trim();
1163: if ("true".equalsIgnoreCase(casesensitive)) {
1164: if (data.getAnswerText() != null) {
1165: studentanswer = data.getAnswerText().trim();
1166: matchresult = fibmatch(answer, studentanswer,
1167: true);
1168:
1169: }
1170: } // if case sensitive
1171: else {
1172: // case insensitive , if casesensitive is false, or null, or "".
1173: if (data.getAnswerText() != null) {
1174: studentanswer = data.getAnswerText().trim();
1175: matchresult = fibmatch(answer, studentanswer,
1176: false);
1177: }
1178: } // else , case insensitive
1179:
1180: if (matchresult) {
1181:
1182: boolean alreadyused = false;
1183: // add check for mutual exclusive
1184: if ("true".equalsIgnoreCase(mutuallyexclusive)) {
1185: // check if answers are already used.
1186: Set answer_used_sofar = (HashSet) fibmap
1187: .get(itemId);
1188: if ((answer_used_sofar != null)
1189: && (answer_used_sofar
1190: .contains(studentanswer
1191: .toLowerCase()))) {
1192: // already used, so it's a wrong answer for mutually exclusive questions
1193: alreadyused = true;
1194: } else {
1195: // not used, it's a good answer, now add this to the already_used list.
1196: // we only store lowercase strings in the fibmap.
1197: if (answer_used_sofar == null) {
1198: answer_used_sofar = new HashSet();
1199: }
1200:
1201: answer_used_sofar.add(studentanswer
1202: .toLowerCase());
1203: fibmap.put(itemId, answer_used_sofar);
1204: }
1205: }
1206:
1207: if (!alreadyused) {
1208: totalScore += ((AnswerIfc) publishedAnswerHash
1209: .get(data.getPublishedAnswerId()))
1210: .getScore().floatValue();
1211: }
1212:
1213: // SAK-3005: quit if answer is correct, e.g. if you answered A for {a|A}, you already scored
1214: break;
1215: }
1216:
1217: }
1218: }
1219: return totalScore;
1220: }
1221:
1222: public boolean getFIBResult(ItemGradingIfc data, HashMap fibmap,
1223: ItemDataIfc itemdata, HashMap publishedAnswerHash) {
1224: // this method is similiar to getFIBScore(), except it returns true/false for the answer, not scores.
1225: // may be able to refactor code out to be reused, but totalscores for mutually exclusive case is a bit tricky.
1226: String studentanswer = "";
1227: boolean matchresult = false;
1228:
1229: if (data.getPublishedAnswerId() == null) {
1230: return false;
1231: }
1232:
1233: String answertext = ((AnswerIfc) publishedAnswerHash.get(data
1234: .getPublishedAnswerId())).getText();
1235: Long itemId = itemdata.getItemId();
1236:
1237: String casesensitive = itemdata
1238: .getItemMetaDataByLabel(ItemMetaDataIfc.CASE_SENSITIVE_FOR_FIB);
1239: String mutuallyexclusive = itemdata
1240: .getItemMetaDataByLabel(ItemMetaDataIfc.MUTUALLY_EXCLUSIVE_FOR_FIB);
1241: //Set answerSet = new HashSet();
1242:
1243: if (answertext != null) {
1244: StringTokenizer st = new StringTokenizer(answertext, "|");
1245: while (st.hasMoreTokens()) {
1246: String answer = st.nextToken().trim();
1247: if ("true".equalsIgnoreCase(casesensitive)) {
1248: if (data.getAnswerText() != null) {
1249: studentanswer = data.getAnswerText().trim();
1250: matchresult = fibmatch(answer, studentanswer,
1251: true);
1252: }
1253: } // if case sensitive
1254: else {
1255: // case insensitive , if casesensitive is false, or null, or "".
1256: if (data.getAnswerText() != null) {
1257: studentanswer = data.getAnswerText().trim();
1258: matchresult = fibmatch(answer, studentanswer,
1259: false);
1260: }
1261: } // else , case insensitive
1262:
1263: if (matchresult) {
1264:
1265: boolean alreadyused = false;
1266: // add check for mutual exclusive
1267: if ("true".equalsIgnoreCase(mutuallyexclusive)) {
1268: // check if answers are already used.
1269: Set answer_used_sofar = (HashSet) fibmap
1270: .get(itemId);
1271: if ((answer_used_sofar != null)
1272: && (answer_used_sofar
1273: .contains(studentanswer
1274: .toLowerCase()))) {
1275: // already used, so it's a wrong answer for mutually exclusive questions
1276: alreadyused = true;
1277: } else {
1278: // not used, it's a good answer, now add this to the already_used list.
1279: // we only store lowercase strings in the fibmap.
1280: if (answer_used_sofar == null) {
1281: answer_used_sofar = new HashSet();
1282: }
1283:
1284: answer_used_sofar.add(studentanswer
1285: .toLowerCase());
1286: fibmap.put(itemId, answer_used_sofar);
1287: }
1288: }
1289:
1290: if (alreadyused) {
1291: matchresult = false;
1292: }
1293:
1294: break;
1295: }
1296:
1297: }
1298: }
1299: return matchresult;
1300: }
1301:
1302: public float getFINScore(ItemGradingIfc data, ItemDataIfc itemdata,
1303: HashMap publishedAnswerHash) {
1304: float totalScore = (float) 0;
1305: boolean matchresult = getFINResult(data, itemdata,
1306: publishedAnswerHash);
1307: if (matchresult) {
1308: totalScore += ((AnswerIfc) publishedAnswerHash.get(data
1309: .getPublishedAnswerId())).getScore().floatValue();
1310:
1311: }
1312: return totalScore;
1313:
1314: }
1315:
1316: public boolean getFINResult(ItemGradingIfc data,
1317: ItemDataIfc itemdata, HashMap publishedAnswerHash) {
1318: // this method checks if the FIN answer is correct.
1319: String studentanswer = "";
1320: boolean range;
1321: boolean matchresult = false;
1322: float studentAnswerNum, answer1Num, answer2Num, answerNum;
1323:
1324: if (data.getPublishedAnswerId() == null) {
1325: return false;
1326: }
1327:
1328: String answertext = ((AnswerIfc) publishedAnswerHash.get(data
1329: .getPublishedAnswerId())).getText();
1330: //Long itemId = itemdata.getItemId();
1331:
1332: //Set answerSet = new HashSet();
1333:
1334: if (answertext != null) {
1335: StringTokenizer st = new StringTokenizer(answertext, "|");
1336: range = false;
1337: if (st.countTokens() > 1) {
1338: range = true;
1339: }
1340: if (range)
1341:
1342: {
1343:
1344: String answer1 = st.nextToken().trim();
1345: String answer2 = st.nextToken().trim();
1346: if (answer1 != null) {
1347: answer1 = answer1.trim().replace(',', '.'); // in Spain, comma is used as a decimal point
1348: }
1349:
1350: try {
1351: answer1Num = Float.valueOf(answer1).floatValue();
1352: } catch (NumberFormatException ex) {
1353: answer1Num = Float.NaN;
1354: }
1355: log.info("answer1Num= " + answer1Num);
1356: if (answer2 != null) {
1357: answer2 = answer2.trim().replace(',', '.'); // in Spain, comma is used as a decimal point
1358: }
1359:
1360: try {
1361: answer2Num = Float.valueOf(answer2).floatValue();
1362: } catch (NumberFormatException ex) {
1363: answer2Num = Float.NaN;
1364: }
1365:
1366: log.info("answer2Num= " + answer2Num);
1367:
1368: if (data.getAnswerText() != null) {
1369: studentanswer = data.getAnswerText().trim()
1370: .replace(',', '.'); // in Spain, comma is used as a decimal point
1371: try {
1372: studentAnswerNum = Float.valueOf(studentanswer)
1373: .floatValue();
1374: } catch (NumberFormatException ex) {
1375: studentAnswerNum = Float.NaN;
1376: //Temporal. Directamente contar\? como mala.
1377: }
1378: log.info("studentAnswerNum= " + studentAnswerNum);
1379: if (!(studentAnswerNum == Float.NaN
1380: || answer1Num == Float.NaN || answer2Num == Float.NaN)) {
1381: matchresult = ((answer1Num <= studentAnswerNum) && (answer2Num >= studentAnswerNum));
1382: }
1383:
1384: }
1385: } else { //range
1386: String answer = st.nextToken().trim();
1387: if (answer != null) {
1388: answer = answer.trim().replace(',', '.'); // in Spain, comma is used as a decimal point
1389: }
1390:
1391: try {
1392: answerNum = Float.valueOf(answer).floatValue();
1393: } catch (NumberFormatException ex) {
1394: answerNum = Float.NaN;
1395: // should not go here
1396: }
1397: log.info("answerNum= " + answerNum);
1398:
1399: if (data.getAnswerText() != null) {
1400: studentanswer = data.getAnswerText().trim()
1401: .replace(',', '.'); // in Spain, comma is used as a decimal point
1402: try {
1403: studentAnswerNum = Float.valueOf(studentanswer)
1404: .floatValue();
1405: } catch (NumberFormatException ex) {
1406: studentAnswerNum = Float.NaN;
1407: }
1408: log.info("studentAnswerNum= " + studentAnswerNum);
1409: if (!(studentAnswerNum == Float.NaN || answerNum == Float.NaN)) {
1410: matchresult = (answerNum == studentAnswerNum);
1411: }
1412: }
1413: }
1414:
1415: }
1416: return matchresult;
1417: }
1418:
1419: public float getTotalCorrectScore(ItemGradingIfc data,
1420: HashMap publishedAnswerHash) {
1421: AnswerIfc answer = (AnswerIfc) publishedAnswerHash.get(data
1422: .getPublishedAnswerId());
1423: if (answer == null || answer.getScore() == null)
1424: return (float) 0;
1425: return answer.getScore().floatValue();
1426: }
1427:
1428: private void setIsLate(AssessmentGradingIfc data,
1429: PublishedAssessmentIfc pub) {
1430: if (pub.getAssessmentAccessControl() != null
1431: && pub.getAssessmentAccessControl().getDueDate() != null
1432: && pub.getAssessmentAccessControl().getDueDate()
1433: .before(new Date()))
1434: data.setIsLate(Boolean.TRUE);
1435: else
1436: data.setIsLate(new Boolean(false));
1437: if (data.getForGrade().booleanValue())
1438: data.setStatus(new Integer(1));
1439: else
1440: data.setStatus(new Integer(0));
1441: data.setTotalOverrideScore(new Float(0));
1442: }
1443:
1444: public void deleteAll(Collection c) {
1445: try {
1446: PersistenceService.getInstance()
1447: .getAssessmentGradingFacadeQueries().deleteAll(c);
1448: } catch (Exception e) {
1449: e.printStackTrace();
1450: }
1451: }
1452:
1453: /* Note:
1454: * assessmentGrading contains set of itemGrading that are not saved in the DB yet
1455: */
1456: public void updateAssessmentGradingScore(
1457: AssessmentGradingIfc adata, PublishedAssessmentIfc pub) {
1458: try {
1459: Set itemGradingSet = adata.getItemGradingSet();
1460: Iterator iter = itemGradingSet.iterator();
1461: float totalAutoScore = 0;
1462: float totalOverrideScore = adata.getTotalOverrideScore()
1463: .floatValue();
1464: while (iter.hasNext()) {
1465: ItemGradingIfc i = (ItemGradingIfc) iter.next();
1466: if (i.getAutoScore() != null)
1467: totalAutoScore += i.getAutoScore().floatValue();
1468: }
1469: float oldAutoScore = adata.getTotalAutoScore().floatValue();
1470: float scoreDifference = totalAutoScore - oldAutoScore;
1471: adata.setTotalAutoScore(new Float(totalAutoScore));
1472: adata.setFinalScore(new Float(totalAutoScore
1473: + totalOverrideScore));
1474: saveOrUpdateAssessmentGrading(adata);
1475: if (scoreDifference != 0) {
1476: notifyGradebookByScoringType(adata, pub);
1477: }
1478: } catch (GradebookServiceException ge) {
1479: ge.printStackTrace();
1480: throw ge;
1481: } catch (Exception e) {
1482: e.printStackTrace();
1483: throw new RuntimeException(e);
1484: }
1485: }
1486:
1487: public void saveOrUpdateAll(Collection c) {
1488: try {
1489: PersistenceService.getInstance()
1490: .getAssessmentGradingFacadeQueries()
1491: .saveOrUpdateAll(c);
1492: } catch (Exception e) {
1493: e.printStackTrace();
1494: }
1495: }
1496:
1497: public PublishedAssessmentIfc getPublishedAssessmentByAssessmentGradingId(
1498: String id) {
1499: PublishedAssessmentIfc pub = null;
1500: try {
1501: pub = PersistenceService.getInstance()
1502: .getAssessmentGradingFacadeQueries()
1503: .getPublishedAssessmentByAssessmentGradingId(
1504: new Long(id));
1505: } catch (Exception e) {
1506: e.printStackTrace();
1507: }
1508: return pub;
1509: }
1510:
1511: public PublishedAssessmentIfc getPublishedAssessmentByPublishedItemId(
1512: String publishedItemId) {
1513: PublishedAssessmentIfc pub = null;
1514: try {
1515: pub = PersistenceService.getInstance()
1516: .getAssessmentGradingFacadeQueries()
1517: .getPublishedAssessmentByPublishedItemId(
1518: new Long(publishedItemId));
1519: } catch (Exception e) {
1520: e.printStackTrace();
1521: }
1522: return pub;
1523: }
1524:
1525: public ArrayList getLastItemGradingDataPosition(
1526: Long assessmentGradingId, String agentId) {
1527: ArrayList results = null;
1528: try {
1529: results = PersistenceService.getInstance()
1530: .getAssessmentGradingFacadeQueries()
1531: .getLastItemGradingDataPosition(
1532: assessmentGradingId, agentId);
1533: } catch (Exception e) {
1534: e.printStackTrace();
1535: }
1536: return results;
1537: }
1538:
1539: public List getItemGradingIds(Long assessmentGradingId) {
1540: List results = null;
1541: try {
1542: results = PersistenceService.getInstance()
1543: .getAssessmentGradingFacadeQueries()
1544: .getItemGradingIds(assessmentGradingId);
1545: } catch (Exception e) {
1546: e.printStackTrace();
1547: }
1548: return results;
1549: }
1550:
1551: public HashSet getItemSet(Long publishedAssessmentId, Long sectionId) {
1552: HashSet results = null;
1553: try {
1554: results = PersistenceService.getInstance()
1555: .getAssessmentGradingFacadeQueries().getItemSet(
1556: publishedAssessmentId, sectionId);
1557: } catch (Exception e) {
1558: e.printStackTrace();
1559: }
1560: return results;
1561: }
1562:
1563: public Long getTypeId(Long itemGradingId) {
1564: Long typeId = null;
1565: try {
1566: typeId = PersistenceService.getInstance()
1567: .getAssessmentGradingFacadeQueries().getTypeId(
1568: itemGradingId);
1569: } catch (Exception e) {
1570: e.printStackTrace();
1571: }
1572: return typeId;
1573: }
1574:
1575: public boolean fibmatch(String answer, String input,
1576: boolean casesensitive) {
1577:
1578: try {
1579:
1580: // comment this part out if using the jdk 1.5 version
1581:
1582: /*
1583: String REGEX = answer.replaceAll("\\*", ".+");
1584: Pattern p;
1585: if (casesensitive) {
1586: p = Pattern.compile(REGEX);
1587: } else {
1588: p = Pattern.compile(REGEX, Pattern.CASE_INSENSITIVE);
1589: }
1590:
1591: Matcher m = p.matcher(input);
1592: boolean matchresult = m.matches();
1593: return matchresult;
1594:
1595: */
1596:
1597: // requires jdk 1.5 for Pattern.quote(), allow metacharacters, such as a+b.
1598:
1599: String regex_quote = "";
1600:
1601: String REGEX = answer.replaceAll("\\*", "|*|");
1602: String[] oneblank = REGEX.split("\\|");
1603: for (int j = 0; j < oneblank.length; j++) {
1604: if ("*".equals(oneblank[j])) {
1605: regex_quote = regex_quote + ".+";
1606: } else {
1607: regex_quote = regex_quote
1608: + Pattern.quote(oneblank[j]);
1609:
1610: }
1611: }
1612:
1613: Pattern p;
1614: if (casesensitive) {
1615: p = Pattern.compile(regex_quote);
1616: } else {
1617: p = Pattern.compile(regex_quote,
1618: Pattern.CASE_INSENSITIVE);
1619: }
1620: Matcher m = p.matcher(input);
1621: boolean result = m.matches();
1622: return result;
1623:
1624: } catch (Exception e) {
1625: return false;
1626: }
1627: }
1628:
1629: public List getAllAssessmentGradingByAgentId(
1630: Long publishedAssessmentId, String agentIdString) {
1631: List results = null;
1632: try {
1633: results = PersistenceService.getInstance()
1634: .getAssessmentGradingFacadeQueries()
1635: .getAllAssessmentGradingByAgentId(
1636: publishedAssessmentId, agentIdString);
1637: } catch (Exception e) {
1638: e.printStackTrace();
1639: }
1640: return results;
1641: }
1642:
1643: public int getActualNumberRetake(Long publishedAssessmentId,
1644: String agentIdString) {
1645: int actualNumberReatke = 0;
1646: try {
1647: actualNumberReatke = PersistenceService.getInstance()
1648: .getAssessmentGradingFacadeQueries()
1649: .getActualNumberRetake(publishedAssessmentId,
1650: agentIdString);
1651: } catch (Exception e) {
1652: e.printStackTrace();
1653: }
1654: return actualNumberReatke;
1655: }
1656:
1657: public List getStudentGradingSummaryData(
1658: Long publishedAssessmentId, String agentIdString) {
1659: List results = null;
1660: try {
1661: results = PersistenceService.getInstance()
1662: .getAssessmentGradingFacadeQueries()
1663: .getStudentGradingSummaryData(
1664: publishedAssessmentId, agentIdString);
1665: } catch (Exception e) {
1666: e.printStackTrace();
1667: }
1668: return results;
1669: }
1670:
1671: public int getNumberRetake(Long publishedAssessmentId,
1672: String agentIdString) {
1673: int numberRetake = 0;
1674: try {
1675: numberRetake = PersistenceService.getInstance()
1676: .getAssessmentGradingFacadeQueries()
1677: .getNumberRetake(publishedAssessmentId,
1678: agentIdString);
1679: } catch (Exception e) {
1680: e.printStackTrace();
1681: }
1682: return numberRetake;
1683: }
1684:
1685: public void saveStudentGradingSummaryData(
1686: StudentGradingSummaryIfc studentGradingSummaryData) {
1687: try {
1688: PersistenceService.getInstance()
1689: .getAssessmentGradingFacadeQueries()
1690: .saveStudentGradingSummaryData(
1691: studentGradingSummaryData);
1692: } catch (Exception e) {
1693: e.printStackTrace();
1694: }
1695: }
1696:
1697: public int getLateSubmissionsNumberByAgentId(
1698: Long publishedAssessmentId, String agentIdString,
1699: Date dueDate) {
1700: int numberRetake = 0;
1701: try {
1702: numberRetake = PersistenceService.getInstance()
1703: .getAssessmentGradingFacadeQueries()
1704: .getLateSubmissionsNumberByAgentId(
1705: publishedAssessmentId, agentIdString,
1706: dueDate);
1707: } catch (Exception e) {
1708: e.printStackTrace();
1709: }
1710: return numberRetake;
1711: }
1712: }
|