org.sakaiproject.evaluation.tool.SetupEvalBean.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.evaluation.tool.SetupEvalBean.java

Source

/**
 * $Id$
 * $URL$
 * SetupEvalBean.java - evaluation - Mar 18, 2008 4:38:20 PM - azeckoski
 **************************************************************************
 * Copyright (c) 2008 Centre for Applied Research in Educational Technologies, University of Cambridge
 * Licensed under the Educational Community License version 1.0
 * 
 * A copy of the Educational Community License has been included in this 
 * distribution and is available at: http://www.opensource.org/licenses/ecl1.php
 *
 * Aaron Zeckoski (azeckoski@gmail.com) (aaronz@vt.edu) (aaron@caret.cam.ac.uk)
 */

package org.sakaiproject.evaluation.tool;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.evaluation.constant.EvalConstants;
import org.sakaiproject.evaluation.logic.EvalAuthoringService;
import org.sakaiproject.evaluation.logic.EvalCommonLogic;
import org.sakaiproject.evaluation.logic.EvalEvaluationService;
import org.sakaiproject.evaluation.logic.EvalEvaluationSetupService;
import org.sakaiproject.evaluation.logic.exceptions.BlankRequiredFieldException;
import org.sakaiproject.evaluation.logic.exceptions.InvalidDatesException;
import org.sakaiproject.evaluation.logic.externals.EvalExternalLogic;
import org.sakaiproject.evaluation.logic.externals.ExternalHierarchyLogic;
import org.sakaiproject.evaluation.logic.model.EvalHierarchyNode;
import org.sakaiproject.evaluation.model.EvalAssignGroup;
import org.sakaiproject.evaluation.model.EvalAssignHierarchy;
import org.sakaiproject.evaluation.model.EvalAssignUser;
import org.sakaiproject.evaluation.model.EvalEmailTemplate;
import org.sakaiproject.evaluation.model.EvalEvaluation;
import org.sakaiproject.evaluation.model.EvalTemplate;
import org.sakaiproject.evaluation.tool.locators.AssignGroupSelectionSettings;
import org.sakaiproject.evaluation.tool.locators.EmailTemplateWBL;
import org.sakaiproject.evaluation.tool.locators.EvaluationBeanLocator;
import org.sakaiproject.evaluation.tool.locators.SelectedEvaluationUsersLocator;
import org.sakaiproject.evaluation.utils.ArrayUtils;
import org.sakaiproject.evaluation.utils.EvalUtils;

import uk.org.ponder.messageutil.TargettedMessage;
import uk.org.ponder.messageutil.TargettedMessageList;

/**
 * This action bean helps with the evaluation setup process where needed, this
 * is a pea
 * 
 * @author Aaron Zeckoski (aaron@caret.cam.ac.uk)
 */
public class SetupEvalBean {

    private static Log log = LogFactory.getLog(SetupEvalBean.class);

    private final String EVENT_EVAL_REOPENED = "eval.evaluation.reopened";

    /**
     * This should be set to true while we are creating an evaluation
     */
    public boolean creatingEval = false;
    /**
     * This should be set to the evalId we are currently working with
     */
    public Long evaluationId;
    /**
     * This should be set to the templateId we are assigning to the evaluation
     */
    public Long templateId;
    /**
     * This should be set to the emailTemplateId we are assigning to the
     * evaluation
     */
    public Long emailTemplateId;
    /**
     * This is set to the type of email template when resetting the evaluation
     * to use default templates
     */
    public String emailTemplateType;
    /**
     * Set to true if we are reopening this evaluation
     */
    public boolean reOpening = false;

    /**
     * the selected groups ids to bind to this evaluation when creating it
     */
    public String[] selectedGroupIDs = new String[] {};
    /**
     * the selected hierarchy nodes to bind to this evaluation when creating it
     */
    public String[] selectedHierarchyNodeIDs = new String[] {};

    /**
     * the selected option (eg. for TAs and Instructors) in this evaluation. see
     * {@link EvalEvaluation.selectionSettings}
     */
    public Map<String, String> selectionOptions = new HashMap<String, String>();
    /**
     * selection value to populate {@link SetupEvalBean.selectionOptions}
     */
    public String selectionInstructors, selectionAssistants;
    /* TODO - delete these now in their own bean
    public Map<String, String[]> deselectedInstructors = new HashMap<String, String[]>();
    public Map<String, String[]> deselectedAssistants = new HashMap<String, String[]>();
    */
    private EvalEvaluationService evaluationService;

    public void setEvaluationService(EvalEvaluationService evaluationService) {
        this.evaluationService = evaluationService;
    }

    private EvalCommonLogic commonLogic;

    public void setCommonLogic(EvalCommonLogic commonLogic) {
        this.commonLogic = commonLogic;
    }

    private ExternalHierarchyLogic hierarchyLogic;

    public void setExternalHierarchyLogic(ExternalHierarchyLogic logic) {
        this.hierarchyLogic = logic;
    }

    private EvalEvaluationSetupService evaluationSetupService;

    public void setEvaluationSetupService(EvalEvaluationSetupService evaluationSetupService) {
        this.evaluationSetupService = evaluationSetupService;
    }

    private EvalAuthoringService authoringService;

    public void setAuthoringService(EvalAuthoringService authoringService) {
        this.authoringService = authoringService;
    }

    private EvaluationBeanLocator evaluationBeanLocator;

    public void setEvaluationBeanLocator(EvaluationBeanLocator evaluationBeanLocator) {
        this.evaluationBeanLocator = evaluationBeanLocator;
    }

    private EmailTemplateWBL emailTemplateWBL;

    public void setEmailTemplateWBL(EmailTemplateWBL emailTemplateWBL) {
        this.emailTemplateWBL = emailTemplateWBL;
    }

    private TargettedMessageList messages;

    public void setMessages(TargettedMessageList messages) {
        this.messages = messages;
    }

    private Locale locale;

    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    private SelectedEvaluationUsersLocator selectedEvaluationUsersLocator;

    public void setSelectedEvalautionUsersLocator(SelectedEvaluationUsersLocator selectedEvaluationUsersLocator) {
        this.selectedEvaluationUsersLocator = selectedEvaluationUsersLocator;
    }

    private AssignGroupSelectionSettings assignGroupSelectionSettings;

    public void setAssignGroupSelectionSettings(AssignGroupSelectionSettings assignGroupSelectionSettings) {
        this.assignGroupSelectionSettings = assignGroupSelectionSettings;
    }

    DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);

    /**
     * sets he locale on the date formatter correctly
     */
    public void init() {
        df = DateFormat.getDateInstance(DateFormat.LONG, locale);
    }

    // Action bindings

    /**
     * Handles removal action from the remove eval view
     */
    public String removeEvalAction() {
        if (evaluationId == null) {
            throw new IllegalArgumentException("evaluationId cannot be null");
        }
        EvalEvaluation eval = evaluationService.getEvaluationById(evaluationId);
        evaluationSetupService.deleteEvaluation(evaluationId, commonLogic.getCurrentUserId());
        messages.addMessage(new TargettedMessage("controlevaluations.delete.user.message",
                new Object[] { eval.getTitle() }, TargettedMessage.SEVERITY_INFO));
        return "success";
    }

    /**
     * Handles close eval action from control evaluations view
     */
    public String closeEvalAction() {
        if (evaluationId == null) {
            throw new IllegalArgumentException("evaluationId cannot be null");
        }
        EvalEvaluation eval = evaluationSetupService.closeEvaluation(evaluationId, commonLogic.getCurrentUserId());
        messages.addMessage(new TargettedMessage("controlevaluations.closed.user.message",
                new Object[] { eval.getTitle() }, TargettedMessage.SEVERITY_INFO));
        return "success";
    }

    /**
     * Handles reopening evaluation action (from eval settings view)
     */
    public String reopenEvalAction() {
        if (evaluationId == null) {
            throw new IllegalArgumentException("evaluationId cannot be null");
        }
        EvalEvaluation eval = evaluationService.getEvaluationById(evaluationId);
        // TODO reopen action
        // evaluationSetupService.deleteEvaluation(evaluationId,
        // commonLogic.getCurrentUserId());
        messages.addMessage(new TargettedMessage("controlevaluations.reopen.user.message",
                new Object[] { eval.getTitle() }, TargettedMessage.SEVERITY_INFO));
        return "success";
    }

    /**
     * Handles saving and assigning email templates to an evaluation, can just
     * assign the email template if the emailTemplateId is set or will save and
     * assign the one in the locator
     */
    public String saveAndAssignEmailTemplate() {
        if (evaluationId == null) {
            throw new IllegalArgumentException("evaluationId and emailTemplateId cannot be null");
        }

        EvalEmailTemplate emailTemplate = null;
        if (emailTemplateId == null) {
            // get it from the locator
            emailTemplateWBL.saveAll();
            emailTemplate = emailTemplateWBL.getCurrentEmailTemplate();
        } else {
            // just load up and assign the template and do not save it
            emailTemplate = evaluationService.getEmailTemplate(emailTemplateId);
        }

        // assign to the evaluation
        evaluationSetupService.assignEmailTemplate(emailTemplate.getId(), evaluationId, null,
                commonLogic.getCurrentUserId());

        // user message
        EvalEvaluation eval = evaluationService.getEvaluationById(evaluationId);
        messages.addMessage(new TargettedMessage("controlemailtemplates.template.assigned.message",
                new Object[] { emailTemplate.getType(), emailTemplate.getSubject(), eval.getTitle() },
                TargettedMessage.SEVERITY_INFO));
        return "successAssign";
    }

    /**
     * Handles resetting the evaluation to use the default template
     */
    public String resetToDefaultEmailTemplate() {
        if (evaluationId == null || emailTemplateType == null) {
            throw new IllegalArgumentException("evaluationId and emailTemplateType cannot be null");
        }

        // reset to default email template
        evaluationSetupService.assignEmailTemplate(null, evaluationId, emailTemplateType,
                commonLogic.getCurrentUserId());

        return "successReset";
    }

    // NOTE: these are the simple navigation methods
    // 4 steps to create an evaluation: 1) Create -> 2) Settings -> 3) Assign ->
    // 4) Confirm/Save

    /**
     * Completed the initial creation page where the template is chosen
     */
    public String completeCreateAction() {
        // TODO - get rid of this once RSF is fixed
        // set the template on the evaluation in the bean locator (TODO - get
        // rid of this)
        if (templateId == null) {
            throw new IllegalStateException(
                    "The templateId is null, it must be set so it can be assigned to the new evaluation");
        }
        EvalEvaluation eval = evaluationBeanLocator.getCurrentEval();
        if (eval == null) {
            throw new IllegalStateException(
                    "The evaluation cannot be retrieved from the bean locator, critical failure");
        }
        EvalTemplate template = authoringService.getTemplateById(templateId);
        eval.setTemplate(template);

        // save the new evaluation
        try {
            setSelectionOptions();
            evaluationBeanLocator.saveAll(selectionOptions);
        } catch (BlankRequiredFieldException e) {
            messages.addMessage(new TargettedMessage(e.messageKey, new Object[] { e.fieldName },
                    TargettedMessage.SEVERITY_ERROR));
            throw new RuntimeException(e); // should not be needed but it is
        }
        return "evalSettings";
    }

    /**
     * Updated or initially set the evaluation settings
     */
    public String completeSettingsAction() {
        // set the template on the evaluation in the bean locator if not null
        if (templateId != null) {
            EvalEvaluation eval = evaluationBeanLocator.getCurrentEval();
            if (eval != null) {
                EvalTemplate template = authoringService.getTemplateById(templateId);
                eval.setTemplate(template);
            }
        }

        try {
            setSelectionOptions();
            evaluationBeanLocator.saveAll(selectionOptions);
        } catch (BlankRequiredFieldException e) {
            messages.addMessage(new TargettedMessage(e.messageKey, new Object[] { e.fieldName },
                    TargettedMessage.SEVERITY_ERROR));
            throw new RuntimeException(e); // should not be needed but it is
        } catch (InvalidDatesException e) {
            messages.addMessage(
                    new TargettedMessage(e.messageKey, new Object[] {}, TargettedMessage.SEVERITY_ERROR));
            throw new RuntimeException(e); // should not be needed but it is
        }
        // TODO - fix this once RSF is fixed, remove all above this line and
        // uncomment below
        // completeCreateAction();

        EvalEvaluation eval = evaluationBeanLocator.getCurrentEval();
        String destination = "controlEvals";
        if (EvalConstants.EVALUATION_STATE_PARTIAL.equals(eval.getState())) {
            destination = "evalAssign";
        } else {
            if (reOpening) {
                // we are reopening the evaluation
                commonLogic.registerEntityEvent(EVENT_EVAL_REOPENED, eval);
                messages.addMessage(new TargettedMessage("controlevaluations.reopen.user.message",
                        new Object[] { eval.getTitle() }, TargettedMessage.SEVERITY_INFO));
            } else {
                messages.addMessage(new TargettedMessage("evalsettings.updated.message",
                        new Object[] { eval.getTitle() }, TargettedMessage.SEVERITY_INFO));
            }
        }
        return destination;
    }

    // NOTE: There is no action for the 3) assign step and action 4 have been
    // merged.

    // TODO - how do we handle removing assignments? (Currently not supported)

    /**
     * Complete the creation process for an evaluation (view all the current
     * settings and assignments and create eval/assignments), this will save the
     * node/group assignments that were submitted and reconcile this list with
     * the previous set of nodes/groups and remove any that are now missing
     * before adding the new ones
     */
    public String completeConfirmAction() {
        if (evaluationId == null) {
            throw new IllegalArgumentException("evaluationId and emailTemplateId cannot be null");
        }

        // make sure that the submitted nodes are valid and populate the nodes
        // list
        Set<EvalHierarchyNode> nodes = null;
        if (selectedHierarchyNodeIDs.length > 0) {
            nodes = hierarchyLogic.getNodesByIds(selectedHierarchyNodeIDs);
            if (nodes.size() != selectedHierarchyNodeIDs.length) {
                throw new IllegalArgumentException("Invalid set of hierarchy node ids submitted which "
                        + "includes node Ids which are not in the hierarchy: "
                        + ArrayUtils.arrayToString(selectedHierarchyNodeIDs));
            }
        } else {
            nodes = new HashSet<EvalHierarchyNode>();
        }

        // at least 1 node or group must be selected
        if (selectedGroupIDs.length == 0 && nodes.isEmpty()) {
            messages.addMessage(new TargettedMessage("assigneval.invalid.selection", new Object[] {},
                    TargettedMessage.SEVERITY_ERROR));
            return "fail";
        }

        EvalEvaluation eval = evaluationService.getEvaluationById(evaluationId);
        if (EvalConstants.EVALUATION_STATE_PARTIAL.equals(eval.getState())) {
            // save eval and assign groups

            // save the new evaluation state (moving from partial), set to true
            // should fix up the state automatically
            evaluationSetupService.saveEvaluation(eval, commonLogic.getCurrentUserId(), true);

            // NOTE - this allows the evaluation to be saved with zero assign
            // groups if this fails

            // save all the assignments (hierarchy and group)
            List<EvalAssignHierarchy> assignedHierList = evaluationSetupService.setEvalAssignments(evaluationId,
                    selectedHierarchyNodeIDs, selectedGroupIDs, false);

            // failsafe check (to make sure we are not creating an eval with no
            // assigned groups)
            if (assignedHierList.isEmpty()) {
                evaluationSetupService.deleteEvaluation(evaluationId, commonLogic.getCurrentUserId());
                throw new IllegalStateException(
                        "Invalid evaluation created with no assignments! Destroying evaluation: " + evaluationId);
            }

            messages.addMessage(new TargettedMessage("controlevaluations.create.user.message",
                    new Object[] { eval.getTitle(), df.format(eval.getStartDate()) },
                    TargettedMessage.SEVERITY_INFO));
        } else {
            // just assigning groups
            if (EvalUtils.checkStateAfter(eval.getState(), EvalConstants.EVALUATION_STATE_ACTIVE, false)) {
                throw new IllegalStateException(
                        "User cannot update evaluation assignments after an evaluation is active and complete");
            }

            // make sure we cannot remove assignments for active evals
            boolean append = false;
            if (EvalUtils.checkStateAfter(eval.getState(), EvalConstants.EVALUATION_STATE_INQUEUE, false)) {
                append = true; // can only append after active
            }

            // save all the assignments (hierarchy and group)
            evaluationSetupService.setEvalAssignments(evaluationId, selectedHierarchyNodeIDs, selectedGroupIDs,
                    append);
        }

        Map<Long, List<EvalAssignGroup>> evalAssignGroupMap = evaluationService
                .getAssignGroupsForEvals(new Long[] { evaluationId }, true, false);
        List<EvalAssignGroup> evalAssignGroups = evalAssignGroupMap.get(evaluationId);

        // Query DB only once to get all EvalAssignUsers
        List<EvalAssignUser> evalUsers = evaluationService.getParticipantsForEval(evaluationId, null, null, null,
                EvalEvaluationService.STATUS_ANY, null, null);

        for (EvalAssignGroup assignGroup : evalAssignGroups) {
            String currentGroupId = assignGroup.getEvalGroupId();
            // Save Assistant/Instructor selections now. EVALSYS-618
            String[] deselectedInstructors = selectedEvaluationUsersLocator
                    .getDeselectedInstructors(currentGroupId);
            String[] deselectedAssistants = selectedEvaluationUsersLocator.getDeselectedAssistants(currentGroupId);
            String[] orderingInstructors = selectedEvaluationUsersLocator.getOrderingForInstructors(currentGroupId);
            String[] orderingAssistants = selectedEvaluationUsersLocator.getOrderingForAssistants(currentGroupId);
            updateEvalAssignUsers(deselectedInstructors, orderingInstructors, EvalAssignUser.TYPE_EVALUATEE,
                    currentGroupId, evalUsers);
            updateEvalAssignUsers(deselectedAssistants, orderingAssistants, EvalAssignUser.TYPE_ASSISTANT,
                    currentGroupId, evalUsers);
            // set selection settings for assign group
            String settingInstructor = assignGroupSelectionSettings.getInstructorSetting(currentGroupId);
            String settingAssistant = assignGroupSelectionSettings.getAssistantSetting(currentGroupId);
            if (settingInstructor == null || "".equals(settingInstructor)) {
                assignGroup.setSelectionOption(EvalAssignGroup.SELECTION_TYPE_INSTRUCTOR,
                        EvalAssignGroup.SELECTION_OPTION_ALL);
            } else {
                assignGroup.setSelectionOption(EvalAssignGroup.SELECTION_TYPE_INSTRUCTOR, settingInstructor);
            }
            if (settingAssistant == null || "".equals(settingAssistant)) {
                assignGroup.setSelectionOption(EvalAssignGroup.SELECTION_TYPE_ASSISTANT,
                        EvalAssignGroup.SELECTION_OPTION_ALL);
            } else {
                assignGroup.setSelectionOption(EvalAssignGroup.SELECTION_TYPE_ASSISTANT, settingAssistant);
            }
            //Save selection settings
            evaluationSetupService.saveAssignGroup(assignGroup, commonLogic.getCurrentUserId());
        }

        return "controlEvals";
    }

    // NOTE: these are the support methods

    /**
     * Turn a boolean selection map into an array of the keys
     * 
     * @param booleanSelectionMap
     *            a map of string -> boolean (from RSF bound booleans)
     * @return an array of the keys where boolean is true
     */
    public static String[] makeArrayFromBooleanMap(Map<String, Boolean> booleanSelectionMap) {
        List<String> hierNodeIdList = new ArrayList<String>();
        for (String hierNodeID : booleanSelectionMap.keySet()) {
            if (booleanSelectionMap.get(hierNodeID) == true) {
                hierNodeIdList.add(hierNodeID);
            }
        }
        String[] selectedHierarchyNodeIds = hierNodeIdList.toArray(new String[] {});
        return selectedHierarchyNodeIds;
    }

    /**
     * Create {@link Map} object to inject into Eval and set Selection Options
     * eg.for {@link EvalAssignGroup.SELECTION_TYPE_INSTRUCTOR} and
     * {@link EvalAssignGroup.SELECTION_TYPE_ASSISTANT}
     * 
     * @return selectionOptions {@link Map}
     */
    private Map<String, String> setSelectionOptions() {
        selectionOptions.put(EvalAssignGroup.SELECTION_TYPE_INSTRUCTOR, selectionInstructors);
        selectionOptions.put(EvalAssignGroup.SELECTION_TYPE_ASSISTANT, selectionAssistants);
        return selectionOptions;
    }

    /**
     * Remove this {@link List} of userIds from being assigned to current
     * evaluation
     * 
     * @param deselected
     * @param ordering 
     * @param type either {@link EvalAssignUser.TYPE_EVALUATEE} or {@link EvalAssignUser.TYPE_ASSISTANT}
     * @param currentGroupId 
     * @param evalUsers 
     */
    private void updateEvalAssignUsers(String[] deselected, String[] ordering, String type, String currentGroupId,
            List<EvalAssignUser> evalUsers) {
        List<String> deselectedList = Arrays.asList(deselected);
        List<String> orderingList = Arrays.asList(ordering);
        for (EvalAssignUser user : evalUsers) {
            // only update users for this group with this permission type
            String userId = user.getUserId();
            if (currentGroupId.equals(user.getEvalGroupId().toString()) && type.equals(user.getType())) {
                if (deselectedList.contains(userId)) {
                    user.setStatus(EvalAssignUser.STATUS_REMOVED);
                } else {
                    user.setStatus(EvalAssignUser.STATUS_LINKED);
                }
                // set users' selection order
                if (orderingList.contains(userId)) {
                    int listOrder = orderingList.indexOf(userId) + 1;
                    user.setListOrder(listOrder);
                }
            }
        }
    }

}