001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/postem/tags/sakai_2-4-1/postem-hbm/src/java/org/sakaiproject/component/app/postem/data/GradebookImpl.java $
003: * $Id: GradebookImpl.java 20160 2007-01-08 19:13:32Z rjlowe@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.component.app.postem.data;
021:
022: import java.io.Serializable;
023: import java.sql.Timestamp;
024: import java.text.DateFormat;
025: import java.text.SimpleDateFormat;
026: import java.util.ArrayList;
027: import java.util.Comparator;
028: import java.util.Date;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.Set;
032: import java.util.SortedSet;
033: import java.util.TreeMap;
034: import java.util.TreeSet;
035:
036: import org.apache.commons.math.stat.descriptive.SummaryStatistics;
037: import org.sakaiproject.api.app.postem.data.Gradebook;
038: import org.sakaiproject.api.app.postem.data.StudentGrades;
039: import org.sakaiproject.api.app.postem.data.Template;
040:
041: import org.sakaiproject.user.api.UserNotDefinedException;
042: import org.sakaiproject.user.cover.UserDirectoryService;
043:
044: public class GradebookImpl implements Gradebook, Comparable,
045: Serializable {
046:
047: protected String title;
048:
049: protected String creator;
050:
051: protected String creatorEid;
052:
053: protected Timestamp created;
054:
055: protected String lastUpdater;
056:
057: protected String lastUpdaterEid;
058:
059: protected DateFormat dateFormat = new SimpleDateFormat(
060: "d MMM yyyy HH:mm");
061:
062: protected Timestamp lastUpdated;
063:
064: protected String context;
065:
066: protected String firstUploadedUsername;
067:
068: protected Set students = new TreeSet();
069:
070: protected Template template;
071:
072: protected List headings = new ArrayList();
073:
074: protected Long id;
075:
076: protected Integer lockId;
077:
078: protected Boolean released = new Boolean(false);
079:
080: protected Boolean releaseStatistics = new Boolean(false);
081:
082: private static String units = "px";
083:
084: public static Comparator TitleAscComparator;
085: public static Comparator TitleDescComparator;
086: public static Comparator CreatorAscComparator;
087: public static Comparator CreatorDescComparator;
088: public static Comparator ModByAscComparator;
089: public static Comparator ModByDescComparator;
090: public static Comparator ModDateAscComparator;
091: public static Comparator ModDateDescComparator;
092: public static Comparator ReleasedAscComparator;
093: public static Comparator ReleasedDescComparator;
094:
095: public GradebookImpl() {
096:
097: }
098:
099: public GradebookImpl(String title, String creator, String context,
100: List headings, SortedSet students, Template template) {
101: Timestamp now = new Timestamp(new Date().getTime());
102: this .title = title;
103: this .creator = creator;
104: this .created = now;
105: this .lastUpdater = creator;
106: this .lastUpdated = now;
107: this .context = context;
108: if (headings != null) {
109: this .headings = headings;
110: } else {
111: this .headings = new ArrayList();
112: }
113: if (students != null) {
114: this .students = students;
115: } else {
116: this .students = new TreeSet();
117: }
118: this .template = template;
119: }
120:
121: public Integer getLockId() {
122: return lockId;
123: }
124:
125: public void setLockId(Integer lockId) {
126: this .lockId = lockId;
127: }
128:
129: public String getTitle() {
130: return title;
131: }
132:
133: public void setTitle(String title) {
134: this .title = title;
135: }
136:
137: public String getCreator() {
138: return creator;
139: }
140:
141: public void setCreator(String creator) {
142: this .creator = creator;
143: setCreatorEid(creator);
144:
145: }
146:
147: public String getCreatorEid() {
148: return creatorEid;
149: }
150:
151: public void setCreatorEid(String creatorUserId) {
152: if (creatorUserId != null) {
153: try {
154: this .creatorEid = UserDirectoryService
155: .getUserEid(creatorUserId);
156: } catch (UserNotDefinedException e) {
157: this .creatorEid = null;
158: }
159: }
160: }
161:
162: public Timestamp getCreated() {
163: return created;
164: }
165:
166: public void setCreated(Timestamp created) {
167: this .created = created;
168: }
169:
170: public String getLastUpdater() {
171: return lastUpdater;
172: }
173:
174: public void setLastUpdater(String lastUpdater) {
175: this .lastUpdater = lastUpdater;
176: setLastUpdaterEid(lastUpdater);
177: }
178:
179: public String getLastUpdaterEid() {
180: return lastUpdaterEid;
181: }
182:
183: public void setLastUpdaterEid(String lastUpdaterUserId) {
184: if (lastUpdaterUserId != null) {
185: try {
186: this .lastUpdaterEid = UserDirectoryService
187: .getUserEid(lastUpdaterUserId);
188: } catch (UserNotDefinedException e) {
189: this .lastUpdaterEid = null;
190: }
191: }
192: }
193:
194: public String getUpdatedDateTime() {
195: return dateFormat.format((Date) lastUpdated);
196:
197: }
198:
199: public Timestamp getLastUpdated() {
200: return lastUpdated;
201: }
202:
203: public void setLastUpdated(Timestamp lastUpdated) {
204: this .lastUpdated = lastUpdated;
205: }
206:
207: public String getContext() {
208: return context;
209: }
210:
211: public void setContext(String context) {
212: this .context = context;
213: }
214:
215: public Set getStudents() {
216: return students;
217: }
218:
219: public void setStudents(Set students) {
220: if (students == null) {
221: this .students = new TreeSet();
222: } else {
223: this .students = new TreeSet(students);
224: }
225: }
226:
227: public Template getTemplate() {
228: return template;
229: }
230:
231: public void setTemplate(Template template) {
232: this .template = template;
233: }
234:
235: public List getHeadings() {
236: return headings;
237: }
238:
239: public void setHeadings(List headings) {
240: if (headings == null) {
241: this .headings = new ArrayList();
242: } else {
243: this .headings = headings;
244: }
245: }
246:
247: public Long getId() {
248: return id;
249: }
250:
251: public void setId(Long id) {
252: this .id = id;
253: }
254:
255: public Boolean getReleased() {
256: return released;
257: }
258:
259: public void setReleased(Boolean released) {
260: this .released = released;
261: }
262:
263: public boolean getRelease() {
264: return released.booleanValue();
265: }
266:
267: public void setRelease(boolean release) {
268: this .released = new Boolean(release);
269: }
270:
271: public Boolean getReleaseStatistics() {
272: return releaseStatistics;
273: }
274:
275: public void setReleaseStatistics(Boolean releaseStatistics) {
276: this .releaseStatistics = releaseStatistics;
277: }
278:
279: public boolean getReleaseStats() {
280: return releaseStatistics.booleanValue();
281: }
282:
283: public void setReleaseStats(boolean releaseStats) {
284: this .releaseStatistics = new Boolean(releaseStats);
285: }
286:
287: public void setFirstUploadedUsername(String firstUploadedUsername) {
288: this .firstUploadedUsername = firstUploadedUsername;
289: }
290:
291: public String getFirstUploadedUsername() {
292: return firstUploadedUsername;
293: }
294:
295: public String getHeadingsRow() {
296: List h2 = new ArrayList(headings);
297: h2.remove(0);
298: StringBuffer headingBuffer = new StringBuffer();
299: // headingBuffer.append("<table><tr>");
300: int totalWidth = 0;
301:
302: Iterator jj = h2.iterator();
303: int ii = 0;
304: while (jj.hasNext()) {
305: String current = (String) jj.next();
306: String width = getProperWidth(ii);
307: int iwidth = Integer.parseInt(width.substring(0, width
308: .length() - 2));
309: totalWidth += iwidth;
310: /*headingBuffer.append("<th width='");
311: headingBuffer.append(width);
312: headingBuffer.append("' style='min-width: ");
313: headingBuffer.append(width);
314: headingBuffer.append("; width: ");
315: headingBuffer.append(width);
316: headingBuffer.append(";' >");
317: headingBuffer.append(current);
318: headingBuffer.append("</th>");*/
319: headingBuffer
320: .append("<th style=\"padding: 0.6em;\" scope=\"col\">"
321: + current + "</th>");
322: ii++;
323: }
324: /*StringBuffer newBuffer = new StringBuffer();
325: newBuffer.append("<table width='");
326: newBuffer.append(totalWidth);
327: newBuffer.append("px' style='min-width: ");
328: newBuffer.append(totalWidth);
329: newBuffer.append("px; width: ");
330: newBuffer.append(totalWidth);
331: newBuffer.append("px;' ><tr>");
332: newBuffer.append(headingBuffer);
333:
334: newBuffer.append("</tr></table>");
335: return newBuffer.toString();*/
336: return headingBuffer.toString();
337: }
338:
339: public int compareTo(Object other) {
340: if (this == other)
341: return 0;
342: final Gradebook that = (Gradebook) other;
343:
344: return this .getTitle().compareTo(that.getTitle());
345: }
346:
347: public boolean equals(Object other) {
348: if (this == other)
349: return true;
350: if (!(other instanceof Gradebook))
351: return false;
352: final Gradebook that = (Gradebook) other;
353:
354: return this .getTitle().equals(that.getTitle());
355: }
356:
357: public int hashCode() {
358: return getTitle().hashCode();
359: }
360:
361: public boolean hasStudent(String username) {
362: Iterator iter = getStudents().iterator();
363: while (iter.hasNext()) {
364: if (((StudentGrades) iter.next()).getUsername()
365: .equalsIgnoreCase(username)) {
366: return true;
367: }
368: }
369: return false;
370: }
371:
372: public boolean getHasGrades() {
373: if (students != null && students.size() != 0) {
374: return true;
375: }
376: return false;
377: }
378:
379: public boolean getHasTemplate() {
380: if (template != null) {
381: return true;
382: }
383: return false;
384: }
385:
386: public String getProperWidth(int column) {
387: int maxWidth = 50;
388: int tops = 150;
389: try {
390: List h2 = new ArrayList(headings);
391: h2.remove(0);
392: int hchars = ((String) h2.get(column)).length();
393: int hwidth = hchars * 10;
394: if (hwidth >= tops) {
395: maxWidth = tops;
396: return "" + maxWidth + units;
397: }
398: if (hwidth >= maxWidth) {
399: maxWidth = hwidth;
400: }
401: } catch (Exception exception) {
402: }
403: Iterator iter = getStudents().iterator();
404: while (iter.hasNext()) {
405: StudentGrades sg = (StudentGrades) iter.next();
406: try {
407: int chars = ((String) sg.getGrades().get(column))
408: .length();
409: int width = chars * 10;
410: if (width >= tops) {
411: maxWidth = tops;
412: return "" + maxWidth + units;
413: }
414: if (width >= maxWidth) {
415: maxWidth = width;
416: }
417: } catch (Exception exception) {
418: }
419: }
420: return "" + maxWidth + units;
421: }
422:
423: public List getRawData(int column) {
424:
425: List rawData = new ArrayList();
426:
427: Iterator iter = getStudents().iterator();
428: while (iter.hasNext()) {
429: StudentGrades sg = (StudentGrades) iter.next();
430: try {
431: rawData.add(new Pair(sg.getUsername(), sg.getGrades()
432: .get(column)));
433: } catch (IndexOutOfBoundsException exception) {
434: rawData.add(new Pair(sg.getUsername(), ""));
435: }
436:
437: }
438:
439: return rawData;
440: }
441:
442: public List getAggregateData(int column) throws Exception {
443: List aggregateData = new ArrayList();
444: SummaryStatistics stats = SummaryStatistics.newInstance();
445: int blanks = 0;
446:
447: Iterator iter = getStudents().iterator();
448: while (iter.hasNext()) {
449: StudentGrades sg = (StudentGrades) iter.next();
450: try {
451: String value = (String) sg.getGrades().get(column);
452: if ("".equals(value.trim())) {
453: // TODO: do blanks count as zeros for stats?
454: // stats.addValue(0);
455: blanks++;
456: } else {
457: stats.addValue(Double.parseDouble(value));
458: }
459: } catch (IndexOutOfBoundsException exception) {
460: blanks++;
461: }
462:
463: }
464: aggregateData.add(new Pair("Average", new Double(stats
465: .getMean())));
466: aggregateData.add(new Pair("Std. Dev.", new Double(stats
467: .getStandardDeviation())));
468: aggregateData.add(new Pair("Highest",
469: new Double(stats.getMax())));
470: aggregateData
471: .add(new Pair("Lowest", new Double(stats.getMin())));
472: aggregateData.add(new Pair("Range", new Double(stats.getMax()
473: - stats.getMin())));
474: aggregateData.add(new Pair("N=count(non-blank)", new Double(
475: stats.getN())));
476: aggregateData
477: .add(new Pair("count(blank)", new Integer(blanks)));
478:
479: return aggregateData;
480: }
481:
482: public StudentGrades studentGrades(String username) {
483: Iterator iter = getStudents().iterator();
484: while (iter.hasNext()) {
485: StudentGrades current = (StudentGrades) iter.next();
486: if (current.getUsername().equalsIgnoreCase(username)) {
487: return current;
488: }
489: }
490: return null;
491: }
492:
493: public TreeMap getStudentMap() {
494: TreeMap studentMap = new TreeMap();
495: studentMap.put(" ", "blank");
496:
497: Iterator iter = getStudents().iterator();
498: while (iter.hasNext()) {
499: StudentGrades ss = (StudentGrades) iter.next();
500: studentMap.put(ss.getUsername(), ss.getUsername());
501: }
502: return studentMap;
503: }
504:
505: private static int compareTitles(Gradebook gradebook,
506: Gradebook otherGradebook) {
507: String title1 = gradebook.getTitle().toUpperCase();
508: String title2 = otherGradebook.getTitle().toUpperCase();
509:
510: int val = title1.compareTo(title2);
511: if (val != 0)
512: return val;
513: else
514: return 1; //we want "Test" and "test" to appear together
515: }
516:
517: static {
518: // We have to be careful because the gradebooks use the "SortedSet" structure
519: // that will only accept one occurrence if the items being compared are equal
520:
521: TitleAscComparator = new Comparator() {
522: public int compare(Object gradebook, Object otherGradebook) {
523: return compareTitles((Gradebook) gradebook,
524: (Gradebook) otherGradebook);
525: }
526: };
527:
528: TitleDescComparator = new Comparator() {
529: public int compare(Object gradebook, Object otherGradebook) {
530: return compareTitles((Gradebook) otherGradebook,
531: (Gradebook) gradebook);
532: }
533: };
534:
535: CreatorAscComparator = new Comparator() {
536: public int compare(Object gradebook, Object otherGradebook) {
537: String creator1 = ((Gradebook) gradebook)
538: .getCreatorEid().toUpperCase();
539: String creator2 = ((Gradebook) otherGradebook)
540: .getCreatorEid().toUpperCase();
541:
542: if (creator1.equals(creator2)) {
543: return compareTitles((Gradebook) gradebook,
544: (Gradebook) otherGradebook);
545: }
546:
547: return creator1.compareTo(creator2);
548: }
549: };
550:
551: CreatorDescComparator = new Comparator() {
552: public int compare(Object gradebook, Object otherGradebook) {
553: String creator1 = ((Gradebook) gradebook)
554: .getCreatorEid().toUpperCase();
555: String creator2 = ((Gradebook) otherGradebook)
556: .getCreatorEid().toUpperCase();
557:
558: if (creator1.equals(creator2)) {
559: return compareTitles((Gradebook) gradebook,
560: (Gradebook) otherGradebook);
561: }
562:
563: return creator2.compareTo(creator1);
564: }
565: };
566:
567: ModByAscComparator = new Comparator() {
568: public int compare(Object gradebook, Object otherGradebook) {
569: String modBy1 = ((Gradebook) gradebook)
570: .getLastUpdaterEid().toUpperCase();
571: String modBy2 = ((Gradebook) otherGradebook)
572: .getLastUpdaterEid().toUpperCase();
573:
574: if (modBy1.equals(modBy2)) {
575: return compareTitles((Gradebook) gradebook,
576: (Gradebook) otherGradebook);
577: }
578:
579: return modBy1.compareTo(modBy2);
580: }
581: };
582:
583: ModByDescComparator = new Comparator() {
584: public int compare(Object gradebook, Object otherGradebook) {
585: String modBy1 = ((Gradebook) gradebook)
586: .getLastUpdaterEid().toUpperCase();
587: String modBy2 = ((Gradebook) otherGradebook)
588: .getLastUpdaterEid().toUpperCase();
589:
590: if (modBy1.equals(modBy2)) {
591: return compareTitles((Gradebook) gradebook,
592: (Gradebook) otherGradebook);
593: }
594:
595: return modBy2.compareTo(modBy1);
596: }
597: };
598:
599: ModDateAscComparator = new Comparator() {
600: public int compare(Object gradebook, Object otherGradebook) {
601: Timestamp modDate1 = ((Gradebook) gradebook)
602: .getLastUpdated();
603: Timestamp modDate2 = ((Gradebook) otherGradebook)
604: .getLastUpdated();
605:
606: if (modDate1.equals(modDate2)) {
607: return compareTitles((Gradebook) gradebook,
608: (Gradebook) otherGradebook);
609: }
610:
611: return modDate1.compareTo(modDate2);
612: }
613: };
614:
615: ModDateDescComparator = new Comparator() {
616: public int compare(Object gradebook, Object otherGradebook) {
617: Timestamp modDate1 = ((Gradebook) gradebook)
618: .getLastUpdated();
619: Timestamp modDate2 = ((Gradebook) otherGradebook)
620: .getLastUpdated();
621:
622: if (modDate1.equals(modDate2)) {
623: return compareTitles((Gradebook) gradebook,
624: (Gradebook) otherGradebook);
625: }
626:
627: return modDate2.compareTo(modDate1);
628: }
629: };
630:
631: ReleasedAscComparator = new Comparator() {
632: public int compare(Object gradebook, Object otherGradebook) {
633: boolean released1 = ((Gradebook) gradebook)
634: .getRelease();
635: boolean released2 = ((Gradebook) otherGradebook)
636: .getRelease();
637:
638: if (released1 == released2)
639: return compareTitles((Gradebook) gradebook,
640: (Gradebook) otherGradebook);
641: else if (released1 && !released2)
642: return -1;
643: else
644: return 1;
645: }
646: };
647:
648: ReleasedDescComparator = new Comparator() {
649: public int compare(Object gradebook, Object otherGradebook) {
650: boolean released1 = ((Gradebook) gradebook)
651: .getRelease();
652: boolean released2 = ((Gradebook) otherGradebook)
653: .getRelease();
654:
655: if (released1 == released2) {
656: return compareTitles((Gradebook) gradebook,
657: (Gradebook) otherGradebook);
658: } else if (released1 && !released2)
659: return 1;
660: else
661: return -1;
662: }
663: };
664:
665: }
666: }
|