Java tutorial
/** * Copyright 2012 The Kuali 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.osedu.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.kuali.student.enrollment.class2.acal.service.impl; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.joda.time.DateMidnight; import org.joda.time.DateTimeConstants; import org.kuali.rice.core.api.criteria.Predicate; import org.kuali.rice.core.api.criteria.QueryByCriteria; import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; import org.kuali.rice.core.api.util.ConcreteKeyValue; import org.kuali.rice.core.api.util.KeyValue; import org.kuali.rice.krad.uif.UifConstants; import org.kuali.rice.krad.uif.component.BindingInfo; import org.kuali.rice.krad.uif.container.CollectionGroup; import org.kuali.rice.krad.uif.control.SelectControl; import org.kuali.rice.krad.uif.field.InputField; import org.kuali.rice.krad.uif.util.ComponentFactory; import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; import org.kuali.rice.krad.uif.view.ViewModel; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krms.api.KrmsConstants; import org.kuali.rice.krms.api.repository.RuleManagementService; import org.kuali.rice.krms.api.repository.reference.ReferenceObjectBinding; import org.kuali.student.common.uif.service.impl.KSViewHelperServiceImpl; import org.kuali.student.enrollment.class2.acal.dto.AcademicTermWrapper; import org.kuali.student.enrollment.class2.acal.dto.AcalEventWrapper; import org.kuali.student.enrollment.class2.acal.dto.ExamPeriodWrapper; import org.kuali.student.enrollment.class2.acal.dto.HolidayCalendarWrapper; import org.kuali.student.enrollment.class2.acal.dto.HolidayWrapper; import org.kuali.student.enrollment.class2.acal.dto.KeyDateWrapper; import org.kuali.student.enrollment.class2.acal.dto.KeyDatesGroupWrapper; import org.kuali.student.enrollment.class2.acal.dto.TimeSetWrapper; import org.kuali.student.enrollment.class2.acal.form.AcademicCalendarForm; import org.kuali.student.enrollment.class2.acal.keyvalue.AcalEventTypeKeyValues; import org.kuali.student.enrollment.class2.acal.service.AcademicCalendarViewHelperService; import org.kuali.student.enrollment.class2.acal.util.AcalCommonUtils; import org.kuali.student.enrollment.class2.acal.util.CalendarConstants; import org.kuali.student.r2.common.dto.ContextInfo; import org.kuali.student.r2.common.util.date.DateFormatters; import org.kuali.student.r2.core.acal.dto.AcademicCalendarInfo; import org.kuali.student.r2.core.acal.dto.AcalEventInfo; import org.kuali.student.r2.core.acal.dto.ExamPeriodInfo; import org.kuali.student.r2.core.acal.dto.HolidayCalendarInfo; import org.kuali.student.r2.core.acal.dto.HolidayInfo; import org.kuali.student.r2.core.acal.dto.KeyDateInfo; import org.kuali.student.r2.core.acal.dto.TermInfo; import org.kuali.student.r2.core.acal.service.AcademicCalendarService; import org.kuali.student.r2.core.acal.service.TermCodeGenerator; import org.kuali.student.r2.core.acal.service.impl.TermCodeGeneratorImpl; import org.kuali.student.r2.core.atp.dto.AtpAtpRelationInfo; import org.kuali.student.r2.core.atp.service.AtpService; import org.kuali.student.r2.core.class1.state.dto.StateInfo; import org.kuali.student.r2.core.class1.type.dto.TypeInfo; import org.kuali.student.r2.core.class1.type.dto.TypeTypeRelationInfo; import org.kuali.student.r2.core.class1.type.service.TypeService; import org.kuali.student.r2.core.constants.AcademicCalendarServiceConstants; import org.kuali.student.r2.core.constants.AtpServiceConstants; import org.kuali.student.r2.core.constants.TypeServiceConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.json.Json; import javax.json.JsonObjectBuilder; import javax.xml.namespace.QName; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.kuali.rice.core.api.criteria.PredicateFactory.and; import static org.kuali.rice.core.api.criteria.PredicateFactory.equal; import static org.kuali.rice.core.api.criteria.PredicateFactory.equalIgnoreCase; /** * This is the helper class for AcademicCalendar Controller * * @author Kuali Student Team */ public class AcademicCalendarViewHelperServiceImpl extends KSViewHelperServiceImpl implements AcademicCalendarViewHelperService { private static final Logger LOG = LoggerFactory.getLogger(AcademicCalendarViewHelperServiceImpl.class); private AcademicCalendarService acalService; private TypeService typeService; private AtpService atpService; private TermCodeGenerator termCodeGenerator; private transient RuleManagementService ruleManagementService; public static Logger getLog() { return LOG; } public AcademicCalendarViewHelperServiceImpl getInstance() { return this; } /** * This method builds an academic calendar for ui processing. Basically, it builds the wrappers * around acal,events,terms,holidays,keydates etc. * * @param acalId academic calendar id * @param acalForm AcademicCalendarForm */ public void populateAcademicCalendar(String acalId, AcademicCalendarForm acalForm) { getLog().debug("Loading Academic calendar for the id {}", acalId); try { AcademicCalendarInfo acalInfo = getAcalService().getAcademicCalendar(acalId, createContextInfo()); acalForm.setAcademicCalendarInfo(acalInfo); acalForm.setAdminOrgName(getAdminOrgNameById(acalInfo.getAdminOrgId())); acalForm.setNewCalendar(false); acalForm.setOfficialCalendar( StringUtils.equals(acalInfo.getStateKey(), AtpServiceConstants.ATP_OFFICIAL_STATE_KEY)); //Events List<AcalEventWrapper> events = populateEventWrappers(acalInfo.getId()); acalForm.setEvents(events); //Holiday calendars associated with acal. List<HolidayCalendarWrapper> holidayCalendarWrapperList = populateHolidayCalendars( acalInfo.getHolidayCalendarIds()); acalForm.setHolidayCalendarList(holidayCalendarWrapperList); //Terms (which in turn builds keydate groups and keydates) boolean calculateInstrDays = !holidayCalendarWrapperList.isEmpty(); List<AcademicTermWrapper> termWrappers = populateTermWrappers(acalId, false, true); acalForm.setTermWrapperList(termWrappers); // set the meta info on the form acalForm.setMeta(acalInfo.getMeta()); } catch (Exception e) { if (getLog().isDebugEnabled()) { getLog().debug(String.format("Error loading academic calendar [id=%s]", acalId), e); } throw convertServiceExceptionsToUI(e); } } /** * Builds the wrappers for all the holiday calendars associated with acal. * * @param holidayCalendarIds list of holiday calendars to populate * @return list of wrappers for the holiday calendars * @throws Exception */ protected List<HolidayCalendarWrapper> populateHolidayCalendars(List<String> holidayCalendarIds) throws Exception { getLog().debug("Loading all the holiday calendars associated with the Acal"); List<HolidayCalendarWrapper> holidayCalendarWrapperList = new ArrayList<HolidayCalendarWrapper>(); ContextInfo contextInfo = createContextInfo(); for (String hcId : holidayCalendarIds) { HolidayCalendarWrapper holidayCalendarWrapper = new HolidayCalendarWrapper(); List<HolidayWrapper> holidays = new ArrayList<HolidayWrapper>(); //need to retrieve HolidayCalendarInfo and all Holidays to form the HolidayCalendarWrapper. HolidayCalendarInfo holidayCalendarInfo = getAcalService().getHolidayCalendar(hcId, contextInfo); holidayCalendarWrapper.setHolidayCalendarInfo(holidayCalendarInfo); holidayCalendarWrapper.setId(holidayCalendarInfo.getId()); holidayCalendarWrapper .setAdminOrgName(AcalCommonUtils.getAdminOrgNameById(holidayCalendarInfo.getAdminOrgId())); StateInfo hcState = getAcalService().getHolidayCalendarState(holidayCalendarInfo.getStateKey(), contextInfo); holidayCalendarWrapper.setStateName(hcState.getName()); List<HolidayInfo> holidayInfoList = getAcalService() .getHolidaysForHolidayCalendar(holidayCalendarInfo.getId(), contextInfo); for (HolidayInfo holidayInfo : holidayInfoList) { HolidayWrapper holiday = new HolidayWrapper(holidayInfo); TypeInfo typeInfo = getAcalService().getHolidayType(holidayInfo.getTypeKey(), contextInfo); holiday.setTypeName(typeInfo.getName()); holidays.add(holiday); } holidayCalendarWrapper.setHolidays(holidays); holidayCalendarWrapperList.add(holidayCalendarWrapper); } return holidayCalendarWrapperList; } /** * Builds the wrapper for Events * * @param acalId * @return * @throws Exception */ public List<AcalEventWrapper> populateEventWrappers(String acalId) throws Exception { if (getLog().isDebugEnabled()) { getLog().debug("Loading all the holiday calendars associated with the Acal"); } List<AcalEventInfo> eventInfos = getAcalService().getAcalEventsForAcademicCalendar(acalId, createContextInfo()); List<AcalEventWrapper> events = new ArrayList<AcalEventWrapper>(); for (AcalEventInfo eventInfo : eventInfos) { AcalEventWrapper event = new AcalEventWrapper(eventInfo, false); TypeInfo type = getTypeInfo(event.getEventTypeKey()); event.setEventTypeName(type.getName()); events.add(event); } return events; } /** * Builds wrappers around the terms * * @param acalId * @param isCopy * @return */ public List<AcademicTermWrapper> populateTermWrappers(String acalId, boolean isCopy, boolean calculateInstrDays) { ContextInfo contextInfo = createContextInfo(); getLog().debug("Loading all the terms associated with an acal [id={}]", acalId); List<AcademicTermWrapper> termWrappers = new ArrayList<AcademicTermWrapper>(); try { List<TermInfo> termInfos = getAcalService().getTermsForAcademicCalendar(acalId, contextInfo); // we go through the terms once to process all parent and sub terms. This list is to process everything else List<TermInfo> processedTerms = new ArrayList<TermInfo>(); for (TermInfo termInfo : termInfos) { if (!processedTerms.contains(termInfo)) { List<AtpAtpRelationInfo> atpRelations = getAtpService().getAtpAtpRelationsByTypeAndAtp( termInfo.getId(), AtpServiceConstants.ATP_ATP_RELATION_INCLUDES_TYPE_KEY, contextInfo); if (atpRelations != null && atpRelations.size() > 0) { // if you're a parent term AcademicTermWrapper termWrapper = populateTermWrapper(termInfo, isCopy, calculateInstrDays); // create the term wrapper for the parent term //add the parent term into the term wrapper list termWrappers.add(termWrapper); processedTerms.add(termInfo); //add the sub terms into the term wrapper list for (AtpAtpRelationInfo parentTermRelations : atpRelations) { // we already have all the terms in the wrappers. We just need to set the parent child relationships for (TermInfo tInfo : termInfos) { // Find the subterms if (parentTermRelations.getRelatedAtpId().equals(tInfo.getId())) { AcademicTermWrapper subTermWrapper = populateTermWrapper(tInfo, isCopy, calculateInstrDays); subTermWrapper.setParentTerm(termInfo.getTypeKey()); // the name here is ambigious subTermWrapper.setSubTerm(true); termWrapper.setHasSubterm(true); termWrapper.getSubterms().add(subTermWrapper); // Allow parent term info to be set to copied term for sorting. subTermWrapper.setParentTermInfo(termInfo); subTermWrapper.setParentTermName(termInfo.getName()); termWrappers.add(subTermWrapper); processedTerms.add(tInfo); // this term has now been processed } } } } } } // The previous loop deals with parents and children. Now we have to deal with term that aren't parents or children for (TermInfo termInfo : termInfos) { if (!processedTerms.contains(termInfo)) { AcademicTermWrapper termWrapper = populateTermWrapper(termInfo, isCopy, calculateInstrDays); // create the term wrapper for the parent term //add the parent term into the term wrapper list termWrappers.add(termWrapper); processedTerms.add(termInfo); } } //sort term wrappers by start date sortTermWrappers(termWrappers); } catch (Exception e) { throw new RuntimeException(e); } return termWrappers; } public AcademicTermWrapper populateTermWrapper(TermInfo termInfo, boolean isCopy, boolean calculateInstrDays) throws Exception { getLog().debug("Populating Term - {}", termInfo.getId()); TypeInfo type = getAcalService().getTermType(termInfo.getTypeKey(), createContextInfo()); AcademicTermWrapper termWrapper = new AcademicTermWrapper(termInfo, isCopy); termWrapper.setTypeInfo(type); termWrapper.setTermNameForUI(type.getName()); if (isCopy) { termWrapper.setName(type.getName()); } //Populate examdates List<ExamPeriodInfo> examPeriodInfos = getAcalService().getExamPeriodsForTerm(termInfo.getId(), createContextInfo()); if (examPeriodInfos != null && examPeriodInfos.size() > 0) { //only one or none for (ExamPeriodInfo examPeriodInfo : examPeriodInfos) { ExamPeriodWrapper examPeriodWrapper = new ExamPeriodWrapper(examPeriodInfo, isCopy); examPeriodWrapper.setExcludeSaturday(Boolean.parseBoolean(examPeriodInfo .getAttributeValue(AcademicCalendarServiceConstants.EXAM_PERIOD_EXCLUDE_SATURDAY_ATTR))); examPeriodWrapper.setExcludeSunday(Boolean.parseBoolean(examPeriodInfo .getAttributeValue(AcademicCalendarServiceConstants.EXAM_PERIOD_EXCLUDE_SUNDAY_ATTR))); termWrapper.getExamdates().add(examPeriodWrapper); } } //Populate keydates List<KeyDateInfo> keydateList = getAcalService().getKeyDatesForTerm(termInfo.getId(), createContextInfo()); List<TypeInfo> keyDateTypes = getTypeService().getAllowedTypesForType(termInfo.getTypeKey(), createContextInfo()); Map<String, KeyDatesGroupWrapper> keyDateGroup = new HashMap<String, KeyDatesGroupWrapper>(); for (KeyDateInfo keyDateInfo : keydateList) { KeyDateWrapper keyDateWrapper = new KeyDateWrapper(keyDateInfo, isCopy); type = getTypeService().getType(keyDateInfo.getTypeKey(), createContextInfo()); keyDateWrapper.setTypeInfo(type); keyDateWrapper.setKeyDateNameUI(type.getName()); addKeyDateGroup(keyDateTypes, keyDateWrapper, keyDateGroup); } for (KeyDatesGroupWrapper group : keyDateGroup.values()) { if (!group.getKeydates().isEmpty()) { //KSENROLL-12648: workaround for rice 2.4 upgrade issue. //Construct key date types JSON string for js to populate key date type dropdown in key date add blank line if (StringUtils.isBlank(group.getKeyDateTypesJSON())) { List<TypeInfo> types = getTypeService().getTypesForGroupType(group.getKeyDateGroupType(), createContextInfo()); JsonObjectBuilder keyDateTypesJsonBuilder = Json.createObjectBuilder(); for (TypeInfo typeInfo : types) { if (!group.isKeyDateExists(typeInfo.getKey())) { keyDateTypesJsonBuilder.add(typeInfo.getKey(), typeInfo.getName().replace("\"", "\\\"")); } } group.setKeyDateTypesJSON(keyDateTypesJsonBuilder.build().toString()); } termWrapper.getKeyDatesGroupWrappers().add(group); } } if (calculateInstrDays) { populateInstructionalDays(termWrapper); } return termWrapper; } /** * Adds a keydate to a proper group. * * @param keyDateTypes * @param keyDateWrapper * @param keyDateGroup */ protected void addKeyDateGroup(List<TypeInfo> keyDateTypes, KeyDateWrapper keyDateWrapper, Map<String, KeyDatesGroupWrapper> keyDateGroup) { getLog().debug("Adding key date to a group"); for (TypeInfo keyDateType : keyDateTypes) { try { List<TypeInfo> allowedTypes = getTypeService().getTypesForGroupType(keyDateType.getKey(), createContextInfo()); for (TypeInfo allowedType : allowedTypes) { if (StringUtils.equals(allowedType.getKey(), keyDateWrapper.getKeyDateType())) { KeyDatesGroupWrapper keyDatesGroup = keyDateGroup.get(keyDateType.getKey()); if (keyDatesGroup == null) { keyDatesGroup = new KeyDatesGroupWrapper(keyDateType.getKey(), keyDateType.getName()); keyDateGroup.put(keyDateType.getKey(), keyDatesGroup); } keyDatesGroup.getKeydates().add(keyDateWrapper); break; } } } catch (Exception e) { throw new RuntimeException(e); } } } /** * This method finds the latest Academic Calendar. * It first tries to find the current year acal. If there is no match found, it looks for last year * * @return * @throws Exception */ public AcademicCalendarInfo getLatestAcademicCalendar() throws Exception { if (getLog().isDebugEnabled()) { getLog().debug("Finding the latest Academic calendar"); } int currentYear = Calendar.getInstance().get(Calendar.YEAR); List<AcademicCalendarInfo> academicCalendarInfoList = getAcalService() .getAcademicCalendarsByStartYear(currentYear, createContextInfo()); if ((null == academicCalendarInfoList) || academicCalendarInfoList.isEmpty()) { academicCalendarInfoList = getAcalService().getAcademicCalendarsByStartYear((currentYear - 1), createContextInfo()); } if ((null == academicCalendarInfoList) || (academicCalendarInfoList.size() == 0)) { return null; } else { // If Calendars are found search through them to find the most recently created. // The number of calendars should be small so naive search possible. AcademicCalendarInfo newestCalendar = academicCalendarInfoList.get(0); for (AcademicCalendarInfo calendarTemp : academicCalendarInfoList) { // Compare the time when the calendars are created and pick the higher one (most recent). if (calendarTemp.getMeta().getCreateTime() .compareTo(newestCalendar.getMeta().getCreateTime()) > 0) { newestCalendar = calendarTemp; } } return newestCalendar; } } public void copyToCreateAcademicCalendar(AcademicCalendarForm form) { AcademicCalendarInfo orgAcalInfo = form.getCopyFromAcal(); if (orgAcalInfo == null || StringUtils.isBlank(orgAcalInfo.getId())) { throw new RuntimeException("ACal Info doesn't exists to copy."); } // 1. copy over events List<AcalEventInfo> orgEventInfoList = null; try { orgEventInfoList = getAcalService().getAcalEventsForAcademicCalendar(orgAcalInfo.getId(), createContextInfo()); } catch (Exception e) { throw convertServiceExceptionsToUI(e); } List<AcalEventWrapper> newEventList = new ArrayList<AcalEventWrapper>(); for (AcalEventInfo orgEventInfo : orgEventInfoList) { AcalEventWrapper newEvent = new AcalEventWrapper(orgEventInfo, true); try { TypeInfo type = getTypeInfo(orgEventInfo.getTypeKey()); newEvent.setEventTypeName(type.getName()); } catch (Exception e) { throw convertServiceExceptionsToUI(e); } newEventList.add(newEvent); } form.setEvents(newEventList); // 2. copy over terms List<AcademicTermWrapper> newTermList = populateTermWrappers(orgAcalInfo.getId(), true, false); form.setTermWrapperList(newTermList); form.setMeta(orgAcalInfo.getMeta()); //clear exam period list for each term since they are not supposed to be copied for (AcademicTermWrapper newTerm : newTermList) { newTerm.getExamdates().clear(); } } /** * Override default handling of adding blank line to add custom validation and custom functions on added lines * */ @Override public void processCollectionAddBlankLine(ViewModel model, String collectionId, String collectionPath) { BindingInfo bindingInfo = (BindingInfo) model.getViewPostMetadata().getComponentPostData(collectionId, UifConstants.PostMetadata.BINDING_INFO); Class<?> collectionObjectClass = (Class<?>) model.getViewPostMetadata().getComponentPostData(collectionId, UifConstants.PostMetadata.COLL_OBJECT_CLASS); //Execute custom functions on added lines for Academic Calendars if (model instanceof AcademicCalendarForm) { processAddBlankLines(model); } //If collection is a KeyDate, check if types are available to add if (collectionObjectClass.equals(KeyDateWrapper.class)) { AcademicCalendarForm form = (AcademicCalendarForm) model; KeyDatesGroupWrapper groupWrapper = ObjectPropertyUtils.getPropertyValue(form, bindingInfo.getBindByNamePrefix()); boolean isValid = false; //Loop through types and already added KeyDates to determine if type is available to add if (StringUtils.isNotBlank(groupWrapper.getKeyDateGroupType())) { try { List<TypeInfo> types = getTypeService().getTypesForGroupType(groupWrapper.getKeyDateGroupType(), createContextInfo()); for (TypeInfo type : types) { if (!groupWrapper.isKeyDateExists(type.getKey())) { isValid = true; } } } catch (Exception e) { throw new RuntimeException(e); } } //If type is available to add, create new line if (isValid) { super.processCollectionAddBlankLine(model, collectionId, collectionPath); } //else display growl message stating no more types are available to add else { GlobalVariables.getMessageMap().addGrowlMessage("", CalendarConstants.MessageKeys.ERROR_KEY_DATE_TYPES_EMPTY, ""); } } //If collection is a Event, check if types are available to add else if (collectionObjectClass.equals(AcalEventWrapper.class)) { AcademicCalendarForm form = (AcademicCalendarForm) model; //If previous events exist, check if types exist to add new line if (!form.getEvents().isEmpty()) { boolean isValid = false; //Loop through types and already added Events to determine if type is available to add for (AcalEventWrapper wrapper : form.getEvents()) { AcalEventTypeKeyValues acalEventTypeKeyValues = new AcalEventTypeKeyValues(); for (KeyValue keyValue : acalEventTypeKeyValues.getKeyValues(form)) { if (keyValue.getKey().isEmpty()) { continue; } else if (!wrapper.getEventTypeKey().equals(keyValue.getKey())) { isValid = true; } } } //If type is available to add, create new line if (isValid) { super.processCollectionAddBlankLine(model, collectionId, collectionPath); } //else display growl message stating no more types are available to add else { GlobalVariables.getMessageMap().addGrowlMessage("", CalendarConstants.MessageKeys.ERROR_EVENT_TYPES_EMPTY, ""); } } //else add new line else { super.processCollectionAddBlankLine(model, collectionId, collectionPath); } } //else add new line else { super.processCollectionAddBlankLine(model, collectionId, collectionPath); } } /** * Execute custom functions on added lines * * @param model */ protected void processAddBlankLines(Object model) { AcademicCalendarForm form = (AcademicCalendarForm) model; //Loop through all added lines on form to execute custom functions for KeyDates and Events for (Object addLine : form.getAddedCollectionItems()) { //If added line is a KeyDate, set name of line for display if (addLine instanceof KeyDateWrapper) { KeyDateWrapper keydate = (KeyDateWrapper) addLine; try { if (StringUtils.isNotEmpty(keydate.getKeyDateType())) { TypeInfo type = getTypeService().getType(keydate.getKeyDateType(), createContextInfo()); keydate.setKeyDateNameUI(type.getName()); keydate.setTypeInfo(type); } } catch (Exception e) { throw new RuntimeException(e); } } //If added line is a Event, set name of line for display if (addLine instanceof AcalEventWrapper) { AcalEventWrapper acalEventWrapper = (AcalEventWrapper) addLine; try { if (!StringUtils.isBlank(acalEventWrapper.getEventTypeKey())) { TypeInfo type = getTypeService().getType(acalEventWrapper.getEventTypeKey(), createContextInfo()); acalEventWrapper.setEventTypeName(type.getName()); } } catch (Exception e) { throw new RuntimeException(e); } } } } /** * Performs validation on adding holiday calendar, key date groups, key date or event. * */ @Override protected boolean performAddLineValidation(ViewModel model, Object newLine, String collectionId, String collectionPath) { if (newLine instanceof HolidayCalendarWrapper) { AcademicCalendarForm form = (AcademicCalendarForm) model; for (HolidayCalendarWrapper holidayCalendarWrapper : form.getHolidayCalendarList()) { if (StringUtils.equals(holidayCalendarWrapper.getId(), ((HolidayCalendarWrapper) newLine).getId())) { GlobalVariables.getMessageMap().putError("newCollectionLines['holidayCalendarList'].id", CalendarConstants.MessageKeys.ERROR_DUPLICATE_HCAL, holidayCalendarWrapper.getHolidayCalendarInfo().getName()); return false; } } } else if (newLine instanceof KeyDatesGroupWrapper) { AcademicCalendarForm form = (AcademicCalendarForm) model; form.setAddLineValid(true); form.setValidationJSONString("{}"); KeyDatesGroupWrapper keydateGroup = (KeyDatesGroupWrapper) newLine; if (StringUtils.isEmpty(keydateGroup.getKeyDateGroupType())) { GlobalVariables.getMessageMap().putErrorForSectionId(collectionId, CalendarConstants.MessageKeys.ERROR_KEY_DATE_GROUP_TYPE_REQUIRED); StringBuilder sb = new StringBuilder(); sb.append("\"key_date_group_type\":\"Required\""); form.setValidationJSONString("{" + sb.toString() + "}"); form.setAddLineValid(false); return false; } } else if (newLine instanceof AcademicTermWrapper) { //if tries to add a Subterm, the parent term has to exist in the Form AcademicTermWrapper term = (AcademicTermWrapper) newLine; AcademicCalendarForm acalForm = (AcademicCalendarForm) model; acalForm.setValidationJSONString("{}"); if (term.getParentTerm() != null && !StringUtils.isBlank(term.getParentTerm())) { AcademicTermWrapper parentTerm = null; for (AcademicTermWrapper termWrapper : acalForm.getTermWrapperList()) { String termType = termWrapper.getTermType(); if (StringUtils.isBlank(termType)) { termType = termWrapper.getTermInfo().getTypeKey(); } if (term.getParentTerm().equals(termType)) { parentTerm = termWrapper; break; } } if (parentTerm == null) { return false; } if (!AcalCommonUtils.isDateWithinRange(parentTerm.getStartDate(), parentTerm.getEndDate(), term.getStartDate()) || !AcalCommonUtils.isDateWithinRange(parentTerm.getStartDate(), parentTerm.getEndDate(), term.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId(collectionId, CalendarConstants.MessageKeys.ERROR_TERM_NOT_IN_TERM_RANGE, term.getName(), parentTerm.getName()); } } if (term.getTermType() == null || StringUtils.isBlank(term.getTermType())) { GlobalVariables.getMessageMap().putError("newCollectionLines['termWrapperList'].termType", CalendarConstants.MessageKeys.ERROR_TERM_TYPE_REQUIRED); } if (term.getStartDate() == null) { GlobalVariables.getMessageMap().putError("newCollectionLines['termWrapperList'].startDate", CalendarConstants.MessageKeys.ERROR_KEY_DATE_START_DATE_REQUIRED, "Add Term"); } if (term.getEndDate() == null) { GlobalVariables.getMessageMap().putError("newCollectionLines['termWrapperList'].endDate", CalendarConstants.MessageKeys.ERROR_KEY_DATE_END_DATE_REQUIRED, "Add Term"); } } return super.performAddLineValidation(model, newLine, collectionId, collectionPath); } /** * This method is being called by KRAD to populate keydate types drop down. There would be no reference * for this method in the code as it has it's reference at the AcademicTermPage.xml page * * @param field * @param acalForm */ @SuppressWarnings("unused") public void populateKeyDateTypes(InputField field, AcademicCalendarForm acalForm) { List<KeyValue> keyValues = new ArrayList<KeyValue>(); keyValues.add(new ConcreteKeyValue("", "Select Keydate Type")); CollectionGroup collectionGroup = (CollectionGroup) field.getContext() .get(UifConstants.ContextVariableNames.PARENT); KeyDatesGroupWrapper groupWrapper = ObjectPropertyUtils.getPropertyValue(acalForm, collectionGroup.getBindingInfo().getBindByNamePrefix()); if (StringUtils.isNotBlank(groupWrapper.getKeyDateGroupType())) { try { List<TypeInfo> types = getTypeService().getTypesForGroupType(groupWrapper.getKeyDateGroupType(), createContextInfo()); for (TypeInfo type : types) { if (!groupWrapper.isKeyDateExists(type.getKey())) { keyValues.add(new ConcreteKeyValue(type.getKey(), type.getName())); } } } catch (Exception e) { throw new RuntimeException(e); } } ((SelectControl) field.getControl()).setOptions(keyValues); } /** * This method is being called by KRAD to populate keydate group types drop down. There would be no reference * for this method in the code as it has it's reference at the AcademicTermPage.xml page * * @param field * @param acalForm */ @SuppressWarnings("unused") public void populateKeyDateGroupTypes(InputField field, AcademicCalendarForm acalForm) { boolean isAddLine = BooleanUtils .toBoolean((Boolean) field.getContext().get(UifConstants.ContextVariableNames.IS_ADD_LINE)); if (!isAddLine) { return; } List<KeyValue> keyValues = new ArrayList<KeyValue>(); keyValues.add(new ConcreteKeyValue("", "Select Keydate Group Type")); CollectionGroup collectionGroup = (CollectionGroup) field.getContext() .get(UifConstants.ContextVariableNames.COLLECTION_GROUP); AcademicTermWrapper termWrapper = ObjectPropertyUtils.getPropertyValue(acalForm, collectionGroup.getBindingInfo().getBindByNamePrefix()); try { List<TypeInfo> keyDateGroupTypes = getAcalService() .getKeyDateTypesForTermType(termWrapper.getTermType(), createContextInfo()); for (TypeInfo keyDateGroupType : keyDateGroupTypes) { if (!termWrapper.isKeyDateGroupExists(keyDateGroupType.getKey())) { keyValues.add(new ConcreteKeyValue(keyDateGroupType.getKey(), keyDateGroupType.getName())); } } } catch (Exception e) { throw new RuntimeException(e); } ((SelectControl) field.getControl()).setOptions(keyValues); } /** * This method is called during calendar save. As there is inconsistency between ui and the services handling * the allday and daterange, this method is like an adapter to convert the ui data to the data needed by services. * * In Services, it handles date range as point in time * More info at https://wiki.kuali.org/display/STUDENT/Storing+and+Querying+Milestone+Dates * * @param acalForm */ public void populateAcademicCalendarDefaults(AcademicCalendarForm acalForm) { for (AcalEventWrapper eventWrapper : acalForm.getEvents()) { try { if (!StringUtils.isBlank(eventWrapper.getEventTypeKey())) { TypeInfo type = getTypeService().getType(eventWrapper.getEventTypeKey(), createContextInfo()); eventWrapper.setEventTypeName(type.getName()); } } catch (Exception e) { throw new RuntimeException(e); } // first setting AllDay, DateRange, etc. String keyDatePath = "events[" + acalForm.getEvents().indexOf(eventWrapper) + "]"; getValidDateTimeErrors(eventWrapper.getEventTypeKey(), eventWrapper, eventWrapper.getEventTypeName(), keyDatePath); eventWrapper.getAcalEventInfo().setStartDate(getStartDateWithUpdatedTime(eventWrapper, false)); setEventEndDate(eventWrapper); } for (int index = 0; index < acalForm.getTermWrapperList().size(); index++) { AcademicTermWrapper academicTermWrapper = acalForm.getTermWrapperList().get(index); String keyDateGroupSectionName = "acal-term-keydatesgroup_line" + index; for (KeyDatesGroupWrapper keyDatesGroupWrapper : academicTermWrapper.getKeyDatesGroupWrappers()) { for (KeyDateWrapper keyDateWrapper : keyDatesGroupWrapper.getKeydates()) { try { if (StringUtils.isNotEmpty(keyDateWrapper.getKeyDateType())) { TypeInfo type = getTypeService().getType(keyDateWrapper.getKeyDateType(), createContextInfo()); keyDateWrapper.setKeyDateNameUI(type.getName()); keyDateWrapper.setTypeInfo(type); } } catch (Exception e) { throw new RuntimeException(e); } String keyDatePath = "termWrapperList[" + index + "].keyDatesGroupWrappers[" + academicTermWrapper.getKeyDatesGroupWrappers().indexOf(keyDatesGroupWrapper) + "].keydates[" + keyDatesGroupWrapper.getKeydates().indexOf(keyDateWrapper) + "]"; getValidDateTimeErrors(keyDateWrapper.getKeyDateType(), keyDateWrapper, keyDateWrapper.getKeyDateNameUI(), keyDatePath); if (keyDateWrapper.getStartDate() != null) { keyDateWrapper.getKeyDateInfo() .setStartDate(getStartDateWithUpdatedTime(keyDateWrapper, false)); setKeyDateEndDate(keyDateWrapper); } } } } } /** * Validates Academic Calendar * * @param acalForm */ public void validateAcademicCalendar(AcademicCalendarForm acalForm) { AcademicCalendarInfo acal = acalForm.getAcademicCalendarInfo(); //Validate Acal Name for duplication if (!isValidAcalName(acalForm.getAcademicCalendarInfo())) { GlobalVariables.getMessageMap().putError("academicCalendarInfo.name", CalendarConstants.MessageKeys.ERROR_DUPLICATE_NAME); } if (!AcalCommonUtils.isValidDateRange(acal.getStartDate(), acal.getEndDate())) { GlobalVariables.getMessageMap().putErrorForSectionId("KS-AcademicCalendar-MetaSection", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_RANGE, "Calendar", AcalCommonUtils.formatDate(acal.getStartDate()), AcalCommonUtils.formatDate(acal.getEndDate())); } //Validate Events for (AcalEventWrapper eventWrapper : acalForm.getEvents()) { if (!AcalCommonUtils.isDateWithinRange(acal.getStartDate(), acal.getEndDate(), eventWrapper.getStartDate()) || !AcalCommonUtils.isDateWithinRange(acal.getStartDate(), acal.getEndDate(), eventWrapper.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId("acal-info-event", CalendarConstants.MessageKeys.ERROR_DATE_NOT_IN_ACAL_RANGE, eventWrapper.getEventTypeName()); } } //Validate Holiday Calendar are in the date range of the Academic Calendar // With holiday calendars we only want there to be Any overlap between the hcal and the acal for (HolidayCalendarWrapper holidayCalendarWrapper : acalForm.getHolidayCalendarList()) { if (!AcalCommonUtils.doDatesOverlap(acal.getStartDate(), acal.getEndDate(), holidayCalendarWrapper.getHolidayCalendarInfo().getStartDate(), holidayCalendarWrapper.getHolidayCalendarInfo().getEndDate())) { GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES, CalendarConstants.MessageKeys.ERROR_DATE_NOT_IN_ACAL_RANGE, "Added Holiday Calendar: " + holidayCalendarWrapper.getHolidayCalendarInfo().getName()); } } // This could not be done at the time of copying so it is done here for the copied acals // find out the parent terms // find their subterms // reassign the subterm's parent to this. for (AcademicTermWrapper termWrapper : acalForm.getTermWrapperList()) { for (AcademicTermWrapper subtermWrapper : termWrapper.getSubterms()) { subtermWrapper.setParentTermInfo(termWrapper.getTermInfo()); subtermWrapper.getParentTermInfo().setStartDate(termWrapper.getStartDate()); subtermWrapper.getParentTermInfo().setEndDate(termWrapper.getEndDate()); subtermWrapper.setParentTermName(termWrapper.getName()); subtermWrapper.getParentTermInfo().setName(termWrapper.getName()); } } // sort the light-weighted term wrappers for displaying error/warning messages on the correct term section List<SimplifiedAcademicTermWrapper> simplifiedAcademicTermWrappers = populateSimplifiedAcademicTermWrappers( acalForm.getTermWrapperList()); //sort term wrappers by start date . We need to do this in the validate call becaues they are later sorted before // the screen is rendered. When that happens the calendars are resorted and the warnding + error messages // will be pointint at the wrong term. sortSimplifiedAcademicTermWrappers(simplifiedAcademicTermWrappers); //get all the holidays for the academic calendar List<HolidayInfo> holidayInfos = new ArrayList<HolidayInfo>(); for (HolidayCalendarWrapper holidayCalendarWrapper : acalForm.getHolidayCalendarList()) { for (HolidayWrapper holidayWrapper : holidayCalendarWrapper.getHolidays()) { holidayInfos.add(holidayWrapper.getHolidayInfo()); } } //Validate Terms keydates and exam period for (int index = 0; index < simplifiedAcademicTermWrappers.size(); index++) { AcademicTermWrapper termWrapperToValidate = acalForm.getTermWrapperList() .get(simplifiedAcademicTermWrappers.get(index).originalIndex); validateTerm(acalForm.getTermWrapperList(), simplifiedAcademicTermWrappers.get(index).originalIndex, index, acal); //in order not to modify the existing method signatures, place the exam period days validation here try { validateExamPeriodDays(termWrapperToValidate, holidayInfos, simplifiedAcademicTermWrappers.get(index).originalIndex, index); } catch (Exception e) { throw new RuntimeException(e); } } } /** * Make sure the user entered Acal name doesnt duplicate with the existing ones * * @param acal * @return */ protected boolean isValidAcalName(AcademicCalendarInfo acal) { QueryByCriteria.Builder qBuilder = QueryByCriteria.Builder.create(); List<Predicate> pList = new ArrayList<Predicate>(); Predicate p = equal("atpType", AcademicCalendarServiceConstants.ACADEMIC_CALENDAR_TYPE_KEY); pList.add(p); p = equalIgnoreCase("name", acal.getName()); pList.add(p); Predicate[] preds = new Predicate[pList.size()]; pList.toArray(preds); qBuilder.setPredicates(and(preds)); try { List<AcademicCalendarInfo> acals = getAcalService().searchForAcademicCalendars(qBuilder.build(), createContextInfo()); boolean valid = acals.isEmpty(); //Make sure it's not the same Acal which is being edited by the user if (!valid && StringUtils.isNotBlank(acal.getId())) { for (AcademicCalendarInfo academicCalendarInfo : acals) { if (!StringUtils.equals(academicCalendarInfo.getId(), acal.getId())) { valid = false; break; } valid = true; } } return valid; } catch (Exception e) { throw new RuntimeException(e); } } // NOTE: edits here should not be needed if KRAD validation is working properly... protected boolean getValidDateTimeErrors(String KeyDateType, TimeSetWrapper wrapper, String wrapperName, String keyDatePath) { boolean result = true; String keyDateTypeRef = "keyDateType"; if (wrapper instanceof AcalEventWrapper) { keyDateTypeRef = "eventTypeKey"; } // The Key Date Type should not be null if (StringUtils.isEmpty(KeyDateType)) { GlobalVariables.getMessageMap().putError(keyDatePath + "." + keyDateTypeRef, CalendarConstants.MessageKeys.ERROR_KEY_DATE_TYPE_REQUIRED); return false; } // Start Date not null, Start Time null, End Date null, End Time not null - illegal if (wrapper.getStartDate() != null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() == null && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { GlobalVariables.getMessageMap().putError(keyDatePath + ".endDate", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_TIME, wrapperName); result = false; } // Start Date null, Start Time not null, different combinations of End Date and End Time - illegal else if (wrapper.getStartDate() == null && (wrapper.getStartTime() != null && !StringUtils.isBlank(wrapper.getStartTime()))) { GlobalVariables.getMessageMap().putError(keyDatePath + ".startDate", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_TIME, wrapperName); result = false; } // Start Date null, Start Time null, End Date null, End Time not null - illegal else if (wrapper.getStartDate() == null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() == null && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { GlobalVariables.getMessageMap().putError(keyDatePath + ".startDate", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_TIME, wrapperName); result = false; } // Start Date and End Date could be null but put a warning if (wrapper.getStartDate() == null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() == null && (wrapper.getEndTime() == null || StringUtils.isBlank(wrapper.getEndTime()))) { GlobalVariables.getMessageMap().putWarning(keyDatePath + ".startDate", CalendarConstants.MessageKeys.ERROR_KEY_DATE_START_DATE_REQUIRED, wrapperName); result = false; // GlobalVariables.getMessageMap().putError(lineName+".startDate", CalendarConstants.MessageKeys.ERROR_KEY_DATE_START_DATE_REQUIRED, wrapperName); } if (wrapper.getStartDate() != null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() == null && (wrapper.getEndTime() == null || StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setAllDay(true); wrapper.setDateRange(false); } else if (wrapper.getStartDate() != null && (wrapper.getStartTime() != null && !StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() == null && (wrapper.getEndTime() == null || StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setAllDay(false); wrapper.setDateRange(false); } else if (wrapper.getStartDate() == null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() != null && (wrapper.getEndTime() == null || StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setStartDate(wrapper.getEndDate()); wrapper.setEndDate(null); wrapper.setAllDay(true); wrapper.setDateRange(false); } else if (wrapper.getStartDate() == null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() != null && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setStartDate(wrapper.getEndDate()); wrapper.setStartTime(wrapper.getEndTime()); wrapper.setEndDate(null); wrapper.setEndTime(null); wrapper.setAllDay(false); wrapper.setDateRange(false); } else if (wrapper.getStartDate() != null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() != null && (wrapper.getEndTime() == null || StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setAllDay(true); wrapper.setDateRange(true); } else if (wrapper.getStartDate() != null && (wrapper.getStartTime() != null && !StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() != null && (wrapper.getEndTime() == null || StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setAllDay(false); wrapper.setDateRange(true); timeSetWrapperEndDate(wrapper); } else if (wrapper.getStartDate() != null && (wrapper.getStartTime() == null || StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() != null && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setAllDay(false); wrapper.setDateRange(true); getStartDateWithUpdatedTime(wrapper, false); } else if (wrapper.getStartDate() != null && (wrapper.getStartTime() != null && !StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() != null && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setAllDay(false); wrapper.setDateRange(true); } else if (wrapper.getStartDate() != null && (wrapper.getStartTime() != null && !StringUtils.isBlank(wrapper.getStartTime())) && wrapper.getEndDate() == null && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { wrapper.setEndDate(wrapper.getStartDate()); wrapper.setAllDay(false); wrapper.setDateRange(true); } // Start Date can't be later than End Date if (wrapper.getStartDate() != null && wrapper.getEndDate() != null) { if ((wrapper.getStartTime() != null && !StringUtils.isBlank(wrapper.getStartTime())) && (wrapper.getEndTime() != null && !StringUtils.isBlank(wrapper.getEndTime()))) { Date startDate = getStartDateWithUpdatedTime(wrapper, false); Date endDate = timeSetWrapperEndDate(wrapper); if (!AcalCommonUtils.isValidDateRange(startDate, endDate)) { GlobalVariables.getMessageMap().putError(keyDatePath + ".startDate", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_RANGE, wrapperName, DateFormatUtils.format(startDate, DateFormatters.MONTH_DAY_YEAR_TIME_DATE_FORMAT), DateFormatUtils.format(endDate, DateFormatters.MONTH_DAY_YEAR_TIME_DATE_FORMAT)); result = false; } } else { if (!AcalCommonUtils.isValidDateRange(wrapper.getStartDate(), wrapper.getEndDate())) { GlobalVariables.getMessageMap().putError(keyDatePath + ".startDate", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_RANGE, wrapperName, AcalCommonUtils.formatDate(wrapper.getStartDate()), AcalCommonUtils.formatDate(wrapper.getEndDate())); result = false; } } } return result; } /** * Validates the term at the given index * * @param termWrapper list of terms in an academic calendar * @param beforeSortingIndex index of the term before sorting for terms happens. * @param afterSortingIndex index of the term after sorting for terms happens. * @param acal ACal dto needed to compare the start and end date */ public void validateTerm(List<AcademicTermWrapper> termWrapper, int beforeSortingIndex, int afterSortingIndex, AcademicCalendarInfo acal) { AcademicTermWrapper termWrapperToValidate = termWrapper.get(beforeSortingIndex); String termSectionName = "term_section_line" + afterSortingIndex; String keyDateGroupSectionName = "acal-term-keydatesgroup_line" + afterSortingIndex; int index2 = 0; //Validate duplicate term name for (AcademicTermWrapper wrapper : termWrapper) { index2++; if (wrapper != termWrapperToValidate) { if (StringUtils.equalsIgnoreCase(wrapper.getName(), termWrapperToValidate.getName())) { GlobalVariables.getMessageMap().putErrorForSectionId(termSectionName, CalendarConstants.MessageKeys.ERROR_DUPLICATE_TERM_NAME, "" + NumberUtils.min(new int[] { afterSortingIndex, index2 }), "" + NumberUtils.max(new int[] { afterSortingIndex, index2 })); } } } if (!AcalCommonUtils.isValidDateRange(termWrapperToValidate.getStartDate(), termWrapperToValidate.getEndDate())) { GlobalVariables.getMessageMap().putErrorForSectionId(termSectionName, CalendarConstants.MessageKeys.ERROR_INVALID_DATE_RANGE, termWrapperToValidate.getName(), AcalCommonUtils.formatDate(termWrapperToValidate.getStartDate()), AcalCommonUtils.formatDate(termWrapperToValidate.getEndDate())); } if (!AcalCommonUtils.isDateWithinRange(acal.getStartDate(), acal.getEndDate(), termWrapperToValidate.getStartDate()) || !AcalCommonUtils.isDateWithinRange(acal.getStartDate(), acal.getEndDate(), termWrapperToValidate.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId(termSectionName, CalendarConstants.MessageKeys.ERROR_TERM_NOT_IN_ACAL_RANGE, termWrapperToValidate.getName()); } if (termWrapperToValidate.isSubTerm()) { if (termWrapperToValidate.getParentTermInfo() != null) { if (!AcalCommonUtils.isDateWithinRange(termWrapperToValidate.getParentTermInfo().getStartDate(), termWrapperToValidate.getParentTermInfo().getEndDate(), termWrapperToValidate.getStartDate()) || !AcalCommonUtils.isDateWithinRange( termWrapperToValidate.getParentTermInfo().getStartDate(), termWrapperToValidate.getParentTermInfo().getEndDate(), termWrapperToValidate.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId(termSectionName, CalendarConstants.MessageKeys.ERROR_TERM_NOT_IN_TERM_RANGE, termWrapperToValidate.getName(), termWrapperToValidate.getParentTermInfo().getName()); } } else { // Find term manually if calendar hasn't already been saved. AcademicTermWrapper parentTerm = null; for (AcademicTermWrapper term : termWrapper) { String termType = term.getTermType(); if (StringUtils.isBlank(termType)) { termType = term.getTermInfo().getTypeKey(); } if (termWrapperToValidate.getParentTerm().equals(termType)) { parentTerm = term; break; } } if (!AcalCommonUtils.isDateWithinRange(parentTerm.getStartDate(), parentTerm.getEndDate(), termWrapperToValidate.getStartDate()) || !AcalCommonUtils.isDateWithinRange(parentTerm.getStartDate(), parentTerm.getEndDate(), termWrapperToValidate.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId(termSectionName, CalendarConstants.MessageKeys.ERROR_TERM_NOT_IN_TERM_RANGE, termWrapperToValidate.getName(), parentTerm.getName()); } } } for (KeyDatesGroupWrapper keyDatesGroupWrapper : termWrapperToValidate.getKeyDatesGroupWrappers()) { for (KeyDateWrapper keyDateWrapper : keyDatesGroupWrapper.getKeydates()) { // Start and End Dates of the key date entry should be within the start and end dates of the term. if (!AcalCommonUtils.isDateWithinRange(termWrapperToValidate.getStartDate(), termWrapperToValidate.getEndDate(), keyDateWrapper.getStartDate()) || !AcalCommonUtils.isDateWithinRange(termWrapperToValidate.getStartDate(), termWrapperToValidate.getEndDate(), keyDateWrapper.getEndDate())) { String keyDatePath = "termWrapperList[" + beforeSortingIndex + "].keyDatesGroupWrappers[" + termWrapperToValidate.getKeyDatesGroupWrappers().indexOf(keyDatesGroupWrapper) + "].keydates[" + keyDatesGroupWrapper.getKeydates().indexOf(keyDateWrapper) + "]"; GlobalVariables.getMessageMap().putWarning(keyDatePath + ".startDate", CalendarConstants.MessageKeys.ERROR_INVALID_DATERANGE_KEYDATE, keyDateWrapper.getKeyDateNameUI(), termWrapperToValidate.getName()); } } } //Validate exam dates validateExamPeriod(termWrapperToValidate, beforeSortingIndex, afterSortingIndex); } /** * Calculates and populates the instructional days for a term * * @param termWrapper * @throws Exception */ public void populateInstructionalDays(AcademicTermWrapper termWrapper) { if (termWrapper.getKeyDatesGroupWrappers() != null) { for (KeyDatesGroupWrapper keyDatesGroupWrapper : termWrapper.getKeyDatesGroupWrappers()) { if (keyDatesGroupWrapper.getKeydates() != null) { for (KeyDateWrapper keydate : keyDatesGroupWrapper.getKeydates()) { if (StringUtils.equals(keydate.getKeyDateType(), AtpServiceConstants.MILESTONE_INSTRUCTIONAL_PERIOD_TYPE_KEY) && termWrapper.getTermInfo() != null && StringUtils.isNotBlank(termWrapper.getTermInfo().getId())) { try { int instructionalDays = getAcalService().getInstructionalDaysForTerm( termWrapper.getTermInfo().getId(), createContextInfo()); termWrapper.setInstructionalDays(instructionalDays); } catch (Exception e) { // Calculating instructional days should not block the normal operation GlobalVariables.getMessageMap().putInfo(KRADConstants.GLOBAL_ERRORS, CalendarConstants.MessageKeys.ERROR_CALCULATING_INSTRUCTIONAL_DAYS, termWrapper.getTermNameForUI(), e.getMessage()); } break; } } } } } } protected Date getStartDateWithUpdatedTime(TimeSetWrapper timeSetWrapper, boolean isSaveAction) { //If start time not blank, set that with the date. If it's empty, just update with default if (!timeSetWrapper.isAllDay()) { if (StringUtils.isNotBlank(timeSetWrapper.getStartTime())) { String startTime = timeSetWrapper.getStartTime(); String startTimeApPm = timeSetWrapper.getStartTimeAmPm(); //On save to DB, have to replace 12AM to 00AM insead of DB considers as 12PM if (isSaveAction && StringUtils.startsWith(startTime, "12:") && StringUtils.equalsIgnoreCase(startTimeApPm, "am")) { startTime = StringUtils.replace(startTime, "12:", "00:"); } return AcalCommonUtils.getDateWithTime(timeSetWrapper.getStartDate(), startTime, startTimeApPm); } else { return null; // should never get here. } } else { return timeSetWrapper.getStartDate(); } } protected void setEventEndDate(AcalEventWrapper eventWrapper) { eventWrapper.getAcalEventInfo().setIsDateRange(eventWrapper.isDateRange()); Date endDateToInfo = timeSetWrapperEndDate(eventWrapper); eventWrapper.getAcalEventInfo().setEndDate(endDateToInfo); } protected void setKeyDateEndDate(KeyDateWrapper keyDateWrapper) { keyDateWrapper.getKeyDateInfo().setIsDateRange(keyDateWrapper.isDateRange()); Date endDateToInfo = timeSetWrapperEndDate(keyDateWrapper); keyDateWrapper.getKeyDateInfo().setEndDate(endDateToInfo); } protected Date timeSetWrapperEndDate(TimeSetWrapper timeSetWrapper) { Date endDateToInfo; if (timeSetWrapper.isAllDay()) { if (timeSetWrapper.isDateRange()) { endDateToInfo = AcalCommonUtils.getDateWithTime(timeSetWrapper.getEndDate(), CalendarConstants.DEFAULT_END_TIME, "PM"); } else { endDateToInfo = null; timeSetWrapper.setEndDate(null); } // set the UI time & am/pm fields to null in case they just had values: timeSetWrapper.setStartTime(null); timeSetWrapper.setStartTimeAmPm("AM"); timeSetWrapper.setEndTime(null); timeSetWrapper.setEndTimeAmPm("AM"); } else { if (timeSetWrapper.isDateRange()) { Date endDate = timeSetWrapper.getEndDate(); String endTime = timeSetWrapper.getEndTime(); String endTimeAmPm = timeSetWrapper.getEndTimeAmPm(); if (StringUtils.isBlank(endTime)) { endTime = CalendarConstants.DEFAULT_END_TIME; endTimeAmPm = "PM"; } timeSetWrapper.setEndTime(endTime); timeSetWrapper.setEndTimeAmPm(endTimeAmPm); endDateToInfo = AcalCommonUtils.getDateWithTime(endDate, endTime, endTimeAmPm); } else { timeSetWrapper.setEndDate(null); timeSetWrapper.setEndTime(null); timeSetWrapper.setEndTimeAmPm("AM"); endDateToInfo = null; } } return endDateToInfo; } /** * Process before adding a term, key date group, holiday calendar or event * */ @Override public void processBeforeAddLine(ViewModel model, Object addLine, String collectionId, String collectionPath) { processAddBlankLines(model); if (addLine instanceof AcademicTermWrapper) { AcademicTermWrapper newLine = (AcademicTermWrapper) addLine; AcademicCalendarForm acalForm = (AcademicCalendarForm) model; //need to handle Term vs subTerm in different way try { if (newLine.getTermType() != null && !StringUtils.isBlank(newLine.getTermType())) { TypeInfo termType = getAcalService().getTermType(newLine.getTermType(), createContextInfo()); // check if term is subterm vs parent term getParentTermType(newLine); if (newLine.getParentTerm() == null || StringUtils.isBlank(newLine.getParentTerm())) { //try to add a term newLine.setTermNameForUI(termType.getName()); newLine.setName(termType.getName() + " " + DateFormatters.DEFULT_YEAR_FORMATTER.format(newLine.getStartDate())); newLine.setTypeInfo(termType); newLine.setSubTerm(false); } else { //try to add a subterm newLine.setTermNameForUI(termType.getName()); newLine.setName(termType.getName() + " " + DateFormatters.DEFULT_YEAR_FORMATTER.format(newLine.getStartDate())); newLine.setTypeInfo(termType); newLine.setSubTerm(true); AcademicTermWrapper parentTermWrapper = getParentTermInForm(newLine.getParentTerm(), acalForm.getTermWrapperList()); if (parentTermWrapper != null) { populateParentTermToSubterm(parentTermWrapper, newLine); } parentTermWrapper.setHasSubterm(true); parentTermWrapper.getSubterms().add(newLine); } } } catch (Exception e) { throw new RuntimeException(e); } } else if (addLine instanceof KeyDatesGroupWrapper) { KeyDatesGroupWrapper group = (KeyDatesGroupWrapper) addLine; if (StringUtils.isNotEmpty(group.getKeyDateGroupType())) { try { TypeInfo termType = getTypeInfo(group.getKeyDateGroupType()); group.setKeyDateGroupNameUI(termType.getName()); group.setTypeInfo(termType); KeyDateWrapper keyDate = new KeyDateWrapper(); group.getKeydates().add(keyDate); ((AcademicCalendarForm) model).getAddedCollectionItems().add(keyDate); //KSENROLL-12648: workaround for rice 2.4 upgrade issue. //Construct key date types JSON string for js to populate key date type dropdown in key date add blank line if (StringUtils.isBlank(group.getKeyDateTypesJSON())) { List<TypeInfo> types = getTypeService().getTypesForGroupType(group.getKeyDateGroupType(), createContextInfo()); JsonObjectBuilder keyDateTypesJsonBuilder = Json.createObjectBuilder(); for (TypeInfo typeInfo : types) { if (!group.isKeyDateExists(typeInfo.getKey())) { keyDateTypesJsonBuilder.add(typeInfo.getKey(), typeInfo.getName().replace("\"", "\\\"")); } } group.setKeyDateTypesJSON(keyDateTypesJsonBuilder.build().toString()); } } catch (Exception e) { throw new RuntimeException(e); } } } else if (addLine instanceof HolidayCalendarInfo) { HolidayCalendarInfo inputLine = (HolidayCalendarInfo) addLine; try { System.out.println("HC id =" + inputLine.getId()); HolidayCalendarInfo exists = getAcalService().getHolidayCalendar(inputLine.getId(), createContextInfo()); inputLine.setName(exists.getName()); inputLine.setId(exists.getId()); inputLine.setTypeKey(exists.getTypeKey()); inputLine.setAdminOrgId(exists.getAdminOrgId()); inputLine.setStartDate(exists.getStartDate()); inputLine.setEndDate(exists.getEndDate()); } catch (Exception e) { throw new RuntimeException(e); } } else if (addLine instanceof HolidayCalendarWrapper) { HolidayCalendarWrapper inputLine = (HolidayCalendarWrapper) addLine; List<HolidayWrapper> holidays = new ArrayList<HolidayWrapper>(); try { String holidayCalendarId = inputLine.getId(); if (!StringUtils.isEmpty(holidayCalendarId)) { HolidayCalendarInfo hcInfo = getAcalService().getHolidayCalendar(inputLine.getId(), createContextInfo()); inputLine.setHolidayCalendarInfo(hcInfo); inputLine.setAdminOrgName(AcalCommonUtils.getAdminOrgNameById(hcInfo.getAdminOrgId())); StateInfo hcState = getAcalService().getHolidayCalendarState(hcInfo.getStateKey(), createContextInfo()); inputLine.setStateName(hcState.getName()); List<HolidayInfo> holidayInfoList = getAcalService() .getHolidaysForHolidayCalendar(hcInfo.getId(), createContextInfo()); for (HolidayInfo holidayInfo : holidayInfoList) { HolidayWrapper holiday = new HolidayWrapper(holidayInfo); TypeInfo typeInfo = getAcalService().getHolidayType(holidayInfo.getTypeKey(), createContextInfo()); holiday.setTypeName(typeInfo.getName()); holidays.add(holiday); } inputLine.setHolidays(holidays); } } catch (Exception e) { throw new RuntimeException(e); } } else if (addLine instanceof HolidayWrapper) { HolidayWrapper holiday = (HolidayWrapper) addLine; try { holiday.setTypeName(getTypeInfo(holiday.getTypeKey()).getName()); } catch (Exception e) { throw new RuntimeException(e); } if (!AcalCommonUtils.isValidDateRange(holiday.getStartDate(), holiday.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId("KS-HolidayCalendar-HolidaySection", CalendarConstants.MessageKeys.ERROR_INVALID_DATE_RANGE, holiday.getTypeName(), AcalCommonUtils.formatDate(holiday.getStartDate()), AcalCommonUtils.formatDate(holiday.getEndDate())); } } else { super.processBeforeAddLine(model, addLine, collectionId, collectionPath); } } protected void getParentTermType(AcademicTermWrapper childTerm) { try { ContextInfo context = createContextInfo(); // check if child term is subterm or term and if it is (list is not empty) then add all parent terms to types List<TypeTypeRelationInfo> typeTypeRelationInfos = getTypeService() .getTypeTypeRelationsByRelatedTypeAndType(childTerm.getTermType(), TypeServiceConstants.TYPE_TYPE_RELATION_CONTAINS_TYPE_KEY, context); //JIRA FIX : KSENROLL-8730 - Added NULL check if (null != typeTypeRelationInfos && !typeTypeRelationInfos.isEmpty()) { int firstTypeRelationInfo = 0; TypeInfo parentTerm = getTypeService() .getType(typeTypeRelationInfos.get(firstTypeRelationInfo).getOwnerTypeKey(), context); childTerm.setParentTerm(parentTerm.getKey()); childTerm.setParentTermName(parentTerm.getName()); } } catch (Exception e) { throw new RuntimeException(e); } } protected AcademicTermWrapper getParentTermInForm(String parentTermType, List<AcademicTermWrapper> termWrapperList) { for (AcademicTermWrapper termWrapper : termWrapperList) { String termType = termWrapper.getTermType(); if (StringUtils.isBlank(termType)) { termType = termWrapper.getTermInfo().getTypeKey(); } if (parentTermType.equals(termType)) { return termWrapper; } } return null; } protected void populateParentTermToSubterm(AcademicTermWrapper parentTermWrapper, AcademicTermWrapper newLine) { List<KeyDatesGroupWrapper> newKeyDatesGroupWrappers = new ArrayList<KeyDatesGroupWrapper>(); for (KeyDatesGroupWrapper keyDatesGroupWrapper : parentTermWrapper.getKeyDatesGroupWrappers()) { KeyDatesGroupWrapper newKeyDatesGroup = new KeyDatesGroupWrapper( keyDatesGroupWrapper.getKeyDateGroupType(), keyDatesGroupWrapper.getKeyDateGroupNameUI()); List<KeyDateWrapper> newKeyDates = newKeyDatesGroup.getKeydates(); for (KeyDateWrapper keyDateWrapper : keyDatesGroupWrapper.getKeydates()) { KeyDateWrapper newKeyDateWrapper = new KeyDateWrapper(); newKeyDateWrapper.setKeyDateType(keyDateWrapper.getKeyDateType()); newKeyDateWrapper.setKeyDateNameUI(keyDateWrapper.getKeyDateNameUI()); newKeyDateWrapper.setAllDay(keyDateWrapper.isAllDay()); newKeyDateWrapper.setDateRange(keyDateWrapper.isDateRange()); newKeyDates.add(newKeyDateWrapper); } newKeyDatesGroupWrappers.add(newKeyDatesGroup); } newLine.setKeyDatesGroupWrappers(newKeyDatesGroupWrappers); newLine.setParentTermInfo(parentTermWrapper.getTermInfo()); } public AcademicCalendarService getAcalService() { if (acalService == null) { acalService = (AcademicCalendarService) GlobalResourceLoader .getService(new QName(AcademicCalendarServiceConstants.NAMESPACE, AcademicCalendarServiceConstants.SERVICE_NAME_LOCAL_PART)); } return this.acalService; } public TypeService getTypeService() { if (typeService == null) { typeService = (TypeService) GlobalResourceLoader.getService( new QName(TypeServiceConstants.NAMESPACE, TypeServiceConstants.SERVICE_NAME_LOCAL_PART)); } return this.typeService; } public AtpService getAtpService() { if (atpService == null) { atpService = (AtpService) GlobalResourceLoader.getService( new QName(AtpServiceConstants.NAMESPACE, AtpServiceConstants.SERVICE_NAME_LOCAL_PART)); } return this.atpService; } public TermCodeGenerator getTermCodeGenerator() { if (termCodeGenerator == null) { //TODO: Change this to get term code generator from the service calls instead of directly (KSENROLL-7233). termCodeGenerator = new TermCodeGeneratorImpl(); //(TermCodeGenerator) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/termcodegen","termCodeGenerator")); } return termCodeGenerator; } public void setTermCodeGenerator(TermCodeGenerator termCodeGenerator) { this.termCodeGenerator = termCodeGenerator; } protected String getAdminOrgNameById(String id) { String adminOrgName = null; Map<String, String> allAcalOrgs = new HashMap<String, String>(); allAcalOrgs.put("102", "Registrar's Office"); allAcalOrgs.put("34", "Medical School"); if (allAcalOrgs.containsKey(id)) { adminOrgName = allAcalOrgs.get(id); } return adminOrgName; } /** * Generated a preview of the term code using the start date and type * Called by and AttributeQuery * * @param startDate - Start date of the term in either MM/dd/yyyy or MM-dd-yyyy format * @param typeKey - The type of term * @return The term code wrapped in a blank academic term wrapper */ public AcademicTermWrapper termInfoAjaxQuery(String startDate, String typeKey) { AcademicTermWrapper temp = new AcademicTermWrapper(); String termCode; try { // Parse the date string Date date; try { // Date format MM/dd/yyyy date = DateFormatters.MONTH_DAY_YEAR_DATE_FORMATTER.parse(startDate); } catch (IllegalArgumentException e) { // Date format MM-dd-yyyy date = DateFormatters.DEFAULT_DATE_FORMATTER.parse(startDate); } // Find what the created term code would be from the term code generator TermInfo term = new TermInfo(); term.setTypeKey(typeKey); term.setStartDate(date); termCode = this.getTermCodeGenerator().generateTermCode(term); } catch (Exception e) { // If code can not be determined from start date and term type key return empty code getLog().error( "Unable to find term code using start date = " + startDate + " and type key = " + typeKey); termCode = ""; } // Set term info code to the found code, wrap it, and return temp.getTermInfo().setCode(termCode); return temp; } /** * Sort the given AcademicTermWrapper list based on the start date * * @param termWrappers - AcademicTermWrapper list * */ public void sortTermWrappers(List<AcademicTermWrapper> termWrappers) { //Sort the termWrappers by start date if (termWrappers != null && !termWrappers.isEmpty()) { Collections.sort(termWrappers, new Comparator<AcademicTermWrapper>() { @Override public int compare(AcademicTermWrapper termWrapper1, AcademicTermWrapper termWrapper2) { int ret = 0; if (!termWrapper1.isSubTerm() && !termWrapper2.isSubTerm()) { // term comp term ret = compareObject(termWrapper1.getStartDate(), termWrapper2.getStartDate()); } if (!termWrapper1.isSubTerm() && termWrapper2.isSubTerm()) { // term comp subterm if (compareObject(termWrapper2.getParentTerm(), termWrapper1.getTermType()) == 0) { // term is parent ret = -1; // term > direct subterm } else { // term comp subterm.parent ret = termWrapper1.getStartDate() .compareTo(termWrapper2.getParentTermInfo().getStartDate()); } } if (termWrapper1.isSubTerm() && !termWrapper2.isSubTerm()) { // subterm comp term if (compareObject(termWrapper1.getParentTerm(), termWrapper2.getTermType()) == 0) { // term is parent ret = 1; // direct subterm < parent term } else { // subterm.parent comp term ret = compareObject(termWrapper1.getParentTermInfo().getStartDate(), termWrapper2.getStartDate()); } } if (termWrapper1.isSubTerm() && termWrapper2.isSubTerm()) { // subterm comp subterm if (compareObject(termWrapper1.getParentTerm(), termWrapper2.getParentTerm()) == 0) { // same parent ret = termWrapper1.getStartDate().compareTo(termWrapper2.getStartDate()); } else { ret = compareObject(termWrapper1.getParentTermInfo().getStartDate(), termWrapper2.getParentTermInfo().getStartDate()); } } return ret; } }); } } /* * Compare with check nullability */ protected int compareObject(Comparable s1, Comparable s2) { if (s1 == null && s2 != null) { return -1; } if (s1 != null && s2 == null) { return 1; } if (s1 == null && s2 == null) { return 0; } return s1.compareTo(s2); } /** * Sort the given AcademicTermWrapper list based on the start date * * @param simplifiedAcademicTermWrappers - SimplifiedAcademicTermWrapper list * */ protected void sortSimplifiedAcademicTermWrappers( List<SimplifiedAcademicTermWrapper> simplifiedAcademicTermWrappers) { //Sort the termWrappers by start date if (simplifiedAcademicTermWrappers != null && !simplifiedAcademicTermWrappers.isEmpty()) { Collections.sort(simplifiedAcademicTermWrappers, new Comparator<SimplifiedAcademicTermWrapper>() { @Override public int compare(SimplifiedAcademicTermWrapper simplifiedAcademicTermWrapper1, SimplifiedAcademicTermWrapper simplifiedAcademicTermWrapper2) { int ret = 0; if (!simplifiedAcademicTermWrapper1.subTerm && !simplifiedAcademicTermWrapper2.subTerm) { // term comp term ret = compareObject(simplifiedAcademicTermWrapper1.startDate, simplifiedAcademicTermWrapper2.startDate); } if (!simplifiedAcademicTermWrapper1.subTerm && simplifiedAcademicTermWrapper2.subTerm) { // term comp subterm if (compareObject(simplifiedAcademicTermWrapper2.parentTerm, simplifiedAcademicTermWrapper1.termType) == 0) { // term is parent ret = -1; // term > direct subterm } else { // term comp subterm.parent ret = compareObject(simplifiedAcademicTermWrapper1.startDate, simplifiedAcademicTermWrapper2.parentTermInfo.getStartDate()); } } if (simplifiedAcademicTermWrapper1.subTerm && !simplifiedAcademicTermWrapper2.subTerm) { // subterm comp term if (compareObject(simplifiedAcademicTermWrapper1.parentTerm, simplifiedAcademicTermWrapper2.termType) == 0) { // term is parent ret = 1; // direct subterm < parent term } else { // subterm.parent comp term } } if (simplifiedAcademicTermWrapper1.subTerm && simplifiedAcademicTermWrapper2.subTerm) { // subterm comp subterm if (compareObject(simplifiedAcademicTermWrapper1.parentTerm, simplifiedAcademicTermWrapper2.parentTerm) == 0) { // same parent ret = simplifiedAcademicTermWrapper1.startDate .compareTo(simplifiedAcademicTermWrapper2.startDate); } else { ret = simplifiedAcademicTermWrapper1.parentTermInfo.getStartDate() .compareTo(simplifiedAcademicTermWrapper2.parentTermInfo.getStartDate()); } } return ret; } }); } } /** * Validates the term at the given index * * @param termWrapperToValidate a term in an academic calendar * @param beforeSortingIndex index of the term before sorting for terms happens. * @param afterSortingIndex index of the term after sorting for terms happens. */ public void validateExamPeriod(AcademicTermWrapper termWrapperToValidate, int beforeSortingIndex, int afterSortingIndex) { String finalExamSectionName = "acal-term-examdates_line" + afterSortingIndex; if (termWrapperToValidate.getExamdates() != null && termWrapperToValidate.getExamdates().size() > 0) { for (ExamPeriodWrapper examWrapper : termWrapperToValidate.getExamdates()) { // startDate must be before endDate if (!AcalCommonUtils.isValidDateRange(examWrapper.getStartDate(), examWrapper.getEndDate())) { GlobalVariables.getMessageMap().putErrorForSectionId(finalExamSectionName, CalendarConstants.MessageKeys.ERROR_INVALID_DATE_RANGE, examWrapper.getExamPeriodNameUI(), AcalCommonUtils.formatDate(examWrapper.getStartDate()), AcalCommonUtils.formatDate(examWrapper.getEndDate())); } // Warning message when Start and End Dates of the exam period not within the term period. if (!AcalCommonUtils.isDateWithinRange(termWrapperToValidate.getStartDate(), termWrapperToValidate.getEndDate(), examWrapper.getStartDate()) || !AcalCommonUtils.isDateWithinRange(termWrapperToValidate.getStartDate(), termWrapperToValidate.getEndDate(), examWrapper.getEndDate())) { GlobalVariables.getMessageMap().putWarningForSectionId(finalExamSectionName, CalendarConstants.MessageKeys.ERROR_TERM_NOT_IN_TERM_RANGE, examWrapper.getExamPeriodNameUI(), termWrapperToValidate.getName()); } // Both or neither dates should be filled if (examWrapper.getStartDate() != null && !examWrapper.getStartDate().equals("") && (examWrapper.getEndDate() == null || examWrapper.getEndDate().equals(""))) { GlobalVariables.getMessageMap().putErrorForSectionId(finalExamSectionName, CalendarConstants.MessageKeys.ERROR_KEY_DATE_END_DATE_REQUIRED, examWrapper.getExamPeriodNameUI()); } if (examWrapper.getEndDate() != null && !examWrapper.getEndDate().equals("") && (examWrapper.getStartDate() == null || examWrapper.getStartDate().equals(""))) { GlobalVariables.getMessageMap().putErrorForSectionId(finalExamSectionName, CalendarConstants.MessageKeys.ERROR_KEY_DATE_START_DATE_REQUIRED, examWrapper.getExamPeriodNameUI()); } // Warn if both dates are empty if ((examWrapper.getStartDate() == null || examWrapper.getStartDate().equals("")) && (examWrapper.getEndDate() == null || examWrapper.getEndDate().equals(""))) { GlobalVariables.getMessageMap().putWarningForSectionId(finalExamSectionName, CalendarConstants.MessageKeys.ERROR_EMPTY_DATES, examWrapper.getExamPeriodNameUI()); } } } } /** * Validates the exam period days given the term that it is associated with * * @param termWrapperToValidate term wrapper that the exam period to be validated is associated with * @param holidayInfos list of holidayinfos of the academic calendar * @param beforeSortingIndex index of the term before sorting for terms happens. * @param afterSortingIndex index of the term after sorting for terms happens. */ protected void validateExamPeriodDays(AcademicTermWrapper termWrapperToValidate, List<HolidayInfo> holidayInfos, int beforeSortingIndex, int afterSortingIndex) throws Exception { //trap null parameters if (termWrapperToValidate == null) { throw new Exception("term wrapper is null"); } List<ReferenceObjectBinding> refObjectsBindings = this.getRuleManagementService() .findReferenceObjectBindingsByReferenceObject(TypeServiceConstants.REF_OBJECT_URI_TYPE, termWrapperToValidate.getTypeInfo().getKey()); if (refObjectsBindings.size() > 0) { String finalExamSectionName = "acal-term-examdates_line" + afterSortingIndex; String termSectionName = "term_section_line" + afterSortingIndex; SelectControl select = (SelectControl) ComponentFactory .getNewComponentInstance("KSFE-FinalExam-ExamDaysDropdown"); int maxday = 0; for (KeyValue value : select.getOptions()) { maxday = Math.max(Integer.valueOf(value.getKey()), maxday); } if (termWrapperToValidate.getExamdates() != null && !termWrapperToValidate.getExamdates().isEmpty()) { for (ExamPeriodWrapper examPeriodWrapper : termWrapperToValidate.getExamdates()) { if (getDaysForExamPeriod(examPeriodWrapper, holidayInfos, createContextInfo()) < maxday) { GlobalVariables.getMessageMap().putErrorForSectionId(finalExamSectionName, CalendarConstants.MessageKeys.ERROR_EXAM_PERIOD_DAYS_VALIDATION); } } } else { GlobalVariables.getMessageMap().putWarningForSectionId(termSectionName, CalendarConstants.MessageKeys.ERROR_NO_EXAM_PEROID_FOR_TERM_LINKED_MATRIX); } } } /** * Calculate and returns the valid number of final exam period days based on the excludeSaturday/excludeSunday setting. * Also, overlapping non-instructional holidays will be subtracted as well. * * @param examPeriodWrapper exam period wrapper * @param holidayInfos list of holidayinfos of the academic calendar */ protected int getDaysForExamPeriod(ExamPeriodWrapper examPeriodWrapper, List<HolidayInfo> holidayInfos, ContextInfo contextInfo) throws Exception { //trap null parameters if (examPeriodWrapper == null) { throw new Exception("Exam Period wrapper is null"); } int examPeriodDays = 0; boolean excludeSaturday = examPeriodWrapper.isExcludeSaturday(); boolean excludeSunday = examPeriodWrapper.isExcludeSunday(); DateMidnight currentDateExamPeriod = new DateMidnight(examPeriodWrapper.getStartDate().getTime()); DateMidnight endDateExamPeriod = new DateMidnight(examPeriodWrapper.getEndDate().getTime()); // go from start to end and count exam period days while (currentDateExamPeriod.compareTo(endDateExamPeriod) <= 0) { // if it is Saturday or Sunday and the exam period set exclude Saturday or Sunday attr // do not count that day if (!(((currentDateExamPeriod.getDayOfWeek() == DateTimeConstants.SATURDAY) && excludeSaturday) || ((currentDateExamPeriod.getDayOfWeek() == DateTimeConstants.SUNDAY) && excludeSunday))) { ++examPeriodDays; } currentDateExamPeriod = currentDateExamPeriod.plusDays(1); } //if there is a holiday calendar for the academic calendar where the exam period is in, //check if there are holidays overlapping with the exam period if (holidayInfos != null && !holidayInfos.isEmpty()) { List<DateMidnight> holidayDatesToSubtract = new ArrayList<DateMidnight>(); for (HolidayInfo holidayInfo : holidayInfos) { Boolean isInstDay = holidayInfo.getIsInstructionalDay(); Boolean isDateRange = holidayInfo.getIsDateRange(); Date holStartDate = holidayInfo.getStartDate(); Date holEndDate = holidayInfo.getEndDate(); // If's it's not a range then the start and end dates are the same if (!isDateRange) { holEndDate = holStartDate; } // if holiday is an instructional day, it doesn't need to be subtracted from the exam period if (!isInstDay) { DateMidnight currentDate = new DateMidnight(holStartDate.getTime()); DateMidnight stopDate = new DateMidnight(holEndDate.getTime()); while (currentDate.compareTo(stopDate) <= 0) { if (doDatesOverlap(examPeriodWrapper.getStartDate(), examPeriodWrapper.getEndDate(), currentDate.toDate(), currentDate.toDate())) { //if holiday is on Saturday or Sunday and excludeSaturday/excludeSunday is set, //the holiday doesn't need to be subtracted again because the Saturday/Sunday has already been excluded if (!(((currentDate.getDayOfWeek() == DateTimeConstants.SATURDAY) && excludeSaturday) || ((currentDate.getDayOfWeek() == DateTimeConstants.SUNDAY) && excludeSunday))) { if (!holidayDatesToSubtract.contains(currentDate)) { holidayDatesToSubtract.add(currentDate); --examPeriodDays; } } } currentDate = currentDate.plusDays(1); } } } } return examPeriodDays; } protected boolean doDatesOverlap(Date periodStartDate, Date periodEndDate, Date subStart, Date subEnd) { boolean bRet = false; int compStart = subStart.compareTo(periodEndDate); int compEnd = subEnd.compareTo(periodStartDate); if (compStart <= 0 && compEnd >= 0) { bRet = true; } return bRet; } protected List<SimplifiedAcademicTermWrapper> populateSimplifiedAcademicTermWrappers( List<AcademicTermWrapper> termWrappers) { List<SimplifiedAcademicTermWrapper> simplifiedAcademicTermWrappers = new ArrayList<SimplifiedAcademicTermWrapper>( termWrappers.size()); int index = 0; for (AcademicTermWrapper academicTermWrapper : termWrappers) { SimplifiedAcademicTermWrapper simplifiedAcademicTermWrapper = new SimplifiedAcademicTermWrapper( academicTermWrapper); simplifiedAcademicTermWrapper.originalIndex = index++; simplifiedAcademicTermWrappers.add(simplifiedAcademicTermWrapper); } return simplifiedAcademicTermWrappers; } public void setAcalService(AcademicCalendarService acalService) { this.acalService = acalService; } public void setTypeService(TypeService typeService) { this.typeService = typeService; } public void setAtpService(AtpService atpService) { this.atpService = atpService; } public void setRuleManagementService(RuleManagementService ruleManagementService) { this.ruleManagementService = ruleManagementService; } /** * A light-weighted inner class to perform term wrapper sorting based on start date when doing acal validation. * We want to keep the original order of term wrappers in acalForm for dirty field processing. However, We will * have to sort the term wrapper list for correctly displaying warning/error messages during acal validation. We * have this light-weighted inner class just for sorting the term wrapper list inside acal validation while keep * the original term wrapper list in acalForm untouched. */ public class SimplifiedAcademicTermWrapper { public String termInfoId; public boolean subTerm = false; public Date startDate; public String termType; public String parentTerm; public TermInfo parentTermInfo; public int originalIndex; // private constructor to prevent the inner class from being instantiated outside the outer class // because this inner class doesn't need to be instantiated/accessed outside public SimplifiedAcademicTermWrapper() { } // private constructor to prevent the inner class from being instantiated outside the outer class // because this inner class doesn't need to be instantiated/accessed outside public SimplifiedAcademicTermWrapper(AcademicTermWrapper academicTermWrapper) { this.termInfoId = academicTermWrapper.getTermInfo().getId(); this.subTerm = academicTermWrapper.isSubTerm(); this.termType = academicTermWrapper.getTermType(); this.startDate = academicTermWrapper.getStartDate(); this.parentTerm = academicTermWrapper.getParentTerm(); this.parentTermInfo = academicTermWrapper.getParentTermInfo(); } } public RuleManagementService getRuleManagementService() { if (ruleManagementService == null) { ruleManagementService = (RuleManagementService) GlobalResourceLoader .getService(new QName(KrmsConstants.Namespaces.KRMS_NAMESPACE_2_0, "ruleManagementService")); } return ruleManagementService; } }