Java tutorial
/* 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); } } }