org.sakaiproject.tool.gradebook.ui.InstructorViewBean.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.tool.gradebook.ui.InstructorViewBean.java

Source

/*******************************************************************************
 * Copyright (c) 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.gradebook.ui;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.event.ActionEvent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord;
import org.sakaiproject.service.gradebook.shared.StaleObjectModificationException;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.tool.gradebook.AbstractGradeRecord;
import org.sakaiproject.tool.gradebook.Assignment;
import org.sakaiproject.tool.gradebook.AssignmentGradeRecord;
import org.sakaiproject.tool.gradebook.Category;
import org.sakaiproject.tool.gradebook.CourseGrade;
import org.sakaiproject.tool.gradebook.CourseGradeRecord;
import org.sakaiproject.tool.gradebook.GradableObject;
import org.sakaiproject.tool.gradebook.jsf.FacesUtil;

/**
 * Provides data for the instructor's view of a student's grades in the gradebook.
 */
public class InstructorViewBean extends ViewByStudentBean implements Serializable {
    private static Log logger = LogFactory.getLog(InstructorViewBean.class);

    private EnrollmentRecord previousStudent;
    private EnrollmentRecord nextStudent;
    private EnrollmentRecord currentStudent;

    private String studentEmailAddress;
    private String studentSections;

    private List orderedEnrollmentList;

    // parameters passed to the page
    private String returnToPage;
    private String assignmentId; // for returning to specific gradebook item

    private static final String ROSTER_PAGE = "roster";
    private static final String ASSIGN_DETAILS_PAGE = "assignmentDetails";

    /**
     * @see org.sakaiproject.tool.gradebook.ui.InitializableBean#init()
     */
    public void init() {
        previousStudent = null;
        nextStudent = null;
        studentSections = null;

        String sortByCol = getSortColumn();
        boolean sortAsc = isSortAscending();

        setIsInstructorView(true);

        if (getStudentUid() != null) {
            super.init();

            studentEmailAddress = getUserDirectoryService().getUserEmailAddress(getStudentUid());
            studentSections = getStudentSectionsForDisplay();

            // set up the "next" and "previous" student navigation
            // TODO preserve filter/sort status from originating page
            if (orderedEnrollmentList == null) {
                orderedEnrollmentList = new ArrayList();
                if (returnToPage.equals(ROSTER_PAGE)) {
                    super.setSelectedSectionFilterValue(getPreferencesBean().getRosterTableSectionFilter());
                    maxDisplayedScoreRows = 0;
                    orderedEnrollmentList = getOrderedEnrolleesFromRosterPage();
                } else if (returnToPage.equals(ASSIGN_DETAILS_PAGE)) {
                    super.setSelectedSectionFilterValue(
                            getPreferencesBean().getAssignmentDetailsTableSectionFilter());
                    maxDisplayedScoreRows = 0;
                    orderedEnrollmentList = getOrderedEnrolleesFromAssignDetailsPage();
                }
            }

            if (orderedEnrollmentList != null && orderedEnrollmentList.size() > 1) {
                int index = 0;
                while (index < orderedEnrollmentList.size()) {
                    EnrollmentRecord enrollee = (EnrollmentRecord) orderedEnrollmentList.get(index);
                    if (enrollee.getUser().getUserUid().equals(getStudentUid())) {
                        currentStudent = enrollee;
                        if (index - 1 >= 0) {
                            previousStudent = (EnrollmentRecord) orderedEnrollmentList.get(index - 1);
                        }
                        if (index + 1 < orderedEnrollmentList.size()) {
                            nextStudent = (EnrollmentRecord) orderedEnrollmentList.get(index + 1);
                        }
                        break;
                    }
                    index++;
                }
            }

            setSortColumn(sortByCol);
            setSortAscending(sortAsc);

        }
    }

    // Navigation
    public EnrollmentRecord getPreviousStudent() {
        return previousStudent;
    }

    public EnrollmentRecord getNextStudent() {
        return nextStudent;
    }

    public boolean isFirst() {
        return previousStudent == null;
    }

    public boolean isLast() {
        return nextStudent == null;
    }

    public EnrollmentRecord getCurrentStudent() {
        return currentStudent;
    }

    /**
     * @return text for "Return to" button
     */
    public String getReturnToPageButtonName() {
        String pageTitle;
        if (ASSIGN_DETAILS_PAGE.equals(returnToPage))
            pageTitle = getLocalizedString("assignment_details_page_title");
        else
            pageTitle = getLocalizedString("roster_page_title");

        return getLocalizedString("inst_view_return_to", new String[] { pageTitle });
    }

    /**
     * 
     * @return page title of originating page
     */
    public String getReturnToPageName() {
        if (returnToPage.equals(ASSIGN_DETAILS_PAGE))
            return getLocalizedString("assignment_details_page_title");
        else
            return getLocalizedString("roster_page_title");
    }

    /**
     * 
     * @return comma-separated string of user's section/group memberships
     */
    public String getStudentSections() {
        return studentSections;
    }

    /**
     * @return studentEmailAddress
     */
    public String getStudentEmailAddress() {
        return studentEmailAddress;
    }

    /**
     * Action listener to view a different student
     */
    public void processStudentUidChange(ActionEvent event) {
        Map params = FacesUtil.getEventParameterMap(event);
        if (logger.isDebugEnabled())
            logger.debug("processStudentUidChange params=" + params + ", current studentUid=" + getStudentUid());
        // run the updates before changing the student id
        processUpdateScoresForPreNextStudent();
        String idParam = (String) params.get("studentUid");
        if (idParam != null) {
            setStudentUid(idParam);
        }
    }

    public void processUpdateScoresForPreNextStudent() {
        try {
            saveScoresWithoutConfirmation();
        } catch (StaleObjectModificationException e) {
            FacesUtil.addErrorMessage(getLocalizedString("assignment_details_locking_failure"));
        }
    }

    /**
     * Save the input scores for the user
     * @throws StaleObjectModificationException
     */
    public void saveScoresWithoutConfirmation() throws StaleObjectModificationException {
        if (logger.isInfoEnabled())
            logger.info("saveScores for " + getStudentUid());

        // first, determine which scores were updated
        List updatedGradeRecords = new ArrayList();
        if (getGradebookItems() != null) {
            Iterator itemIter = getGradebookItems().iterator();
            while (itemIter.hasNext()) {
                Object item = itemIter.next();
                if (item instanceof AssignmentGradeRow) {
                    AssignmentGradeRow gradeRow = (AssignmentGradeRow) item;
                    AssignmentGradeRecord gradeRecord = gradeRow.getGradeRecord();

                    if (gradeRecord == null && (gradeRow.getScore() != null || gradeRow.getLetterScore() != null)) {
                        // this is a new grade
                        gradeRecord = new AssignmentGradeRecord(gradeRow.getAssociatedAssignment(), getStudentUid(),
                                null);
                    }
                    if (gradeRecord != null) {
                        if (getGradeEntryByPoints()) {
                            Double originalScore = null;
                            originalScore = gradeRecord.getPointsEarned();

                            if (originalScore != null) {
                                // truncate to two decimals for more accurate comparison
                                originalScore = new Double(FacesUtil.getRoundDown(originalScore.doubleValue(), 2));
                            }
                            Double newScore = gradeRow.getScore();
                            if ((originalScore != null && !originalScore.equals(newScore))
                                    || (originalScore == null && newScore != null)) {
                                gradeRecord.setPointsEarned(newScore);
                                updatedGradeRecords.add(gradeRecord);
                            }
                        } else if (getGradeEntryByPercent()) {
                            Double originalScore = null;
                            originalScore = gradeRecord.getPercentEarned();

                            if (originalScore != null) {
                                // truncate to two decimals for more accurate comparison
                                originalScore = new Double(FacesUtil.getRoundDown(originalScore.doubleValue(), 2));
                            }
                            Double newScore = gradeRow.getScore();
                            if ((originalScore != null && !originalScore.equals(newScore))
                                    || (originalScore == null && newScore != null)) {
                                gradeRecord.setPercentEarned(newScore);
                                updatedGradeRecords.add(gradeRecord);
                            }

                        } else if (getGradeEntryByLetter()) {

                            String originalScore = gradeRecord.getLetterEarned();
                            String newScore = gradeRow.getLetterScore();
                            if ((originalScore != null && !originalScore.equals(newScore))
                                    || (originalScore == null && newScore != null)) {
                                gradeRecord.setLetterEarned(newScore);
                                updatedGradeRecords.add(gradeRecord);
                            }
                        }
                    }
                }
            }
        }

        Set excessiveScores = getGradebookManager().updateStudentGradeRecords(updatedGradeRecords,
                getGradebook().getGrade_type(), getStudentUid());

        if (updatedGradeRecords.size() > 0) {
            getGradebookBean().getEventTrackingService().postEvent("gradebook.updateItemScores",
                    "/gradebook/" + getGradebookId() + "/" + updatedGradeRecords.size() + "/" + getAuthzLevel());
        }
    }

    /**
     * Action listener to update scores.
     */
    public void processUpdateScores() {
        try {
            saveScores();
        } catch (StaleObjectModificationException e) {
            FacesUtil.addErrorMessage(getLocalizedString("assignment_details_locking_failure"));
        }
    }

    /**
     * Save the input scores for the user
     * @throws StaleObjectModificationException
     */
    public void saveScores() throws StaleObjectModificationException {
        if (logger.isInfoEnabled())
            logger.info("saveScores for " + getStudentUid());

        // first, determine which scores were updated
        List updatedGradeRecords = new ArrayList();
        if (getGradebookItems() != null) {
            Iterator itemIter = getGradebookItems().iterator();
            while (itemIter.hasNext()) {
                Object item = itemIter.next();
                if (item instanceof AssignmentGradeRow) {
                    AssignmentGradeRow gradeRow = (AssignmentGradeRow) item;
                    AssignmentGradeRecord gradeRecord = gradeRow.getGradeRecord();

                    if (gradeRecord == null && (gradeRow.getScore() != null || gradeRow.getLetterScore() != null)) {
                        // this is a new grade
                        gradeRecord = new AssignmentGradeRecord(gradeRow.getAssociatedAssignment(), getStudentUid(),
                                null);
                    }
                    if (gradeRecord != null) {
                        if (getGradeEntryByPoints()) {
                            Double originalScore = null;
                            originalScore = gradeRecord.getPointsEarned();

                            if (originalScore != null) {
                                // truncate to two decimals for more accurate comparison
                                originalScore = new Double(FacesUtil.getRoundDown(originalScore.doubleValue(), 2));
                            }
                            Double newScore = gradeRow.getScore();
                            if ((originalScore != null && !originalScore.equals(newScore))
                                    || (originalScore == null && newScore != null)) {
                                gradeRecord.setPointsEarned(newScore);
                                updatedGradeRecords.add(gradeRecord);
                                getGradebookBean().getEventTrackingService().postEvent("gradebook.updateItemScore",
                                        "/gradebook/" + getGradebookUid() + "/"
                                                + gradeRecord.getAssignment().getName() + "/"
                                                + gradeRecord.getStudentId() + "/" + gradeRecord.getPointsEarned()
                                                + "/" + getAuthzLevel());
                            }
                        } else if (getGradeEntryByPercent()) {
                            Double originalScore = null;
                            originalScore = gradeRecord.getPercentEarned();

                            if (originalScore != null) {
                                // truncate to two decimals for more accurate comparison
                                originalScore = new Double(FacesUtil.getRoundDown(originalScore.doubleValue(), 2));
                            }
                            Double newScore = gradeRow.getScore();
                            if ((originalScore != null && !originalScore.equals(newScore))
                                    || (originalScore == null && newScore != null)) {
                                gradeRecord.setPercentEarned(newScore);
                                updatedGradeRecords.add(gradeRecord);
                            }

                        } else if (getGradeEntryByLetter()) {

                            String originalScore = gradeRecord.getLetterEarned();
                            String newScore = gradeRow.getLetterScore();
                            if ((originalScore != null && !originalScore.equals(newScore))
                                    || (originalScore == null && newScore != null)) {
                                gradeRecord.setLetterEarned(newScore);
                                updatedGradeRecords.add(gradeRecord);
                            }
                        }
                    }
                }
            }
        }

        Set excessiveScores = getGradebookManager().updateStudentGradeRecords(updatedGradeRecords,
                getGradebook().getGrade_type(), getStudentUid());

        if (updatedGradeRecords.size() > 0) {
            getGradebookBean().getEventTrackingService().postEvent("gradebook.updateItemScores",
                    "/gradebook/" + getGradebookId() + "/" + updatedGradeRecords.size() + "/" + getAuthzLevel());
            String messageKey = (excessiveScores.size() > 0) ? "inst_view_scores_saved_excessive"
                    : "inst_view_scores_saved";

            // Let the user know.
            FacesUtil.addMessage(getLocalizedString(messageKey));
        }

    }

    private String getColumnHeader(GradableObject gradableObject) {
        if (gradableObject.isCourseGrade()) {
            return getLocalizedString("roster_course_grade_column_name");
        } else {
            return ((Assignment) gradableObject).getName();
        }
    }

    /**
     * If we came to the instructor view from the roster page, we need to
     * set the previous and next student info according to the order and filter
     * on the roster page
     * @return
     */
    private List getOrderedEnrolleesFromRosterPage() {
        // it may be sorted by name, id, cumulative score, or any of the individual
        // assignments
        setSortColumn(getPreferencesBean().getRosterTableSortColumn());
        setSortAscending(getPreferencesBean().isRosterTableSortAscending());

        Map enrollmentMap = getOrderedEnrollmentMapForAllItems();

        List workingEnrollments = new ArrayList(enrollmentMap.keySet());

        if (isEnrollmentSort()) {
            return workingEnrollments;
        }

        Map studentIdItemIdFunctionMap = new HashMap();
        Map studentIdEnrRecMap = new HashMap();
        for (Iterator enrIter = workingEnrollments.iterator(); enrIter.hasNext();) {
            EnrollmentRecord enr = (EnrollmentRecord) enrIter.next();
            if (enr != null) {
                String studentId = enr.getUser().getUserUid();
                Map itemFunctionMap = (Map) enrollmentMap.get(enr);

                studentIdItemIdFunctionMap.put(studentId, itemFunctionMap);
                studentIdEnrRecMap.put(studentId, enr);
            }
        }

        List rosterGradeRecords = getGradebookManager().getAllAssignmentGradeRecords(getGradebookId(),
                studentIdItemIdFunctionMap.keySet());
        Map gradeRecordMap = new HashMap();

        if (!isUserAbleToGradeAll() && isUserHasGraderPermissions()) {
            getGradebookManager().addToGradeRecordMap(gradeRecordMap, rosterGradeRecords,
                    studentIdItemIdFunctionMap);
            // we need to re-sort these records b/c some may actually be null based upon permissions.
            // retrieve updated grade recs from gradeRecordMap
            List updatedGradeRecs = new ArrayList();
            for (Iterator<Map.Entry<String, Map>> iter = gradeRecordMap.entrySet().iterator(); iter.hasNext();) {
                Map.Entry<String, Map> entry = iter.next();
                String studentId = entry.getKey();
                Map itemIdGradeRecMap = (Map) gradeRecordMap.get(studentId);
                if (!itemIdGradeRecMap.isEmpty()) {
                    updatedGradeRecs.addAll(itemIdGradeRecMap.values());
                }
            }
            Collections.sort(updatedGradeRecs, AssignmentGradeRecord.calcComparator);
            rosterGradeRecords = updatedGradeRecs;
        } else {
            getGradebookManager().addToGradeRecordMap(gradeRecordMap, rosterGradeRecords);
        }
        if (logger.isDebugEnabled())
            logger.debug("init - gradeRecordMap.keySet().size() = " + gradeRecordMap.keySet().size());

        List assignments = null;
        String selectedCategoryUid = getSelectedCategoryUid();
        CourseGrade courseGrade = getGradebookManager().getCourseGrade(getGradebookId());
        if (selectedCategoryUid == null) {
            assignments = getGradebookManager().getAssignments(getGradebookId());
        } else {
            assignments = getGradebookManager()
                    .getAssignmentsForCategory(new Long(getSelectedSectionFilterValue().longValue()));
        }

        List courseGradeRecords = getGradebookManager().getPointsEarnedCourseGradeRecords(courseGrade,
                studentIdItemIdFunctionMap.keySet(), assignments, gradeRecordMap);
        Collections.sort(courseGradeRecords, CourseGradeRecord.calcComparator);
        getGradebookManager().addToGradeRecordMap(gradeRecordMap, courseGradeRecords);
        rosterGradeRecords.addAll(courseGradeRecords);

        //do category results
        Map categoryResultMap = new HashMap();
        List categories = getGradebookManager().getCategories(getGradebookId());
        getGradebookManager().addToCategoryResultMap(categoryResultMap, categories, gradeRecordMap,
                studentIdEnrRecMap);
        if (logger.isDebugEnabled())
            logger.debug("init - categoryResultMap.keySet().size() = " + categoryResultMap.keySet().size());

        // Need to sort and page based on a scores column.
        String sortColumn = getSortColumn();
        List scoreSortedEnrollments = new ArrayList();
        for (Iterator iter = rosterGradeRecords.iterator(); iter.hasNext();) {
            AbstractGradeRecord agr = (AbstractGradeRecord) iter.next();
            if (getColumnHeader(agr.getGradableObject()).equals(sortColumn)) {
                scoreSortedEnrollments.add(studentIdEnrRecMap.get(agr.getStudentId()));
            }
        }

        // Put enrollments with no scores at the beginning of the final list.
        workingEnrollments.removeAll(scoreSortedEnrollments);

        // Add all sorted enrollments with scores into the final list
        workingEnrollments.addAll(scoreSortedEnrollments);

        workingEnrollments = finalizeSortingAndPaging(workingEnrollments);

        return workingEnrollments;
    }

    /**
     * If we came to the instructor view from the assign details page, we need to
     * set the previous and next student info according to the order and filter
     * on the assign details page
     * @return
     */
    private List getOrderedEnrolleesFromAssignDetailsPage() {
        setSortColumn(getPreferencesBean().getAssignmentDetailsTableSortColumn());
        setSortAscending(getPreferencesBean().isAssignmentDetailsTableSortAscending());

        List assignGradeRecords = new ArrayList();
        List enrollments = new ArrayList();

        Long assignmentIdAsLong = getAssignmentIdAsLong();
        if (assignmentIdAsLong != null) {
            Assignment prevAssignment = getGradebookManager().getAssignment(assignmentIdAsLong);
            Category category = prevAssignment.getCategory();
            Long catId = null;
            if (category != null)
                catId = category.getId();

            Map enrollmentMap = getOrderedStudentIdEnrollmentMapForItem(catId);
            if (isEnrollmentSort()) {
                return new ArrayList(enrollmentMap.values());
            }

            List studentUids = new ArrayList(enrollmentMap.keySet());

            if (getGradeEntryByPoints())
                assignGradeRecords = getGradebookManager().getAssignmentGradeRecords(prevAssignment, studentUids);
            else if (getGradeEntryByPercent() || getGradeEntryByLetter())
                assignGradeRecords = getGradebookManager().getAssignmentGradeRecordsConverted(prevAssignment,
                        studentUids);

            // Need to sort and page based on a scores column.
            List scoreSortedStudentUids = new ArrayList();
            for (Iterator iter = assignGradeRecords.iterator(); iter.hasNext();) {
                AbstractGradeRecord agr = (AbstractGradeRecord) iter.next();
                scoreSortedStudentUids.add(agr.getStudentId());
            }

            // Put enrollments with no scores at the beginning of the final list.
            studentUids.removeAll(scoreSortedStudentUids);

            // Add all sorted enrollments with scores into the final list
            studentUids.addAll(scoreSortedStudentUids);

            studentUids = finalizeSortingAndPaging(studentUids);

            if (studentUids != null) {
                Iterator studentIter = studentUids.iterator();
                while (studentIter.hasNext()) {
                    String studentId = (String) studentIter.next();
                    EnrollmentRecord enrollee = (EnrollmentRecord) enrollmentMap.get(studentId);
                    if (enrollee != null)
                        enrollments.add(enrollee);
                }
            }
        }

        return enrollments;
    }

    /**
     * 
     * @return String representation of the student's sections/groups
     */
    private String getStudentSectionsForDisplay() {
        StringBuilder sectionList = new StringBuilder();
        List studentMemberships = getGradebookBean().getAuthzService()
                .getStudentSectionMembershipNames(getGradebookUid(), getStudentUid());
        if (studentMemberships != null && !studentMemberships.isEmpty()) {
            Collections.sort(studentMemberships);
            for (int i = 0; i < studentMemberships.size(); i++) {
                String sectionName = (String) studentMemberships.get(i);
                if (i == (studentMemberships.size() - 1))
                    sectionList.append(sectionName);
                else
                    sectionList.append(
                            getLocalizedString("inst_view_sections_list", new String[] { sectionName }) + " ");
            }
        }

        return sectionList.toString();
    }

    /**
     * View maintenance methods.
     */
    public String getReturnToPage() {
        if (returnToPage == null)
            returnToPage = ROSTER_PAGE;
        return returnToPage;
    }

    public void setReturnToPage(String returnToPage) {
        this.returnToPage = returnToPage;
    }

    public String getAssignmentId() {
        return assignmentId;
    }

    public void setAssignmentId(String assignmentId) {
        this.assignmentId = assignmentId;
    }

    private Long getAssignmentIdAsLong() {
        Long id = null;
        if (assignmentId == null)
            return id;

        try {
            id = new Long(assignmentId);

        } catch (Exception e) {
        }

        return id;
    }

    /**
     * Go to assignment details page. Need to override here
     * because on other pages, may need to return to where
     * called from while here we want to go directly to
     * assignment details.
     */
    public String navigateToAssignmentDetails() {
        setNav(null, null, null, "false", null);

        return "assignmentDetails";
    }

    /**
     * Go to either Roster or Assignment Details page.
     */
    public String processCancel() {
        if (new Boolean((String) SessionManager.getCurrentToolSession().getAttribute("middle")).booleanValue()) {
            AssignmentDetailsBean assignmentDetailsBean = (AssignmentDetailsBean) FacesUtil
                    .resolveVariable("assignmentDetailsBean");
            assignmentDetailsBean.setAssignmentId(new Long(assignmentId));

            return navigateToAssignmentDetails();
        } else {
            return getBreadcrumbPage();
        }

    }
}