/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/author/SectionBean.java $ * $Id: SectionBean.java 128687 2013-08-20 18:46:26Z ktsao@stanford.edu $ *********************************************************************************** * * Copyright (c) 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.tool.assessment.ui.bean.author; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.text.Collator; import java.text.ParseException; import java.text.RuleBasedCollator; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.event.ValueChangeEvent; import javax.faces.model.SelectItem; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.content.api.ContentResource; import org.sakaiproject.content.api.FilePickerHelper; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entity.cover.EntityManager; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.exception.TypeException; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.AttachmentIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.SectionDataIfc; import org.sakaiproject.tool.assessment.facade.AgentFacade; import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade; import org.sakaiproject.tool.assessment.facade.SectionFacade; import org.sakaiproject.tool.assessment.services.QuestionPoolService; import org.sakaiproject.tool.assessment.services.assessment.AssessmentService; import org.sakaiproject.tool.assessment.services.assessment.PublishedAssessmentService; import org.sakaiproject.tool.assessment.ui.listener.author.SavePartAttachmentListener; import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.util.FormattedText; import org.sakaiproject.util.ResourceLoader; public class SectionBean implements Serializable { private static Log log = LogFactory.getLog(SectionBean.class); /** Use serialVersionUID for interoperability. */ private final static long serialVersionUID = 4216587136245498157L; private String assessmentTitle; private String assessmentId; private String showMetadata; private String sectionId; private String noOfItems; private String sectionTitle; private String sectionDescription; private ArrayList assessmentSectionIdents; private ArrayList poolsAvailable; // selectItems for pools private ArrayList items; private boolean random; private String randomPartScore; private String randomPartDiscount; private String removeAllQuestions; // 1=Yes, 0=No private SectionFacade section; private AssessmentIfc assessment; private String destSectionId; //destinated section where questions will be moved to private String randomizationType; private boolean pointValueHasOverrided; private boolean discountValueHasOverrided; private String numberSelected; private String selectedPool; // pool id for the item to be added to private String objective; private String keyword; private String rubric; private String type; private String questionOrdering; private boolean hideRandom = false; private boolean hideOneByOne= false; private String outcome; private List attachmentList; public void setSection(SectionFacade section) { try { if (section == null) { this.section = null; } else { this.section = section; this.assessment = section.getAssessment(); this.assessmentId = assessment.getAssessmentId().toString(); this.assessmentTitle = assessment.getTitle(); this.sectionId = section.getSectionId().toString(); this.sectionTitle = section.getTitle(); this.sectionDescription = section.getDescription(); this.attachmentList = section.getSectionAttachmentList(); if (this.attachmentList != null && this.attachmentList.size() >0) this.hasAttachment = true; } } catch (Exception ex) { log.warn("Unable to set section. Exception thrown from setSection(): " + ex.getMessage()); } } public SectionFacade getSection(){ return section; } public boolean getHideRandom() { return hideRandom; } public void setHideRandom(boolean param) { hideRandom = param; } public boolean getHideOneByOne() { return hideOneByOne; } public void setHideOneByOne(boolean param) { hideOneByOne= param; } /** * @return */ public String getAssessmentId() { return assessmentId; } /** * @return */ public String getAssessmentTitle() { return assessmentTitle; } /** * @param string */ public void setAssessmentId(String string) { assessmentId = string; } /** * @param string */ public void setAssessmentTitle(String string) { assessmentTitle = string; } /** * @return */ public String getShowMetadata() { return showMetadata; } /** * @param string */ public void setShowMetadata(String string) { showMetadata = string; } /** * @return */ public String getSectionId() { return sectionId; } public String getSectionIdent() { return getSectionId(); } /** * @param string */ public void setSectionId(String string) { sectionId = string; } public void setSectionIdent(String string) { setSectionId(string); } /** * @return */ public ArrayList getAssessmentSectionIdents() { return assessmentSectionIdents; } /** * @param list */ public void setAssessmentSectionIdents(ArrayList list) { assessmentSectionIdents = list; } /** * Get a numerical sequence for all parts. * Derived property. * @return String[] in format "1", "2", "3"... up to the number of parts */ public ArrayList getSectionNumberList() { ArrayList list = new ArrayList(); if (assessmentSectionIdents==null) return list; for (int i = 0; i < assessmentSectionIdents.toArray().length; i++) { SelectItem selection = new SelectItem(); selection.setLabel("" + i); selection.setValue("" + i); list.add(selection); } return list; } public ArrayList getAuthorTypeList(){ ArrayList list = new ArrayList(); // cannot disable only one radio button in a list, so am generating the list again ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.AuthorMessages"); if (hideRandom){ SelectItem selection = new SelectItem(); selection.setLabel(rb.getString("type_onebyone")); selection.setValue("1"); list.add(selection); } else { SelectItem selection = new SelectItem(); selection.setLabel(rb.getString("type_onebyone")); selection.setValue("1"); list.add(selection); SelectItem selection1 = new SelectItem(); selection1.setLabel(rb.getString("random_draw_from_que")); selection1.setValue("2"); list.add(selection1); } return list; } /** * Ordinal number of current section. * Derived property. * @return String the number as a String, e.g. "3" */ public String getSelectedSection(){ return "" + assessmentSectionIdents.indexOf(sectionId); } public int getTotalSections() { return assessmentSectionIdents.size(); } /**List of available question pools for random draw. * returns a list of pools that have not been used by other random drawn parts * @return ArrayList of QuestionPoolFacade objects */ public ArrayList getPoolsAvailable() { ArrayList resultPoolList= new ArrayList(); if (this.getType() != null && this.getType().equals(SectionDataIfc.QUESTIONS_AUTHORED_ONE_BY_ONE.toString())) { this.setSelectedPool(""); this.setNumberSelected(""); return resultPoolList; } AssessmentBean assessmentBean = (AssessmentBean) ContextUtil.lookupBean("assessmentBean"); //ItemAuthorBean itemauthorBean = (ItemAuthorBean) ContextUtil.lookupBean("itemauthor"); QuestionPoolService delegate = new QuestionPoolService(); ArrayList allpoollist = delegate.getBasicInfoOfAllPools(AgentFacade.getAgentString()); HashMap allPoolsMap= new HashMap(); for (int i=0; i<allpoollist.size();i++){ QuestionPoolFacade apool = (QuestionPoolFacade) allpoollist.get(i); allPoolsMap.put(apool.getQuestionPoolId().toString(), apool); } AssessmentService assessdelegate = null; AuthorBean author = (AuthorBean) ContextUtil.lookupBean("author"); boolean isEditPendingAssessmentFlow = author.getIsEditPendingAssessmentFlow(); if (isEditPendingAssessmentFlow) { assessdelegate = new AssessmentService(); } else { assessdelegate = new PublishedAssessmentService(); } List sectionList = assessmentBean.getSectionList(); for (int i=0; i<sectionList.size();i++){ SelectItem s = (SelectItem) sectionList.get(i); // need to remove the pools already used by random draw parts SectionDataIfc section= assessdelegate.getSection(s.getValue().toString()); if( (section !=null) && (section.getSectionMetaDataByLabel(SectionDataIfc.AUTHOR_TYPE)!=null) && (section.getSectionMetaDataByLabel(SectionDataIfc.AUTHOR_TYPE).equals(SectionDataIfc.RANDOM_DRAW_FROM_QUESTIONPOOL.toString()))) { String poolid = section.getSectionMetaDataByLabel(SectionDataIfc.POOLID_FOR_RANDOM_DRAW); if (allPoolsMap.containsKey(poolid) ) { allPoolsMap.remove(poolid); } } } Iterator pooliter = allPoolsMap.keySet().iterator(); while (pooliter.hasNext()) { QuestionPoolFacade pool = (QuestionPoolFacade) allPoolsMap.get(pooliter.next()); //Huong's new int items = delegate.getCountItems(pool.getQuestionPoolId() ); if(items>0){ String resultListName= FormattedText.convertFormattedTextToPlaintext(pool.getDisplayName())+"("+ items +")" ; resultPoolList.add(new SelectItem((pool.getQuestionPoolId().toString()),resultListName) ); } } // add pool which is currently used in current Part for modify part if (!("".equals(this.getSelectedPool())) && (this.getSelectedPool() !=null)){ //now we need to get the poolid and displayName QuestionPoolFacade currPool= delegate.getPool(new Long(this.getSelectedPool()), AgentFacade.getAgentString()); // now add the current pool used to the list, so it's available in the pulldown if (currPool!=null) { // if the pool still exists, it's possible that the pool has been deleted int currItems = delegate.getCountItems(currPool.getQuestionPoolId()); if(currItems>0){ String currPoolName= FormattedText.convertFormattedTextToPlaintext(currPool.getDisplayName())+"("+ currItems +")" ; resultPoolList.add(new SelectItem((currPool.getQuestionPoolId().toString()), currPoolName)); } } else { // the pool has been deleted, } } Collections.sort(resultPoolList, new ItemComparator()); return resultPoolList; } class ItemComparator implements Comparator { public int compare(Object o1, Object o2) { SelectItem i1 = (SelectItem)o1; SelectItem i2 = (SelectItem)o2; try{ RuleBasedCollator r_collator= new RuleBasedCollator(((RuleBasedCollator)Collator.getInstance()).getRules().replaceAll("<'\u005f'", "<' '<'\u005f'")); return r_collator.compare(i1.getLabel(), i2.getLabel()); }catch(ParseException e){ return Collator.getInstance().compare(i1.getLabel(),i2.getLabel()); } } } /**List of available question pools. * @param list ArrayList of selectItems */ public void setPoolsAvailable(ArrayList list) { poolsAvailable = list; } /** * @return */ public String getNoOfItems() { return noOfItems; } /** * @param string */ public void setNoOfItems(String string) { noOfItems = string; } /** * Get a numerical sequence for all questions. * Derived property. * @return String[] in format "1", "2", "3"... up to the number of questions */ public ArrayList getItemNumberList(){ ArrayList list = new ArrayList(); for (int i = 0; i < items.toArray().length; i++) { SelectItem selection = new SelectItem(); selection.setLabel("" + i); selection.setValue("" + i); list.add(selection); } return list; } /** * @return the title */ public String getSectionTitle() { return this.sectionTitle; } /** * @param string the title */ public void setSectionTitle(String string) { this.sectionTitle = string; } /** * @return the info */ public String getSectionDescription() { return sectionDescription; } /** * @param string the info */ public void setSectionDescription(String string) { sectionDescription = string; } /** * @return the number selected */ public String getNumberSelected() { return numberSelected; } /** * @param string the number selected */ public void setNumberSelected(String string) { numberSelected = string; } /** * randomize? * @return boolean */ public boolean getRandom() { return random; } public ArrayList getItems() { return items; } /** * randomize? * @param bool boolean */ public void setRandom(boolean bool) { random = bool; } public void setItems(ArrayList items) { this.items = items; } public String getRandomPartScore() { if (randomPartScore != null) return randomPartScore; if (section == null) return ""; if (section.getSectionMetaDataByLabel(SectionDataIfc.POINT_VALUE_FOR_QUESTION) != null) { return section.getSectionMetaDataByLabel(SectionDataIfc.POINT_VALUE_FOR_QUESTION); } else { return ""; } } public void setRandomPartScore(String score) { randomPartScore = score; } public String getRandomPartDiscount() { if (randomPartDiscount != null) return randomPartDiscount; if (section == null) return "0"; if (section.getSectionMetaDataByLabel(SectionDataIfc.DISCOUNT_VALUE_FOR_QUESTION) != null) { return section.getSectionMetaDataByLabel(SectionDataIfc.DISCOUNT_VALUE_FOR_QUESTION); } else { return "0"; } } public void setRandomPartDiscount(String discount) { randomPartDiscount = discount; } /** * If removing part, do questions go with it? * @return true if questions are deleted too. */ public String getRemoveAllQuestions() { return removeAllQuestions; } /** * If removing part, do questions go with it? * @param removeAllQuestions */ public void setRemoveAllQuestions(String removeAllQuestions) { this.removeAllQuestions = removeAllQuestions; } public String getDestSectionId() { return destSectionId; } /** * @param string the title */ public void setDestSectionId(String destSectionId) { this.destSectionId = destSectionId; } /** * String value of selected pool id * @return String value of selected pool id */ public String getSelectedPool() { return selectedPool; } /** * set the String value of selected pool id * @param selectedPool String value of selected pool id */ public void setSelectedPool(String selectedPool) { this.selectedPool = selectedPool; } /** * get keyword metadata */ public String getKeyword() { return keyword; } /** * set metadata * @param param */ public void setKeyword(String param) { this.keyword= param; } /** * get objective metadata */ public String getObjective() { return objective; } /** * set metadata * @param param */ public void setObjective(String param) { this.objective= param; } /** * get rubric metadata */ public String getRubric() { return rubric; } /** * set metadata * @param param */ public void setRubric(String param) { this.rubric= param; } /** * get type */ public String getType() { return type; } /** * set type * @param param */ public void setType(String param) { this.type= param; } /** * get questionOrdering */ public String getQuestionOrdering() { return questionOrdering; } /** * set questionOrdering * @param param */ public void setQuestionOrdering(String param) { this.questionOrdering= param; } public void toggleAuthorType(ValueChangeEvent event) { // need to update metadata in db. //FacesContext context = FacesContext.getCurrentInstance(); String type = (String) event.getNewValue(); if ((type == null) || type.equals(SectionDataIfc.QUESTIONS_AUTHORED_ONE_BY_ONE.toString())) { setType(SectionDataIfc.QUESTIONS_AUTHORED_ONE_BY_ONE.toString()); } else if (type.equals(SectionDataIfc.RANDOM_DRAW_FROM_QUESTIONPOOL.toString())) { setType(SectionDataIfc.RANDOM_DRAW_FROM_QUESTIONPOOL.toString()); } else { // shouldn't go here. } } /** * get outcome */ public String getOutcome() { return outcome; } /** * set outcome * @param param */ public void setOutcome(String param) { this.outcome= param; } public List getAttachmentList() { return attachmentList; } public void setAttachmentList(List attachmentList) { this.attachmentList = attachmentList; } private boolean hasAttachment = false; public boolean getHasAttachment(){ return this.hasAttachment; } public void setHasAttachment(boolean hasAttachment){ this.hasAttachment = hasAttachment; } public String addAttachmentsRedirect() { // 1. then redirect to add attachment try { List filePickerList = new ArrayList(); if (attachmentList != null){ filePickerList = prepareReferenceList(attachmentList); } log.debug("**filePicker list="+filePickerList.size()); ToolSession currentToolSession = SessionManager.getCurrentToolSession(); currentToolSession.setAttribute(FilePickerHelper.FILE_PICKER_ATTACHMENTS, filePickerList); ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); context.redirect("sakai.filepicker.helper/tool"); } catch(Exception e){ log.error("fail to redirect to attachment page: " + e.getMessage()); } return getOutcome(); } public void setPartAttachment(){ AuthorBean author = (AuthorBean) ContextUtil.lookupBean("author"); boolean isEditPendingAssessmentFlow = author.getIsEditPendingAssessmentFlow(); SavePartAttachmentListener lis = null; if (isEditPendingAssessmentFlow) { lis = new SavePartAttachmentListener(true); } else { lis = new SavePartAttachmentListener(false); } lis.processAction(null); } private List prepareReferenceList(List attachmentList){ List list = new ArrayList(); for (int i=0; i<attachmentList.size(); i++){ ContentResource cr = null; AttachmentIfc attach = (AttachmentIfc) attachmentList.get(i); try{ cr = AssessmentService.getContentHostingService().getResource(attach.getResourceId()); } catch (PermissionException e) { log.warn("PermissionException from ContentHostingService:"+e.getMessage()); } catch (IdUnusedException e) { log.warn("IdUnusedException from ContentHostingService:"+e.getMessage()); // <-- bad sign, some left over association of part and resource, // use case: user remove resource in file picker, then exit modification without // proper cancellation by clicking at the left nav instead of "cancel". // Also in this use case, any added resource would be left orphan. AuthorBean author = (AuthorBean) ContextUtil.lookupBean("author"); boolean isEditPendingAssessmentFlow = author.getIsEditPendingAssessmentFlow(); AssessmentService assessmentService = null; if (isEditPendingAssessmentFlow) { assessmentService = new AssessmentService(); } else { assessmentService = new PublishedAssessmentService(); } assessmentService.removeSectionAttachment(attach.getAttachmentId().toString()); } catch (TypeException e) { log.warn("TypeException from ContentHostingService:"+e.getMessage()); } if (cr!=null){ if (this.resourceHash == null) this.resourceHash = new HashMap(); this.resourceHash.put(attach.getResourceId(),cr); Reference ref = EntityManager.newReference(cr.getReference()); if (ref !=null ) list.add(ref); } } return list; } private HashMap resourceHash = new HashMap(); public HashMap getResourceHash() { return resourceHash; } public void setResourceHash(HashMap resourceHash) { this.resourceHash = resourceHash; } public ArrayList getRandomizationTypeList(){ ArrayList list = new ArrayList(); ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.AuthorMessages"); SelectItem selection = new SelectItem(); selection.setLabel(rb.getString("randomized_per_submission")); selection.setValue("1"); list.add(selection); selection = new SelectItem(); selection.setLabel(rb.getString("randomized_per_student")); selection.setValue("2"); list.add(selection); return list; } public String getRandomizationType() { return randomizationType; } public void setRandomizationType(String randomizationType) { this.randomizationType = randomizationType; } public boolean getPointValueHasOverrided() { return pointValueHasOverrided; } public void setPointValueHasOverrided(boolean pointValueHasOverrided) { this.pointValueHasOverrided = pointValueHasOverrided; } public boolean getDiscountValueHasOverrided() { return discountValueHasOverrided; } public void setDiscountValueHasOverrided(boolean discountValueHasOverrided) { this.discountValueHasOverrided = discountValueHasOverrided; } }