001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/sam/trunk/component/src/java/org/sakaiproject/tool/assessment/business/questionpool/QuestionPoolTreeImpl.java $
003: * $Id: QuestionPoolTreeImpl.java 9273 2006-05-10 22:34:28Z daisyf@stanford.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 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.tool.assessment.business.questionpool;
021:
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Collections;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.osid.shared.SharedException;
033:
034: import org.sakaiproject.tool.assessment.data.dao.questionpool.QuestionPoolData;
035: import org.sakaiproject.tool.assessment.data.model.Tree;
036: import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade;
037: import org.sakaiproject.tool.assessment.facade.QuestionPoolIteratorFacade;
038: import org.sakaiproject.tool.assessment.util.BeanSort;
039:
040: //import org.sakaiproject.tool.assessment.osid.shared.impl.IdImpl;
041: //import osid.shared.*;
042: // import org.osid.shared.Id; // should only use Long for id.
043:
044: /**
045: * DOCUMENTATION PENDING
046: *
047: * @author $author$
048: * @version $Id: QuestionPoolTreeImpl.java 9273 2006-05-10 22:34:28Z daisyf@stanford.edu $
049: */
050: public class QuestionPoolTreeImpl implements Tree {
051:
052: /**
053: *
054: */
055: private static final long serialVersionUID = 2173986944623441011L;
056:
057: private static Log log = LogFactory
058: .getLog(QuestionPoolTreeImpl.class);
059:
060: private HashMap poolMap;
061: private HashMap poolFamilies;
062: private Long currentPoolId;
063: private String currentObjectHTMLId;
064: private String currentLevel;
065: private String sortString = "lastModified";
066:
067: public QuestionPoolTreeImpl() {
068: poolMap = new HashMap();
069: poolFamilies = new HashMap();
070: }
071:
072: /**
073: * Constucts the representation of the tree of pools.
074: * @param iter QuestionPoolIteratorFacade for the pools in question
075: */
076: public QuestionPoolTreeImpl(QuestionPoolIteratorFacade iter) {
077: // this is a table of pools by Id
078: poolMap = new HashMap();
079:
080: // this is a cross reference of pool ids by parent id
081: // the pool ids in an Arraylist where the key is parent id
082: poolFamilies = new HashMap();
083:
084: try {
085: while (iter.hasNext()) {
086: QuestionPoolFacade pool = (QuestionPoolFacade) iter
087: .next();
088:
089: Long parentId = pool.getParentPoolId();
090:
091: Long poolId = pool.getQuestionPoolId();
092: poolMap.put(poolId.toString(), pool);
093: ArrayList childList = new ArrayList();
094: if (poolFamilies.containsKey(parentId.toString())) {
095: childList = (ArrayList) poolFamilies.get(parentId
096: .toString());
097: }
098:
099: childList.add(poolId);
100: poolFamilies.put(parentId.toString(), childList);
101: }
102:
103: // Now sort the sibling lists.
104: Iterator iter2 = poolFamilies.keySet().iterator();
105: while (iter2.hasNext()) {
106: String key = (String) iter2.next();
107: Iterator children = ((ArrayList) poolFamilies.get(key))
108: .iterator();
109: Collection sortedList = new ArrayList();
110: while (children.hasNext()) {
111: QuestionPoolFacade pool = (QuestionPoolFacade) poolMap
112: .get(children.next().toString());
113: sortedList.add(pool.getData());
114: }
115:
116: BeanSort sort = new BeanSort(sortedList, sortString);
117: sortedList = sort.sort();
118: ArrayList ids = new ArrayList();
119: Iterator siblings = sortedList.iterator();
120: while (siblings.hasNext()) {
121: QuestionPoolData next = null;
122: try {
123: next = (QuestionPoolData) siblings.next();
124: if (poolMap != null) {
125: // Add at 0 because we want a reverse list.
126: if (sortString.equals("lastModified")) {
127: ids
128: .add(
129: 0,
130: ((QuestionPoolFacade) poolMap
131: .get(next
132: .getQuestionPoolId()
133: .toString()))
134: .getQuestionPoolId());
135: }
136: // Add to the end of list if not sorted by lastModified.
137: else {
138: ids.add(((QuestionPoolFacade) poolMap
139: .get(next.getQuestionPoolId()
140: .toString()))
141: .getQuestionPoolId());
142: }
143: } else {
144: log.error("poolMap is null");
145: }
146: } catch (RuntimeException e) {
147: log.error("Couldn't get ID "
148: + next.getQuestionPoolId());
149: }
150: }
151: poolFamilies.put(key, ids);
152: }
153: } catch (SharedException se) {
154: se.printStackTrace();
155: } catch (RuntimeException e) {
156: e.printStackTrace();
157: }
158: }
159:
160: /**
161: * Get a List of pools having parentId as parent
162: * @param parentId the Id of the parent pool
163: * @return a List with the Ids of all momma's children
164: */
165: public List getChildList(Long parentId) {
166: if (!poolFamilies.containsKey(parentId.toString())) {
167: return new ArrayList();
168: }
169:
170: return (ArrayList) poolFamilies.get(parentId.toString());
171: }
172:
173: /**
174: * Get a List of top level pools.
175: * @return List of top level pool id strings
176: */
177: public List getRootNodeList() {
178: try {
179:
180: return getChildList(new Long("0"));
181: } catch (Exception e) {
182: e.printStackTrace();
183: return null;
184: }
185: }
186:
187: /**
188: * Get the object we're currently looking at.
189: *
190: * @return Current QuestionPool.
191: */
192: public Object getCurrentObject() {
193: return poolMap.get(currentPoolId.toString());
194: }
195:
196: /**
197: * Get the parent of the object we're currently looking at.
198: *
199: * @return The parent pool of the current object, or null if
200: * it's a root node.
201: */
202: public Object getParent() {
203: if (currentPoolId == null) {
204: return null;
205: }
206:
207: QuestionPoolFacade current = (QuestionPoolFacade) getCurrentObject();
208: try {
209: return (poolMap.get(current.getParentPoolId().toString()));
210: } catch (Exception e) {
211: e.printStackTrace();
212:
213: return null;
214: }
215:
216: }
217:
218: public void setCurrentObjectHTMLId(String param) {
219: currentObjectHTMLId = param;
220: }
221:
222: /**
223: * Get the HTML id of the current object.
224: *
225: * @return An HTML representation of the pool Id.
226: */
227: public String getCurrentObjectHTMLId() {
228: QuestionPoolFacade current = (QuestionPoolFacade) getCurrentObject();
229: try {
230: QuestionPoolFacade parent = (QuestionPoolFacade) getParent();
231: if (parent == null) {
232: Collection childList = getChildList(new Long("0"));
233:
234: return Integer
235: .toString(((ArrayList) childList)
236: .indexOf(((QuestionPoolFacade) getCurrentObject())
237: .getQuestionPoolId()) + 1);
238: } else {
239: setCurrentId(current.getParentPoolId());
240: String result = getCurrentObjectHTMLId();
241: Collection childList = getChildList(parent
242: .getQuestionPoolId());
243: setCurrentId(current.getQuestionPoolId());
244:
245: return result
246: + "-"
247: + (((ArrayList) childList)
248: .indexOf(((QuestionPoolFacade) getCurrentObject())
249: .getQuestionPoolId()) + 1);
250: }
251: }
252:
253: catch (RuntimeException e) {
254: e.printStackTrace();
255: return "0";
256: }
257:
258: }
259:
260: /**
261: * Get the current level.
262: *
263: * @return A String that represents the level we're on (1 is root node,
264: * 2 is first level child, etc..
265: */
266: public String getCurrentLevel() {
267: int index1 = 1;
268: QuestionPoolFacade current = (QuestionPoolFacade) getCurrentObject();
269: try {
270: while (!current.getParentPoolId().toString().equals("0")) {
271: current = (QuestionPoolFacade) poolMap.get(current
272: .getParentPoolId().toString());
273: index1++;
274: }
275:
276: //QuestionPoolFacade parent = (QuestionPoolFacade) getParent();
277: }
278:
279: catch (Exception e) {
280: e.printStackTrace();
281: return "0";
282: }
283:
284: return Integer.toString(index1);
285: }
286:
287: /**
288: * Return in order the current:<ul>
289: * <li> Pool Name
290: * <li> Author
291: * <li> Last Modified
292: * <li> Total # of Questions
293: * <li> Total # of Subpools
294: */
295: public Collection getCurrentObjectProperties() {
296: Collection properties = new ArrayList();
297: /*
298: // not used anymore,
299:
300: if(currentPoolId == null)
301: {
302: properties.add("Pool Name");
303: properties.add("Author");
304: properties.add("Last Modified");
305: properties.add("Total # of Questions");
306: properties.add("Total # of Subpools");
307: }
308: else
309: {
310: try
311: {
312: QuestionPoolFacade pool = (QuestionPoolFacade) getCurrentObject();
313: QuestionPoolData props = (QuestionPoolData) pool.getData();
314: if(props == null)
315: {
316: props = new QuestionPoolData();
317: }
318:
319: //properties.add(pool.getDisplayName());
320:
321: // commenting the following temporarily because getOwner is null - daisyf (9/19/04)
322: properties.add(props.getOwner().getDisplayName());
323:
324: if(props.getLastModified() != null)
325: {
326: // SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
327: // properties.add(sdf.format(props.getLastModified()));
328: properties.add(props.getLastModified());
329:
330: }
331: else
332: {
333: properties.add("N/A");
334: }
335:
336: if(props.getQuestions() != null)
337: {
338: properties.add(new Integer(props.getQuestions().size()).toString());
339: }
340: else
341: {
342: properties.add("0");
343: }
344:
345: if(getChildren(currentPoolId) != null)
346: {
347: properties.add(
348: new Integer(getChildren(currentPoolId).size()).toString());
349: }
350: else
351: {
352: properties.add("0");
353: }
354: }
355: catch(Exception e)
356: {
357: e.printStackTrace();
358: throw new RuntimeException(e);
359:
360: }
361: }
362:
363: */
364: return properties;
365: }
366:
367: /**
368: * Set the properties to request. Not needed here.
369: */
370: public void setPropertyMethods(String[] methods) {
371: }
372:
373: /**
374: * Get Map of QuestionPoolImpls.
375: * @return Map of all QuestionPoolImpls
376: */
377: public Map getAllObjects() {
378: return poolMap;
379: }
380:
381: /**
382: * Dump the tree into a long collection of objects of the form:<ul>
383: * <li> Pool 1
384: * <ul> <li> Pool 2
385: * <ul> <li> Pool 3
386: * <li> Pool 4
387: * </ul><li> Pool 5
388: *
389: */
390: public Collection getSortedObjects() {
391: Collection total = new ArrayList();
392: try {
393: addChildren(total, new Long("0"));
394: } catch (Exception e) {
395: e.printStackTrace();
396: throw new RuntimeException(e);
397: }
398:
399: return total;
400: }
401:
402: /**
403: * get sorted objects for a subpool tree
404: */
405: public Collection getSortedObjects(Long poolId) {
406: Collection total = new ArrayList();
407: try {
408: addChildren(total, poolId);
409: } catch (Exception e) {
410: e.printStackTrace();
411: throw new RuntimeException(e);
412: }
413:
414: return total;
415: }
416:
417: /**
418: * Auxiliary method for recursion.
419: */
420: private void addChildren(Collection total, Long parentId) {
421: List childList = getChildList(parentId);
422: if (childList.isEmpty()) {
423: return;
424: }
425:
426: Iterator iter = childList.iterator();
427: while (iter.hasNext()) {
428: Long nextId = (Long) iter.next();
429: total.add(poolMap.get(nextId.toString()));
430: addChildren(total, nextId);
431: }
432: }
433:
434: /**
435: * Get Map of QuestionPoolImpls retricted to a given
436: * Parent Id string
437: * @param parentId parent of all returned children
438: * @return a Map of QuestionPoolImpls that are childen
439: */
440: public Map getChildren(Long parentId) {
441: HashMap childPool = new HashMap();
442: List childList = getChildList(parentId);
443: Iterator children = childList.iterator();
444:
445: while (children.hasNext()) {
446: Long poolId = (Long) children.next();
447: childPool.put(poolId.toString(), poolMap.get(poolId
448: .toString()));
449: }
450:
451: return childPool;
452: }
453:
454: /**
455: * Get Map of QuestionPoolImpls retricted to childeren of the currently
456: * selected pool Id string
457: * @return a Map of QuestionPoolImpls that are children
458: */
459: public Map getChildren() {
460: return getChildren(getCurrentId());
461: }
462:
463: /**
464: * Obtain the poolId set as the current working poolId-designated node
465: * @return the current working poolId String
466: */
467: public Long getCurrentId() {
468: return currentPoolId;
469: }
470:
471: /**
472: * Set the current working poolId String, from which context relative
473: * child lists are calculated from the poolId-designated node
474: * @param poolId
475: */
476: public void setCurrentId(Long poolId) {
477: currentPoolId = poolId;
478: }
479:
480: /**
481: * Determine if the pool has childeren
482: * @return true if it has children
483: */
484: public boolean currentObjectIsParent() {
485: return poolFamilies.containsKey(getCurrentId().toString());
486: }
487:
488: /**
489: * List the child pool id strings
490: * @return a list of children's pool id strings
491: */
492: public List getChildList() {
493: return getChildList(getCurrentId());
494: }
495:
496: /**
497: * @return true if childlist is not empty, false otherwise
498: */
499: public boolean getHasChildList() {
500: if (this .getChildList().isEmpty()) {
501: return false;
502: } else {
503: return true;
504: }
505: }
506:
507: public boolean getHasNoChildList() {
508: if (this .getChildList().isEmpty()) {
509: return true;
510: } else {
511: return false;
512: }
513: }
514:
515: /**
516: * This gets the property by which siblings will be sorted.
517: *
518: * @return A String representation of the sort property.
519: */
520: public String getSortProperty() {
521: return sortString;
522: }
523:
524: /**
525: * This sets the property by which siblings will be sorted.
526: */
527: public void setSortProperty(String newProperty) {
528: sortString = newProperty;
529: }
530:
531: public void sortByProperty(String sortProperty,
532: boolean sortAscending) {
533: // Now sort the sibling lists.
534: Iterator iter2 = poolFamilies.keySet().iterator();
535: while (iter2.hasNext()) {
536: String key = (String) iter2.next();
537: Iterator children = ((ArrayList) poolFamilies.get(key))
538: .iterator();
539: ArrayList sortedList = new ArrayList();
540: while (children.hasNext()) {
541: QuestionPoolFacade pool = (QuestionPoolFacade) poolMap
542: .get(children.next().toString());
543: sortedList.add(pool.getData());
544: }
545:
546: BeanSort sort = new BeanSort(sortedList, sortProperty);
547:
548: if (sortProperty.equals("lastModified")) {
549: sort.toDateSort();
550: } else {
551: sort.toStringSort();
552: }
553:
554: sort.sort();
555:
556: if (!sortAscending) {
557: Collections.reverse(sortedList);
558: }
559:
560: ArrayList ids = new ArrayList();
561: Iterator siblings = sortedList.iterator();
562: while (siblings.hasNext()) {
563: QuestionPoolData next = null;
564: try {
565: next = (QuestionPoolData) siblings.next();
566: if (next != null) {
567: // Add at 0 because we want a reverse list.
568: if (sortProperty.equals("lastModified")) {
569: ids.add(0, ((QuestionPoolFacade) poolMap
570: .get(next.getQuestionPoolId()
571: .toString()))
572: .getQuestionPoolId());
573: } else {
574: // Add at the end , if not sorted by lastModified.
575: ids.add(((QuestionPoolFacade) poolMap
576: .get(next.getQuestionPoolId()
577: .toString()))
578: .getQuestionPoolId());
579: }
580: } else {
581: log.error("next is null");
582: }
583: } catch (RuntimeException e) {
584: log.error("Couldn't get ID "
585: + next.getQuestionPoolId());
586: }
587: }
588:
589: poolFamilies.put(key, ids);
590: }
591:
592: }
593:
594: /**
595: * THis checks to see if given two pools have a common ancestor
596: */
597: public boolean haveCommonRoot(Long poolIdA, Long poolIdB) {
598: try {
599: Long rootA = poolIdA;
600: Long rootB = poolIdB;
601:
602: QuestionPoolFacade tempPool = (QuestionPoolFacade) poolMap
603: .get(rootA.toString());
604: while (tempPool != null) {
605: if ((tempPool.getParentPoolId() == null)
606: || (((tempPool.getParentPoolId()).toString())
607: .equals("0"))) {
608: tempPool = null;
609: } else {
610: rootA = tempPool.getParentPoolId();
611: tempPool = (QuestionPoolFacade) poolMap.get(rootA
612: .toString());
613: }
614: }
615: tempPool = (QuestionPoolFacade) poolMap.get(rootB
616: .toString());
617: while (tempPool != null) {
618: if ((tempPool.getParentPoolId() == null)
619: || (((tempPool.getParentPoolId()).toString())
620: .equals("0"))) {
621: tempPool = null;
622: } else {
623: rootB = tempPool.getParentPoolId();
624: tempPool = (QuestionPoolFacade) poolMap.get(rootB
625: .toString());
626: }
627: }
628: return rootA.equals(rootB);
629: } catch (Exception e) {
630: e.printStackTrace();
631: return false;
632: }
633: }
634:
635: /**
636: * Is a pool (pool A) a descendant of the other (Pool B)?
637: */
638: public boolean isDescendantOf(Long poolA, Long poolB) {
639: try {
640: Long tempPoolId = poolA;
641: while ((tempPoolId != null)
642: && (tempPoolId.toString().compareTo("0") > 0)) {
643: QuestionPoolFacade tempPool = (QuestionPoolFacade) poolMap
644: .get(tempPoolId.toString());
645: if (tempPool.getParentPoolId().toString().compareTo(
646: poolB.toString()) == 0)
647: return true;
648: tempPoolId = tempPool.getParentPoolId();
649: }
650: return false;
651:
652: } catch (Exception e) {
653: e.printStackTrace();
654: return false;
655: }
656: }
657:
658: /**
659: * This returns the level of the pool inside a pool tree, Root being 0.
660: */
661: public int poolLevel(Long poolId) {
662: try {
663: Long rootId = poolId;
664: int level = 0;
665:
666: QuestionPoolFacade tempPool = (QuestionPoolFacade) poolMap
667: .get(rootId.toString());
668: while (tempPool != null) {
669: if ((tempPool.getParentPoolId() == null)
670: || (((tempPool.getParentPoolId()).toString())
671: .equals("0"))) {
672: tempPool = null;
673: } else {
674: level++;
675: rootId = tempPool.getParentPoolId();
676: tempPool = (QuestionPoolFacade) poolMap.get(rootId
677: .toString());
678: }
679: }
680: return level;
681: } catch (Exception e) {
682: e.printStackTrace();
683: return 0;
684: }
685: }
686:
687: }
|