org.opentestsystem.delivery.testadmin.domain.schedule.ScheduledStudent.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.delivery.testadmin.domain.schedule.ScheduledStudent.java

Source

/*
Educational Online Test Delivery System Copyright (c) 2013 American Institutes for Research
    
Distributed under the AIR Open Source License, Version 1.0 See accompanying file AIR-License-1_0.txt or at
http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 */

package org.opentestsystem.delivery.testadmin.domain.schedule;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.joda.time.DateTime;
import org.opentestsystem.delivery.testadmin.domain.AccessibilityEquipment;
import org.opentestsystem.delivery.testreg.domain.Accommodation;
import org.opentestsystem.delivery.testreg.domain.Assessment;
import org.opentestsystem.delivery.testreg.domain.EligibleStudent;
import org.opentestsystem.delivery.testreg.domain.ImplicitEligibilityRule;
import org.opentestsystem.delivery.testreg.domain.Student;
import org.opentestsystem.delivery.testreg.domain.exception.EligibilityException;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

/**
 * Convenience class used to keep track of students, which assessments in this current context they are eligible for,
 * whether or not they actually are scheduled for them, and which accessibility equipment they are eligible for and are
 * scheduled for.
 */
public class ScheduledStudent {

    /**
     * Associates an assessment to a boolean to describe whether or not the assessment has been scheduled for this
     * student
     */
    private Map<Assessment, Boolean> scheduledAssessments;

    /**
     * Associates an assessment with accessibility equipment to a boolean. Keeps track of which assessments have been
     * scheduled for this student, and which accessibility equipment as well.
     */
    private final Table<Assessment, AccessibilityEquipment, Boolean> assessmentToAccessEquip;

    private Student student;

    public ScheduledStudent() {
        super();
        this.scheduledAssessments = new HashMap<Assessment, Boolean>(5);
        this.assessmentToAccessEquip = HashBasedTable.create();

    }

    public ScheduledStudent(final EligibleStudent elig, final Set<Assessment> validAssessments) {
        this();

        // store the student in this class so that it can be used later
        this.student = elig.getStudent();

        // match up the list of valid assessments to the assessments on the EligibleStudent
        // and generate the map of scheduled assessments so that we can keep track of whether or not this
        // student has been scheduled for the assessments he/she is eligible for

        for (final Assessment assess : elig.getAssessments()) {
            if (validAssessments.contains(assess)) {
                this.scheduledAssessments.put(assess, Boolean.FALSE);
            }
        }

    }

    public void setScheduledAssessments(final Map<Assessment, Boolean> scheduledAssessments) {
        this.scheduledAssessments = scheduledAssessments;
    }

    public Student getStudent() {
        return this.student;
    }

    public void setStudent(final Student student) {
        this.student = student;
    }

    /**
     * Can this student use the accessibility equipment for this assessment?
     * 
     * @param equipment
     * @param assessment
     * @return
     */
    public Boolean canUseAccessibilityEquipment(final List<AccessibilityEquipment> equipment,
            final Assessment assessment) {

        // check first to see if there is data in assessmentToAccessEquip
        if (!this.assessmentToAccessEquip.row(assessment).isEmpty()) {
            final Map<AccessibilityEquipment, Boolean> equipForAssessment = this.assessmentToAccessEquip
                    .row(assessment);

            for (final AccessibilityEquipment singleEquip : equipment) {
                if (equipForAssessment.containsKey(singleEquip)) {
                    return true;
                }
            }
        }

        // if we didn't return from above, run the rules

        // find out if the student has accommodations matching equipment
        final List<ImplicitEligibilityRule> rules = new ArrayList<ImplicitEligibilityRule>();
        for (final AccessibilityEquipment ae : equipment) {
            if (ae.getRules() != null) {
                rules.addAll(ae.getRules());
            }
        }
        for (final ImplicitEligibilityRule rule : rules) {
            if (applyRule(assessment, rule, this.student, rule.getField())) {
                return true;
            } else {
                continue;
            }
        }
        return false;
    }

    /**
     * Is this student scheduled for this assessment?
     * 
     * @param assessment
     * @return
     */
    public boolean isStudentScheduled(final Assessment assessment) {
        final Boolean scheduled = this.scheduledAssessments.get(assessment);

        if (scheduled == null) {
            return false;
        } else {
            return scheduled;
        }
    }

    /**
     * Is this student eligible to take this assessment?
     * 
     * @param assessment
     * @return
     */
    public boolean isEligibleForAssessment(final Assessment assessment) {
        return this.scheduledAssessments.containsKey(assessment);
    }

    /**
     * Is this student scheduled for all of the assessments he/she is eligible to take?
     * 
     * @return
     */
    public boolean isStudentFullyScheduled() {
        for (final Boolean scheduled : this.scheduledAssessments.values()) {
            if (!scheduled) {
                return false;
            }
        }

        return true;
    }

    public Map<Assessment, Boolean> getScheduledAssessments() {
        return this.scheduledAssessments;
    }

    public void setAssessmentScheduled(final Assessment assessment) {
        this.scheduledAssessments.put(assessment, Boolean.TRUE);
    }

    /**
     * Add the association between an assessment and eligibility equipment and mark as not yet scheduled.
     * 
     * @param assessment
     * @param accessEquip
     */
    public void addAccessEquipEligibility(final Assessment assessment, final AccessibilityEquipment accessEquip) {
        this.assessmentToAccessEquip.put(assessment, accessEquip, Boolean.FALSE);
    }

    /**
     * Mark the association between assessment and eligibility equipment as scheduled.
     * 
     * @param assessment
     * @param equipment
     */
    public void scheduledToEquipment(final Assessment assessment, final List<AccessibilityEquipment> equipment) {

        for (final AccessibilityEquipment equip : equipment) {
            this.assessmentToAccessEquip.put(assessment, equip, Boolean.TRUE);
        }

    }

    /**
     * Is the equipment even valid for the assessment?
     * 
     * @param assessment
     * @param equipment
     * @return
     */
    public boolean isScheduledForEquipmentInAssessment(final Assessment assessment,
            final AccessibilityEquipment equipment) {
        if (assessmentToAccessEquip.isEmpty()) {
            return false;
        }
        return this.assessmentToAccessEquip.get(assessment, equipment);

    }

    /**
     * Get all the accessibility equipment that this student is eligible for for the given assessment
     * 
     * @param assessment
     * @return
     */
    public Map<AccessibilityEquipment, Boolean> getAllScheduledForEquipmentInAssessment(
            final Assessment assessment) {

        return this.assessmentToAccessEquip.row(assessment);

    }

    /**
     * Get the number of assessments that this student should be scheduled for with accessibility equipment
     * 
     * @return
     */
    public int numAssessmentsAccessEquipRequiredFor() {

        return this.assessmentToAccessEquip.rowKeySet().size();
    }

    private boolean applyRule(final Assessment assessment, final ImplicitEligibilityRule rule,
            final Student student, final String fieldName) {
        Object reflectedValue = null;
        try {
            reflectedValue = PropertyUtils.getProperty(student, fieldName);
            if (reflectedValue == null || !evaluateOperator(reflectedValue, rule)) {
                return false;
            }
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            final Map<String, Object> accommodation = student.getAccommodation(assessment.getSubjectCode());
            if (accommodation != null) {
                try {
                    reflectedValue = accommodation.get(fieldName);
                } catch (Exception e1) {
                    throw new EligibilityException("eligibility.invalid.compare.field", new String[] { fieldName },
                            e);
                }
            }

            if (reflectedValue == null || !evaluateOperator(reflectedValue, rule)) {
                return false;
            }
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    private boolean evaluateOperator(final Object value, final ImplicitEligibilityRule rule) {

        if (rule.getOperatorType().isValidFor(value.getClass())) {
            switch (rule.getOperatorType()) {
            case EQUALS:
                return value.equals(convertTo(rule.getValue(), value.getClass()));
            case GREATER_THAN:
                return ((Comparable<Object>) value).compareTo(convertTo(rule.getValue(), value.getClass())) >= 1;
            case GREATER_THAN_EQUALS:
                return ((Comparable<Object>) value).compareTo(convertTo(rule.getValue(), value.getClass())) >= 0;
            case LESS_THAN:
                return ((Comparable<Object>) value).compareTo(convertTo(rule.getValue(), value.getClass())) <= 1;
            case LESS_THAN_EQUALS:
                return ((Comparable<Object>) value).compareTo(convertTo(rule.getValue(), value.getClass())) <= 0;
            default:
                throw new EligibilityException("eligiblity.invalid.operator.forclass",
                        new String[] { value.getClass().toString(), rule.getOperatorType().name() });
            }
        } else {
            throw new EligibilityException("eligiblity.invalid.operator.forclass",
                    new String[] { value.getClass().toString(), rule.getOperatorType().name() });
        }

    }

    @SuppressWarnings("unchecked")
    private <T> T convertTo(final String value, final Class<T> clazz) {

        try {
            if (String.class.isAssignableFrom(clazz)) {
                return (T) value;
            } else if (Number.class.isAssignableFrom(clazz)) {
                return clazz.getConstructor(String.class).newInstance(value);
            } else if (DateTime.class.isAssignableFrom(clazz)) {
                return (T) DateTime.parse(value);
            } else if (Enum.class.isAssignableFrom(clazz)) {
                Method getEnum = null;
                try {
                    getEnum = clazz.getDeclaredMethod("getEnumByValue", String.class);
                } catch (final NoSuchMethodException me) {
                    getEnum = clazz.getMethod("valueOf", String.class);
                }
                return (T) getEnum.invoke(null, value);
            } else {
                throw new EligibilityException("eligibility.value.convert.error",
                        new String[] { value, clazz.toString() });
            }
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | NoSuchMethodException | SecurityException e) {
            throw new EligibilityException("eligibility.value.convert.error",
                    new String[] { value, clazz.toString() }, e);
        }

    }

}