/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/delivery/BeginDeliveryActionListener.java $
* $Id: BeginDeliveryActionListener.java 121231 2013-03-14 20:08:58Z ktsao@stanford.edu $
***********************************************************************************
*
* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009 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.listener.delivery;
import java.util.List;
import java.util.Date;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl;
import org.sakaiproject.tool.assessment.data.dao.assessment.PublishedFeedback;
import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentAccessControlIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentFeedbackIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.PublishedAssessmentIfc;
import org.sakaiproject.tool.assessment.data.ifc.assessment.SectionDataIfc;
import org.sakaiproject.tool.assessment.facade.AgentFacade;
import org.sakaiproject.tool.assessment.facade.AssessmentFacade;
import org.sakaiproject.tool.assessment.facade.PublishedAssessmentFacade;
import org.sakaiproject.tool.assessment.services.assessment.AssessmentService;
import org.sakaiproject.tool.assessment.services.assessment.PublishedAssessmentService;
import org.sakaiproject.tool.assessment.ui.bean.author.AssessmentBean;
import org.sakaiproject.tool.assessment.ui.bean.author.AuthorBean;
import org.sakaiproject.tool.assessment.ui.bean.cms.CourseManagementBean;
import org.sakaiproject.tool.assessment.ui.bean.delivery.DeliveryBean;
import org.sakaiproject.tool.assessment.ui.bean.delivery.FeedbackComponent;
import org.sakaiproject.tool.assessment.ui.bean.delivery.SectionContentsBean;
import org.sakaiproject.tool.assessment.ui.bean.delivery.SettingsDeliveryBean;
import org.sakaiproject.tool.assessment.ui.bean.shared.PersonBean;
import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil;
import org.sakaiproject.tool.assessment.ui.listener.author.RemovePublishedAssessmentThread;
/**
* <p>Title: Samigo</p>
* <p>Purpose: this module handles the beginning of the assessment
* <p>Description: Sakai Assessment Manager</p>
* @author Ed Smiley
* @version $Id: BeginDeliveryActionListener.java 121231 2013-03-14 20:08:58Z ktsao@stanford.edu $
*/
public class BeginDeliveryActionListener implements ActionListener
{
private static Log log = LogFactory.getLog(BeginDeliveryActionListener.class);
/**
* ACTION.
* @param ae
* @throws AbortProcessingException
*/
public void processAction(ActionEvent ae) throws
AbortProcessingException
{
log.debug("BeginDeliveryActionListener.processAction() ");
// get managed bean and set its action accordingly
DeliveryBean delivery = (DeliveryBean) ContextUtil.lookupBean("delivery");
log.debug("****DeliveryBean= "+delivery);
String actionString = ContextUtil.lookupParam("actionString");
if (actionString != null && !actionString.trim().equals("")) {
// if actionString is null, likely that action & actionString has been set already,
// e.g. take assessment via url, actionString is set by LoginServlet.
// preview and take assessment is set by the parameter in the jsp pages
delivery.setActionString(actionString);
}
delivery.setDisplayFormat();
if ("previewAssessment".equals(delivery.getActionString()) || "editAssessment".equals(actionString)) {
String isFromPrint = ContextUtil.lookupParam("isFromPrint");
if (isFromPrint != null && !isFromPrint.trim().equals("")) {
delivery.setIsFromPrint(Boolean.parseBoolean(isFromPrint));
}
}
else {
delivery.setIsFromPrint(false);
}
int action = delivery.getActionMode();
PublishedAssessmentFacade pub = getPublishedAssessmentBasedOnAction(action, delivery);
if(pub == null){
delivery.setOutcome("poolUpdateError");
throw new AbortProcessingException("pub is null");
}
if (DeliveryBean.REVIEW_ASSESSMENT == action && AssessmentIfc.RETRACT_FOR_EDIT_STATUS.equals(pub.getStatus())) {
// Bug 1547: If this is during review and the assessment is retracted for edit now,
// set the outcome to isRetractedForEdit2 error page.
delivery.setAssessmentTitle(pub.getTitle());
delivery.setOutcome("isRetractedForEdit2");
return;
}
// reset DeliveryBean before begin
ResetDeliveryListener reset = new ResetDeliveryListener();
reset.processAction(null);
// reset timer before begin
/*
delivery.setTimeElapse("0");
delivery.setTimeElapseAfterFileUpload(null);
delivery.setLastTimer(0);
delivery.setTimeLimit("0");
*/
delivery.setBeginAssessment(true);
delivery.setTimeStamp((new Date()).getTime());
delivery.setRedrawAnchorName("");
// protocol = http://servername:8080/; deliverAudioRecording.jsp needs it
delivery.setProtocol(ContextUtil.getProtocol());
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext external = context.getExternalContext();
String paramValue = ((Long)((ServletContext)external.getContext()).getAttribute("FILEUPLOAD_SIZE_MAX")).toString();
Long sizeMax = null;
float sizeMax_float = 0f;
if (paramValue != null) {
sizeMax = Long.parseLong(paramValue);
sizeMax_float = sizeMax.floatValue()/1024;
}
delivery.setFileUploadSizeMax(Math.round(sizeMax_float));
delivery.setPublishedAssessment(pub);
// populate backing bean from published assessment
populateBeanFromPub(delivery, pub);
}
private PublishedAssessmentFacade lookupPublishedAssessment(String id,
PublishedAssessmentService publishedAssessmentService
)
{
PublishedAssessmentFacade pub;
PublishedAssessmentService assessmentService = new PublishedAssessmentService();
pub = assessmentService.getPublishedAssessment(id);
if (pub.getAssessmentFeedback()==null)
{
pub.setAssessmentFeedback(new PublishedFeedback());
}
return pub;
}
/**
* This takes the published assessment information and puts it in the delivery
* bean. This is primarily the information that needs to be set up for the
* begin assessment page. Additional properties will be set when the student
* elects to begin taking assessment.
* @param delivery
* @param pubAssessment
*/
public void populateBeanFromPub(DeliveryBean delivery,
PublishedAssessmentFacade pubAssessment)
{
AssessmentAccessControlIfc control = (AssessmentAccessControlIfc)pubAssessment.getAssessmentAccessControl();
// populate deliveryBean, settingsBean and feedbackComponent .
// deliveryBean contains settingsBean & feedbackComponent)
populateDelivery(delivery, pubAssessment);
SettingsDeliveryBean settings = populateSettings(pubAssessment);
delivery.setSettings(settings);
// feedback
FeedbackComponent component = populateFeedbackComponent(pubAssessment);
delivery.setFeedbackComponent(component);
// feedback component option
if (pubAssessment.getFeedbackComponentOption() != null) {
delivery.setFeedbackComponentOption(pubAssessment.getFeedbackComponentOption().toString());
}
else {
delivery.setFeedbackComponentOption("1");
}
// important: set feedbackOnDate last
Date currentDate = new Date();
if (component.getShowDateFeedback() && control.getFeedbackDate()!= null && currentDate.after(control.getFeedbackDate())) {
delivery.setFeedbackOnDate(true);
}
EvaluationModelIfc eval = (EvaluationModelIfc) pubAssessment.getEvaluationModel();
delivery.setScoringType(eval.getScoringType());
delivery.setAttachmentList(pubAssessment.getAssessmentAttachmentList());
}
/**
* This grabs the assessment feedback & puts it in the FeedbackComponent
* @param feedback
* @param pubAssessment
*/
private FeedbackComponent populateFeedbackComponent(PublishedAssessmentFacade pubAssessment)
{
FeedbackComponent component = new FeedbackComponent();
AssessmentFeedbackIfc info = (AssessmentFeedbackIfc) pubAssessment.getAssessmentFeedback();
if ( info != null) {
component.setAssessmentFeedback(info);
}
return component;
}
/**
* This grabs the assessment and its AssessmentAccessControlIfc &
* puts it in the SettingsDeliveryBean.
* @param settings
* @param pubAssessment
*/
private SettingsDeliveryBean populateSettings(PublishedAssessmentIfc pubAssessment)
{
// #1 - poplulate control properties such as dueDate, feedbackDate, autoSubmit, autoSave
// max. no. of attempt, display format, username & password - mostly info
// on the BeginAssessment page. And deliveryBean contains settingsBean
SettingsDeliveryBean settings = new SettingsDeliveryBean();
settings.setAssessmentAccessControl(pubAssessment);
return settings;
}
/**
* Massage control settings into settings bean
* @param settings target SettingsDeliveryBean
* @param control the AssessmentAccessControlIfc
*/
private void populateDelivery(DeliveryBean delivery, PublishedAssessmentIfc pubAssessment){
Long publishedAssessmentId = pubAssessment.getPublishedAssessmentId();
AssessmentAccessControlIfc control = pubAssessment.getAssessmentAccessControl();
PublishedAssessmentService service = new PublishedAssessmentService();
// #0 - global information
delivery.setAssessmentId((pubAssessment.getPublishedAssessmentId()).toString());
delivery.setAssessmentTitle(pubAssessment.getTitle());
String instructorMessage = pubAssessment.getDescription();
delivery.setInstructorMessage(instructorMessage);
String ownerSiteId = service.getPublishedAssessmentOwner(pubAssessment.getPublishedAssessmentId());
String ownerSiteName = AgentFacade.getSiteName(ownerSiteId);
delivery.setCourseName(ownerSiteName);
// for now instructor is the creator 'cos sakai don't have instructor role in 1.5
delivery.setCreatorName(AgentFacade.getDisplayNameByAgentId(pubAssessment.getCreatedBy()));
delivery.setInstructorName(AgentFacade.getDisplayNameByAgentId(pubAssessment.getCreatedBy()));
delivery.setSubmitted(false);
delivery.setGraded(false);
delivery.setPartIndex(0);
delivery.setQuestionIndex(0);
delivery.setBeginTime(null);
delivery.setFeedbackOnDate(false);
delivery.setDueDate(control.getDueDate());
delivery.setRetractDate(control.getRetractDate());
if (control.getMarkForReview() != null && (Integer.valueOf(1)).equals(control.getMarkForReview())) {
delivery.setDisplayMardForReview(true);
}
else {
delivery.setDisplayMardForReview(false);
}
// #1 - set submission remains
int totalSubmissions = (service.getTotalSubmission(AgentFacade.getAgentString(),
publishedAssessmentId.toString())).intValue();
delivery.setTotalSubmissions(totalSubmissions);
if (!(Boolean.TRUE).equals(control.getUnlimitedSubmissions())){
// when there are retaks, we always display 1 as number of remaining submission
int submissionsRemaining = control.getSubmissionsAllowed().intValue() - totalSubmissions;
if (submissionsRemaining < 1) {
submissionsRemaining = 1;
}
delivery.setSubmissionsRemaining(submissionsRemaining);
}
// #2 - check if TOC should be made avaliable
if (control.getItemNavigation() == null)
delivery.setNavigation(AssessmentAccessControl.RANDOM_ACCESS.toString());
else
delivery.setNavigation(control.getItemNavigation().toString());
// #3 - if this is a timed assessment, set the time limit in hr, min & sec.
setTimedAssessment(delivery, pubAssessment);
}
private void setTimedAssessment(DeliveryBean delivery, PublishedAssessmentIfc pubAssessment){
AssessmentAccessControlIfc control = pubAssessment.getAssessmentAccessControl();
// check if we need to time the assessment, i.e.hasTimeassessment="true"
String hasTimeLimit = pubAssessment.getAssessmentMetaDataByLabel("hasTimeAssessment");
if (hasTimeLimit!=null && hasTimeLimit.equals("true")){
delivery.setHasTimeLimit(true);
delivery.setTimerId((new Date()).getTime()+"");
try {
if (control.getTimeLimit() != null) {
delivery.setTimeLimit(delivery.updateTimeLimit(control.getTimeLimit().toString()));
int seconds = control.getTimeLimit().intValue();
int hour = 0;
int minute = 0;
if (seconds>=3600) {
hour = Math.abs(seconds/3600);
minute =Math.abs((seconds-hour*3600)/60);
}
else {
minute = Math.abs(seconds/60);
}
delivery.setTimeLimit_hour(hour);
delivery.setTimeLimit_minute(minute);
}
} catch (RuntimeException e)
{
delivery.setTimeLimit("");
}
}
else{
delivery.setHasTimeLimit(false);
delivery.setTimerId(null);
delivery.setTimeLimit("0");
}
}
private PublishedAssessmentFacade getPublishedAssessmentBasedOnAction(int action, DeliveryBean delivery){
AssessmentService assessmentService = new AssessmentService();
PublishedAssessmentService publishedAssessmentService = new PublishedAssessmentService();
PublishedAssessmentFacade pub = null;
String publishedId = ContextUtil.lookupParam("publishedId");
String assessmentId = (String)ContextUtil.lookupParam("assessmentId");
if (assessmentId == null || "".equals(assessmentId))
assessmentId = delivery.getAssessmentId();
switch (action){
case 2: // delivery.PREVIEW_ASSESSMENT
AuthorBean author = (AuthorBean) ContextUtil.lookupBean("author");
if (author.getIsEditPendingAssessmentFlow()) {
// we would publish to create the publishedAssessment which we would use to populate
// properties in delivery. However, for previewing, we do not need to keep this
// publishedAssessment record in DB at all, so we would delete it from DB right away.
int success = updateQuestionPoolQuestions(assessmentId, assessmentService);
if(success == AssessmentService.UPDATE_SUCCESS){
AssessmentFacade assessment = assessmentService.getAssessment(assessmentId);
try {
PublishedAssessmentFacade tempPub = publishedAssessmentService.publishPreviewAssessment(
assessment);
publishedId = tempPub.getPublishedAssessmentId().toString();
// clone pub from tempPub, clone is not in anyway bound to the DB session
pub = tempPub.clonePublishedAssessment();
//get list of resources attached to the published Assessment
List resourceIdList = assessmentService.getAssessmentResourceIdList(pub);
PersonBean personBean = (PersonBean) ContextUtil.lookupBean("person");
personBean.setResourceIdListInPreview(resourceIdList);
//log.info("****publishedId="+publishedId);
//log.info("****clone publishedId="+pub.getPublishedAssessmentId());
RemovePublishedAssessmentThread thread = new RemovePublishedAssessmentThread(publishedId, "preview");
thread.start();
}
catch (Exception e) {
log.error(e);
e.printStackTrace();
}
}else{
FacesContext context = FacesContext.getCurrentInstance();
if(success == AssessmentService.UPDATE_ERROR_DRAW_SIZE_TOO_LARGE){
String err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AuthorMessages","update_pool_error_size_too_large");
context.addMessage(null,new FacesMessage(err));
}else{
String err=ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.AuthorMessages","update_pool_error_unknown");
context.addMessage(null,new FacesMessage(err));
}
return null;
}
}
else {
pub = publishedAssessmentService.getPublishedAssessment(assessmentId);
}
break;
case 5: //delivery.TAKE_ASSESSMENT_VIA_URL:
// this is accessed via publishedUrl so pubishedId==null
pub = delivery.getPublishedAssessment();
if (pub == null)
throw new AbortProcessingException(
"taking: publishedAsessmentId null or blank");
//else
//publishedId = pub.getPublishedAssessmentId().toString();
break;
case 1: //delivery.TAKE_ASSESSMENT
case 3: //delivery.REVIEW_ASSESSMENT
pub = lookupPublishedAssessment(publishedId, publishedAssessmentService);
break;
default:
break;
}
return pub;
}
private int updateQuestionPoolQuestions(String assessmentId, AssessmentService assessmentService){
int success = assessmentService.updateAllRandomPoolQuestions(assessmentService.getAssessment(assessmentId));
if(success == AssessmentService.UPDATE_SUCCESS){
String fromEditStr = ContextUtil.lookupParam("fromEdit");
if(fromEditStr != null && "true".equals(fromEditStr)){
//since this is coming from the edit page, we need to update the bean information so it doesn't have stale data
AssessmentBean assessmentBean = (AssessmentBean) ContextUtil.lookupBean("assessmentBean");
if(assessmentBean != null && assessmentBean.getSections() != null){
for(int i = 0; i < assessmentBean.getSections().size(); i++){
SectionContentsBean sectionBean = (SectionContentsBean) assessmentBean.getSections().get(i);
if((sectionBean.getSectionAuthorTypeString() != null)
&& (sectionBean.getSectionAuthorTypeString().equals(SectionDataIfc.RANDOM_DRAW_FROM_QUESTIONPOOL
.toString()))){
//this has been updated so we need to reset it
assessmentBean.getSections().set(i, new SectionContentsBean(assessmentService.getSection(sectionBean.getSectionId().toString())));
}
}
}
}
}
return success;
}
}