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; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.validation.Valid; import javax.validation.constraints.NotNull; import org.joda.time.DateTime; import org.joda.time.Interval; import org.opentestsystem.delivery.testadmin.domain.Affinity.AffinityRule; import org.opentestsystem.delivery.testadmin.domain.Affinity.AffinityType; import org.opentestsystem.delivery.testadmin.domain.constraints.DuplicateAvailabilityWindow; import org.opentestsystem.delivery.testadmin.domain.constraints.OverlappingAvailabilityWindow; import org.opentestsystem.delivery.testadmin.domain.constraints.ValidEndTime; import org.opentestsystem.delivery.testreg.domain.User; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.CompoundIndex; import org.springframework.data.mongodb.core.index.CompoundIndexes; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.util.CollectionUtils; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.common.base.Objects; import com.google.common.collect.Lists; @Document @JsonIgnoreProperties(ignoreUnknown = true, value = { "dateWindows" }) @CompoundIndexes(value = { @CompoundIndex(name = "userMongoId", def = "{'user._id':1}", unique = true) }) @DuplicateAvailabilityWindow(message = "{timeperiod.duplicate.invalid}", node = "availabilityWindow.startDateTime") @OverlappingAvailabilityWindow(message = "{timeperiod.overlap.invalid}", node = "availabilityWindow.startDateTime") public class Proctor implements TestAdminBase, DateWindowable { private static final long serialVersionUID = 1830323774952289118L; private static final String GET_RESOURCE_NAME = "/proctor/"; @Id private String id; @Valid private List<Affinity> affinities; @Valid private List<AvailabilityWindow> availabilityWindow; private User user; public String getId() { return this.id; } public void setId(final String id) { this.id = id; } public void setAvailabilityWindow(final List<AvailabilityWindow> availabilityWindows) { this.availabilityWindow = availabilityWindows; } public void addTimePeriods(final List<AvailabilityWindow> availabilityWindows) { if (getAvailabilityWindow() == null || getAvailabilityWindow().isEmpty()) { setAvailabilityWindow(new ArrayList<AvailabilityWindow>()); } getAvailabilityWindow().addAll(availabilityWindows); } public List<AvailabilityWindow> getAvailabilityWindow() { return this.availabilityWindow; } @ValidEndTime @JsonIgnoreProperties(ignoreUnknown = true) public static class AvailabilityWindow implements Serializable, DateWindow { private static final long serialVersionUID = 8156730549695535082L; @NotNull(message = "{timeperiod.starttime.required}") private DateTime startDateTime; @NotNull(message = "{timeperiod.endtime.required}") private DateTime endDateTime; @NotNull(message = "{timeperiod.availability.empty}") private Availability availability; public AvailabilityWindow() { this(null, null, null); } public AvailabilityWindow(final DateTime startTime, final DateTime endTime, final Availability availability) { this.startDateTime = startTime; this.endDateTime = endTime; this.availability = availability; } @Override public DateTime getStartDateTime() { return this.startDateTime; } @JsonDeserialize(using = TZBasedDateTimeDeserialier.class) public void setStartDateTime(final DateTime startTime) { this.startDateTime = startTime; } @Override public DateTime getEndDateTime() { return this.endDateTime; } @JsonDeserialize(using = TZBasedDateTimeDeserialier.class) public void setEndDateTime(final DateTime endTime) { this.endDateTime = endTime; } public Availability getAvailability() { return this.availability; } public void setAvailability(final Availability availability) { this.availability = availability; } @Override public boolean equals(final Object obj) { if (obj instanceof AvailabilityWindow) { final DateTime startDateTime = ((AvailabilityWindow) obj).getStartDateTime(); final DateTime endDateTime = ((AvailabilityWindow) obj).getEndDateTime(); return startDateTime.isEqual(getStartDateTime()) && endDateTime.isEqual(getEndDateTime()); } return false; } @Override public int hashCode() { return Objects.hashCode(getStartDateTime(), getEndDateTime()); } } public List<Affinity> getAffinities() { return this.affinities; } public void setAffinities(final List<Affinity> affinities) { this.affinities = affinities; } public User getUser() { return this.user; } public void setUser(final User user) { this.user = user; } public boolean hasSubjectAffinity() { if (hasAffinities()) { for (final Affinity affinity : this.affinities) { if (affinity.getType() == AffinityType.SUBJECT) { return true; } } } return false; } public boolean hasGradeAffinity() { if (hasAffinities()) { for (final Affinity affinity : this.affinities) { if (affinity.getType() == AffinityType.GRADE) { return true; } } } return false; } public boolean hasAssessmentAffinity() { if (hasAffinities()) { for (final Affinity affinity : this.affinities) { if (affinity.getType() == AffinityType.ASSESSMENT) { return true; } } } return false; } @JsonProperty public String getUrl() { return GET_RESOURCE_NAME + this.id; } public boolean isAvailableForTimeSlot(final TimeSlot timeSlot) { // if the user has not setup any availability windows just return true so the proctor can be scheduled if (this.availabilityWindow == null || this.availabilityWindow.isEmpty()) { return true; } final Interval timeSlotInterval = new Interval(timeSlot.getStartTime(), timeSlot.getEndTime()); boolean passesAvailable = false; boolean passesUnavailable = true; for (final AvailabilityWindow window : this.availabilityWindow) { if (!passesAvailable || passesUnavailable) { final Interval windowInterval = new Interval(window.getStartDateTime(), window.getEndDateTime()); if (Availability.AVAILABLE == window.getAvailability()) { if (windowInterval.contains(timeSlotInterval)) { passesAvailable = true; } } else if (Availability.NOTAVAILABLE == window.getAvailability()) { if (windowInterval.contains(timeSlotInterval) || windowInterval.overlaps(timeSlotInterval)) { passesUnavailable = false; } } } } return passesAvailable && passesUnavailable; } public boolean hasStrictAffinity() { for (final Affinity affinity : this.affinities) { if (affinity.getRule() == AffinityRule.STRICT) { return true; } } return false; } public Affinity findFirstStrictAffinity() { for (final Affinity affinity : this.affinities) { if (affinity.getRule() == AffinityRule.STRICT) { return affinity; } } return null; } public boolean hasAffinities() { return !CollectionUtils.isEmpty(this.affinities); } @Override public List<DateWindow> getDateWindows() { final List<DateWindow> dateWindows = Lists.newArrayList(); if (getAvailabilityWindow() == null) { return dateWindows; } for (final AvailabilityWindow availabilityWindow : getAvailabilityWindow()) { dateWindows.add(availabilityWindow); } return dateWindows; } }