001: package org.sakaiproject.tool.assessment.data.dao.assessment;
002:
003: import java.io.IOException;
004: import java.util.ArrayList;
005: import java.util.Collections;
006: import java.util.Date;
007: import java.util.HashMap;
008: import java.util.HashSet;
009: import java.util.Iterator;
010: import java.util.List;
011: import java.util.Set;
012:
013: import org.apache.log4j.Category;
014: import org.sakaiproject.tool.assessment.data.dao.shared.TypeD;
015: import org.sakaiproject.tool.assessment.data.ifc.assessment.AnswerIfc;
016: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemAttachmentIfc;
017: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemDataIfc;
018: import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemTextIfc;
019: import org.sakaiproject.tool.assessment.data.ifc.assessment.SectionDataIfc;
020: import org.sakaiproject.tool.assessment.data.ifc.shared.TypeIfc;
021:
022: //import org.sakaiproject.tool.assessment.facade.TypeFacadeQueriesAPI;
023: //import org.sakaiproject.tool.assessment.services.PersistenceService;
024:
025: public class ItemData implements java.io.Serializable, ItemDataIfc,
026: Comparable {
027: static Category errorLogger = Category.getInstance("errorLogger");
028:
029: private static final long serialVersionUID = 7526471155622776147L;
030: public static final Long ADMIN = new Long(34);
031:
032: private Long itemId;
033: private String itemIdString;
034: private SectionDataIfc section;
035: private Integer sequence;
036: private Integer duration;
037: private Integer triesAllowed;
038: private String instruction;
039: private String description;
040: private Long typeId;
041: private String grade;
042: private Float score;
043: private String hint;
044: private Boolean hasRationale;
045: private Integer status;
046: private String createdBy;
047: private Date createdDate;
048: private String lastModifiedBy;
049: private Date lastModifiedDate;
050: private Set itemTextSet;
051: private Set itemMetaDataSet;
052: private Set itemFeedbackSet;
053: private HashMap itemMetaDataMap = new HashMap();
054: private HashMap itemFeedbackMap;
055: private Set itemAttachmentSet;
056:
057: public ItemData() {
058: }
059:
060: // this constructor should be deprecated, it is missing triesAllowed
061: public ItemData(SectionDataIfc section, Integer sequence,
062: Integer duration, String instruction, String description,
063: Long typeId, String grade, Float score, String hint,
064: Boolean hasRationale, Integer status, String createdBy,
065: Date createdDate, String lastModifiedBy,
066: Date lastModifiedDate, Set itemTextSet,
067: Set itemMetaDataSet, Set itemFeedbackSet) {
068: this .section = section;
069: this .sequence = sequence;
070: this .duration = duration;
071: this .instruction = instruction;
072: this .description = description;
073: this .typeId = typeId;
074: this .grade = grade;
075: this .score = score;
076: this .hint = hint;
077: this .hasRationale = hasRationale;
078: this .status = status;
079: this .createdBy = createdBy;
080: this .createdDate = createdDate;
081: this .lastModifiedBy = lastModifiedBy;
082: this .lastModifiedDate = lastModifiedDate;
083: this .itemTextSet = itemTextSet;
084: this .itemMetaDataSet = itemMetaDataSet;
085: this .itemFeedbackSet = itemFeedbackSet;
086: }
087:
088: public ItemData(SectionDataIfc section, Integer sequence,
089: Integer duration, String instruction, String description,
090: Long typeId, String grade, Float score, String hint,
091: Boolean hasRationale, Integer status, String createdBy,
092: Date createdDate, String lastModifiedBy,
093: Date lastModifiedDate, Set itemTextSet,
094: Set itemMetaDataSet, Set itemFeedbackSet,
095: Integer triesAllowed) {
096: this .section = section;
097: this .sequence = sequence;
098: this .duration = duration;
099: this .instruction = instruction;
100: this .description = description;
101: this .typeId = typeId;
102: this .grade = grade;
103: this .score = score;
104: this .hint = hint;
105: this .hasRationale = hasRationale;
106: this .status = status;
107: this .createdBy = createdBy;
108: this .createdDate = createdDate;
109: this .lastModifiedBy = lastModifiedBy;
110: this .lastModifiedDate = lastModifiedDate;
111: this .itemTextSet = itemTextSet;
112: this .itemMetaDataSet = itemMetaDataSet;
113: this .itemFeedbackSet = itemFeedbackSet;
114: this .triesAllowed = triesAllowed;
115: }
116:
117: /*
118: public Object clone() throws CloneNotSupportedException{
119:
120: ItemData cloned= new ItemData(
121: this.getSection(),this.getSequence(), this.getDuration(), this.getInstruction(),
122: this.getDescription(),this.getTypeId(),this.getGrade(),this.getScore(),
123: this.getHint(),this.getHasRationale(),this.getStatus(),this.getCreatedBy(),
124: this.getCreatedDate(),this.getLastModifiedBy(),this.getLastModifiedDate(),
125: null, null, null, this.getTriesAllowed());
126:
127: // perform deep copy, set ItemTextSet, itemMetaDataSet and itemFeedbackSet
128: Set newItemTextSet = copyItemTextSet(cloned, this.getItemTextSet());
129: Set newItemMetaDataSet = copyItemMetaDataSet(cloned, this.getItemMetaDataSet());
130: Set newItemFeedbackSet = copyItemFeedbackSet(cloned, this.getItemFeedbackSet());
131: Set newItemAttachmentSet = copyItemAttachmentSet(cloned, this.getItemAttachmentSet());
132: cloned.setItemTextSet(newItemTextSet);
133: cloned.setItemMetaDataSet(newItemMetaDataSet);
134: cloned.setItemFeedbackSet(newItemFeedbackSet);
135: cloned.setItemAttachmentSet(newItemAttachmentSet);
136:
137: return (Object)cloned;
138: }
139:
140: public Set copyItemTextSet(ItemData cloned, Set itemTextSet) {
141: HashSet h = new HashSet();
142: Iterator k = itemTextSet.iterator();
143: while (k.hasNext()) {
144: ItemText itemText = (ItemText) k.next();
145: ItemText newItemText = new ItemText(cloned, itemText.getSequence(), itemText.getText(), null);
146: Set newAnswerSet = copyAnswerSet(newItemText, itemText.getAnswerSet());
147: newItemText.setAnswerSet(newAnswerSet);
148: h.add(newItemText);
149: }
150: return h;
151: }
152:
153: public Set copyAnswerSet(ItemText newItemText, Set answerSet) {
154: HashSet h = new HashSet();
155: Iterator l = answerSet.iterator();
156: while (l.hasNext()) {
157: Answer answer = (Answer) l.next();
158: Answer newAnswer = new Answer(
159: newItemText, answer.getText(), answer.getSequence(),
160: answer.getLabel(),
161: answer.getIsCorrect(), answer.getGrade(), answer.getScore(), null);
162: Set newAnswerFeedbackSet = copyAnswerFeedbackSet(
163: newAnswer, answer.getAnswerFeedbackSet());
164: newAnswer.setAnswerFeedbackSet(newAnswerFeedbackSet);
165: h.add(newAnswer);
166: }
167: return h;
168: }
169:
170: public Set copyAnswerFeedbackSet(Answer newAnswer, Set answerFeedbackSet) {
171: HashSet h = new HashSet();
172: Iterator m = answerFeedbackSet.iterator();
173: while (m.hasNext()) {
174: AnswerFeedback answerFeedback = (AnswerFeedback) m.next();
175: AnswerFeedback newAnswerFeedback = new AnswerFeedback(
176: newAnswer, answerFeedback.getTypeId(), answerFeedback.getText());
177: h.add(newAnswerFeedback);
178: }
179: return h;
180: }
181:
182: public Set copyItemMetaDataSet(ItemData cloned, Set itemMetaDataSet) {
183: HashSet h = new HashSet();
184: Iterator n = itemMetaDataSet.iterator();
185: while (n.hasNext()) {
186: ItemMetaData itemMetaData = (ItemMetaData) n.next();
187: ItemMetaData newItemMetaData = new ItemMetaData(
188: cloned, itemMetaData.getLabel(), itemMetaData.getEntry());
189: h.add(newItemMetaData);
190: }
191: return h;
192: }
193:
194: public Set copyItemFeedbackSet(ItemData cloned, Set itemFeedbackSet) {
195: HashSet h = new HashSet();
196: Iterator o = itemFeedbackSet.iterator();
197: while (o.hasNext()) {
198: ItemFeedback itemFeedback = (ItemFeedback) o.next();
199: ItemFeedback newItemFeedback = new ItemFeedback(
200: cloned, itemFeedback.getTypeId(), itemFeedback.getText());
201: h.add(newItemFeedback);
202: }
203: return h;
204: }
205:
206: */
207:
208: public Long getItemId() {
209: return this .itemId;
210: }
211:
212: public void setItemId(Long itemId) {
213: this .itemId = itemId;
214: setItemIdString(itemId.toString());
215: }
216:
217: public String getItemIdString() {
218: return this .itemIdString;
219: }
220:
221: public void setItemIdString(String itemIdString) {
222: this .itemIdString = itemIdString;
223: }
224:
225: public SectionDataIfc getSection() {
226: return this .section;
227: }
228:
229: public void setSection(SectionDataIfc section) {
230: this .section = section;
231: }
232:
233: public Integer getDuration() {
234: return this .duration;
235: }
236:
237: public void setDuration(Integer duration) {
238: this .duration = duration;
239: }
240:
241: public Integer getSequence() {
242: return this .sequence;
243: }
244:
245: public void setSequence(Integer sequence) {
246: this .sequence = sequence;
247: }
248:
249: public String getInstruction() {
250: return this .instruction;
251: }
252:
253: public void setInstruction(String instruction) {
254: this .instruction = instruction;
255: }
256:
257: public String getDescription() {
258: return this .description;
259: }
260:
261: public void setDescription(String description) {
262: this .description = description;
263: }
264:
265: public Long getTypeId() {
266: return this .typeId;
267: }
268:
269: public void setTypeId(Long typeId) {
270: this .typeId = typeId;
271: }
272:
273: public String getGrade() {
274: return this .grade;
275: }
276:
277: public void setGrade(String grade) {
278: this .grade = grade;
279: }
280:
281: public Float getScore() {
282: return this .score;
283: }
284:
285: public void setScore(Float score) {
286: this .score = score;
287: }
288:
289: public String getHint() {
290: return this .hint;
291: }
292:
293: public void setHint(String hint) {
294: this .hint = hint;
295: }
296:
297: public Boolean getHasRationale() {
298: return this .hasRationale;
299: }
300:
301: public void setHasRationale(Boolean hasRationale) {
302: this .hasRationale = hasRationale;
303: }
304:
305: public Integer getStatus() {
306: return this .status;
307: }
308:
309: public void setStatus(Integer status) {
310: this .status = status;
311: }
312:
313: public String getCreatedBy() {
314: return this .createdBy;
315: }
316:
317: public void setCreatedBy(String createdBy) {
318: this .createdBy = createdBy;
319: }
320:
321: public Date getCreatedDate() {
322: return this .createdDate;
323: }
324:
325: public void setCreatedDate(Date createdDate) {
326: this .createdDate = createdDate;
327: }
328:
329: public String getLastModifiedBy() {
330: return this .lastModifiedBy;
331: }
332:
333: public void setLastModifiedBy(String lastModifiedBy) {
334: this .lastModifiedBy = lastModifiedBy;
335: }
336:
337: public Date getLastModifiedDate() {
338: return this .lastModifiedDate;
339: }
340:
341: public void setLastModifiedDate(Date lastModifiedDate) {
342: this .lastModifiedDate = lastModifiedDate;
343: }
344:
345: public Set getItemTextSet() {
346: return itemTextSet;
347: }
348:
349: public void setItemTextSet(Set itemTextSet) {
350: this .itemTextSet = itemTextSet;
351: }
352:
353: public Set getItemMetaDataSet() {
354: return itemMetaDataSet;
355: }
356:
357: public void setItemMetaDataSet(Set itemMetaDataSet) {
358: this .itemMetaDataSet = itemMetaDataSet;
359: this .itemMetaDataMap = getItemMetaDataMap(itemMetaDataSet);
360: }
361:
362: public HashMap getItemMetaDataMap(Set itemMetaDataSet) {
363: HashMap itemMetaDataMap = new HashMap();
364: if (itemMetaDataSet != null) {
365: for (Iterator i = itemMetaDataSet.iterator(); i.hasNext();) {
366: ItemMetaData itemMetaData = (ItemMetaData) i.next();
367: itemMetaDataMap.put(itemMetaData.getLabel(),
368: itemMetaData.getEntry());
369: }
370: }
371: return itemMetaDataMap;
372: }
373:
374: public Set getItemFeedbackSet() {
375: return itemFeedbackSet;
376: }
377:
378: public void setItemFeedbackSet(Set itemFeedbackSet) {
379: this .itemFeedbackSet = itemFeedbackSet;
380: this .itemFeedbackMap = getItemFeedbackMap(itemFeedbackSet);
381: }
382:
383: public HashMap getItemFeedbackMap(Set itemFeedbackSet) {
384: HashMap itemFeedbackMap = new HashMap();
385: if (itemFeedbackSet != null) {
386: for (Iterator i = itemFeedbackSet.iterator(); i.hasNext();) {
387: ItemFeedback itemFeedback = (ItemFeedback) i.next();
388: itemFeedbackMap.put(itemFeedback.getTypeId(),
389: itemFeedback.getText());
390: }
391: }
392: return itemFeedbackMap;
393: }
394:
395: private void writeObject(java.io.ObjectOutputStream out)
396: throws IOException {
397: out.defaultWriteObject();
398: }
399:
400: private void readObject(java.io.ObjectInputStream in)
401: throws IOException, ClassNotFoundException {
402: in.defaultReadObject();
403: }
404:
405: public void addItemText(String text, Set answerSet) {
406: if (this .itemTextSet == null) {
407: this .itemTextSet = new HashSet();
408: }
409: Long sequence = new Long(this .itemTextSet.size() + 1);
410: ItemText itemText = new ItemText(this , sequence, text,
411: answerSet);
412: this .itemTextSet.add(itemText);
413: }
414:
415: public String getItemMetaDataByLabel(String label) {
416: return (String) this .itemMetaDataMap.get(label);
417: }
418:
419: public void addItemMetaData(String label, String entry) {
420: if (this .itemMetaDataSet == null) {
421: setItemMetaDataSet(new HashSet());
422: this .itemMetaDataMap = new HashMap();
423: }
424: this .itemMetaDataMap.put(label, entry);
425: this .itemMetaDataSet.add(new ItemMetaData(this , label, entry));
426: }
427:
428: public String getCorrectItemFeedback() {
429: return getItemFeedback(ItemFeedback.CORRECT_FEEDBACK);
430: }
431:
432: public void setCorrectItemFeedback(String text) {
433: removeFeedbackByType(ItemFeedback.CORRECT_FEEDBACK);
434: addItemFeedback(ItemFeedback.CORRECT_FEEDBACK, text);
435: }
436:
437: public String getInCorrectItemFeedback() {
438: return getItemFeedback(ItemFeedback.INCORRECT_FEEDBACK);
439: }
440:
441: public void setInCorrectItemFeedback(String text) {
442: removeFeedbackByType(ItemFeedback.INCORRECT_FEEDBACK);
443: addItemFeedback(ItemFeedback.INCORRECT_FEEDBACK, text);
444: }
445:
446: /**
447: * Get General Feedback
448: * @return
449: */
450: public String getGeneralItemFeedback() {
451: return getItemFeedback(ItemFeedback.GENERAL_FEEDBACK);
452: }
453:
454: /**
455: * Set General Feedback
456: * @param text
457: */
458: public void setGeneralItemFeedback(String text) {
459: removeFeedbackByType(ItemFeedback.GENERAL_FEEDBACK);
460: addItemFeedback(ItemFeedback.GENERAL_FEEDBACK, text);
461: }
462:
463: public String getItemFeedback(String typeId) {
464: if (this .itemFeedbackMap == null)
465: this .itemFeedbackMap = getItemFeedbackMap(this .itemFeedbackSet);
466: return (String) this .itemFeedbackMap.get(typeId);
467: }
468:
469: public void addItemFeedback(String typeId, String text) {
470: if (this .itemFeedbackSet == null) {
471: setItemFeedbackSet(new HashSet());
472: this .itemFeedbackMap = new HashMap();
473: }
474: this .itemFeedbackMap.put(typeId, text);
475: this .itemFeedbackSet.add(new ItemFeedback(this , typeId, text));
476: }
477:
478: public void removeFeedbackByType(String typeId) {
479: if (itemFeedbackSet != null) {
480: for (Iterator i = this .itemFeedbackSet.iterator(); i
481: .hasNext();) {
482: ItemFeedback itemFeedback = (ItemFeedback) i.next();
483: if (itemFeedback.getTypeId().equals(typeId)) {
484: //this.itemFeedbackSet.remove(itemFeedback);
485: i.remove();
486: }
487: }
488: }
489: }
490:
491: public void removeMetaDataByType(String label) {
492: try {
493: if (itemMetaDataSet != null) {
494: for (Iterator i = this .itemMetaDataSet.iterator(); i
495: .hasNext();) {
496: ItemMetaData itemMetaData = (ItemMetaData) i.next();
497: if (itemMetaData.getLabel().equals(label)) {
498: //this.itemMetaDataSet.remove(itemMetaData);
499: i.remove();
500: }
501: }
502: }
503: } catch (Exception e) {
504: e.printStackTrace();
505: }
506: }
507:
508: /**
509: * If this is a true-false question return true if it is true, else false.
510: * If it is not a true-false question return false.
511: * @return true if this is a true true-false question
512: */
513: public Boolean getIsTrue() {
514: // if not true false, done.
515: if (!this .getTypeId().equals(TypeD.TRUE_FALSE)) {
516: return Boolean.FALSE;
517: }
518:
519: Set answerSet = null;
520:
521: Set set = this .getItemTextSet();
522: Iterator iter = set.iterator();
523: if (iter.hasNext()) {
524: answerSet = ((ItemTextIfc) iter.next()).getAnswerSet();
525: }
526:
527: // if the FIRST answer is CORRECT, the true false question is TRUE
528: // Note that this is implementation dependent
529: if (answerSet != null) {
530: Iterator aiter = answerSet.iterator();
531: if (aiter.hasNext()) {
532: AnswerIfc answer = (AnswerIfc) aiter.next();
533: return answer.getIsCorrect();
534: }
535: }
536:
537: return Boolean.FALSE;
538:
539: }
540:
541: /**
542: * In the case of an ordinary question, this will obtain the a set of text with
543: * one element and return it; in FIB or FIN return multiple elements separated by underscores.
544: * @return text of question
545: */
546: public String getText() {
547: String text = "";
548: if (getTypeId().equals(TypeIfc.MATCHING))
549: return instruction;
550: Set set = this .getItemTextSet();
551: Iterator iter = set.iterator();
552:
553: while (iter.hasNext()) {
554: ItemTextIfc itemText = (ItemTextIfc) iter.next();
555: text += "" + itemText.getText(); //each text add it in
556:
557: if (this .getTypeId().equals(TypeIfc.FILL_IN_BLANK)) { //e.g. Roses are {}. Violets are {}. replace as
558: // Roses are ____. Violets are ____.
559: text = text.replaceAll("\\{", "__");
560: text = text.replaceAll("\\}", "__");
561: }
562:
563: if (this .getTypeId().equals(TypeIfc.FILL_IN_NUMERIC)) { //e.g. Roses are {}. Violets are {}. replace as
564: // Roses are ____. Violets are ____.
565: text = text.replaceAll("\\{", "__");
566: text = text.replaceAll("\\}", "__");
567: }
568: }
569: return text;
570: }
571:
572: public TypeIfc getType() {
573: /*
574: TypeFacadeQueriesAPI typeFacadeQueries = PersistenceService.getInstance().getTypeFacadeQueries();
575: TypeIfc type = typeFacadeQueries.getTypeFacadeById(this.typeId);
576: TypeD typeD = new TypeD(type.getAuthority(), type.getDomain(),
577: type.getKeyword(), type.getDescription());
578: typeD.setTypeId(this.typeId);
579: return typeD;
580: */
581: return null;
582: }
583:
584: public ArrayList getItemTextArray() {
585: ArrayList list = new ArrayList();
586: Iterator iter = itemTextSet.iterator();
587: while (iter.hasNext()) {
588: list.add(iter.next());
589: }
590: return list;
591: }
592:
593: public ArrayList getItemTextArraySorted() {
594: ArrayList list = getItemTextArray();
595: Collections.sort(list);
596: return list;
597: }
598:
599: public void setTriesAllowed(Integer triesAllowed) {
600: this .triesAllowed = triesAllowed;
601: }
602:
603: public Integer getTriesAllowed() {
604: return this .triesAllowed;
605: }
606:
607: /**
608: * This method return the answerKey for a matching question
609: * e.g. A:2, B:3, C:1, D:4 (where A, B & C is the answer label and 1,2 &3
610: * are the itemText sequence
611: * Added by Huong Nguyen for other types as well.
612: */
613: public String getAnswerKey() {
614: String answerKey = "";
615: ArrayList itemTextArray = getItemTextArraySorted();
616: if (itemTextArray.size() == 0)
617: return answerKey;
618:
619: ArrayList answerArray = ((ItemTextIfc) itemTextArray.get(0))
620: .getAnswerArraySorted();
621: HashMap h = new HashMap();
622:
623: for (int i = 0; i < itemTextArray.size(); i++) {
624: ItemTextIfc text = (ItemTextIfc) itemTextArray.get(i);
625: ArrayList answers = text.getAnswerArraySorted();
626: for (int j = 0; j < answers.size(); j++) {
627: AnswerIfc a = (AnswerIfc) answers.get(j);
628: if ((Boolean.TRUE).equals(a.getIsCorrect())) {
629: String pair = (String) h.get(a.getLabel());
630: if (!this .getTypeId().equals(TypeD.MATCHING)) {
631: if (this .getTypeId().equals(TypeD.TRUE_FALSE)) {
632: answerKey = a.getText();
633: } else {
634: if (("").equals(answerKey)) {
635: answerKey = a.getLabel();
636: } else {
637: answerKey += "," + a.getLabel();
638: }
639: }
640: }
641:
642: else {
643:
644: if (pair == null) {
645: String s = a.getLabel() + ":"
646: + text.getSequence();
647: h.put(a.getLabel(), s);
648: } else {
649: h.put(a.getLabel(), pair + " "
650: + text.getSequence());
651: }
652: }
653: }
654: }
655: }
656:
657: if (this .getTypeId().equals(TypeD.MATCHING)) {
658: for (int k = 0; k < answerArray.size(); k++) {
659: AnswerIfc a = (AnswerIfc) answerArray.get(k);
660: String pair = (String) h.get(a.getLabel());
661: //if answer is not a match to any text, just print answer label
662: if (pair == null)
663: pair = a.getLabel() + ": ";
664:
665: if (k != 0)
666: answerKey = answerKey + ", " + pair;
667: else
668:
669: answerKey = pair;
670: }
671: }
672:
673: return answerKey;
674:
675: }
676:
677: public int compareTo(Object o) {
678: ItemData a = (ItemData) o;
679: return sequence.compareTo(a.sequence);
680: }
681:
682: public boolean getGeneralItemFbIsNotEmpty() {
683: return isNotEmpty(getGeneralItemFeedback());
684: }
685:
686: public boolean getCorrectItemFbIsNotEmpty() {
687: return isNotEmpty(getCorrectItemFeedback());
688: }
689:
690: public boolean getIncorrectItemFbIsNotEmpty() {
691: return isNotEmpty(getInCorrectItemFeedback());
692: }
693:
694: public boolean isNotEmpty(String wyzText) {
695:
696: if (wyzText != null) {
697: int index = 0;
698: String t = (wyzText.replaceAll("<.*?>", " ")).trim();
699: while (index < t.length()) {
700: char c = t.charAt(index);
701: if (Character.isLetterOrDigit(c)) {
702: return true;
703: }
704: index++;
705: }
706: }
707: return false;
708: }
709:
710: public Set getItemAttachmentSet() {
711: return itemAttachmentSet;
712: }
713:
714: public void setItemAttachmentSet(Set itemAttachmentSet) {
715: this .itemAttachmentSet = itemAttachmentSet;
716: }
717:
718: public List getItemAttachmentList() {
719: ArrayList list = new ArrayList();
720: if (itemAttachmentSet != null) {
721: Iterator iter = itemAttachmentSet.iterator();
722: while (iter.hasNext()) {
723: ItemAttachmentIfc a = (ItemAttachmentIfc) iter.next();
724: list.add(a);
725: }
726: }
727: return list;
728: }
729:
730: }
|