Coverage Report - org.kuali.student.enrollment.class2.acal.service.decorators.AcademicCalendarServiceCalculationDecorator
 
Classes in this File Line Coverage Branch Coverage Complexity
AcademicCalendarServiceCalculationDecorator
0%
0/180
0%
0/42
6.273
 
 1  
 package org.kuali.student.enrollment.class2.acal.service.decorators;
 2  
 
 3  
 import org.apache.commons.lang.RandomStringUtils;
 4  
 import org.apache.commons.lang.time.FastDateFormat;
 5  
 import org.kuali.student.common.util.UUIDHelper;
 6  
 import org.kuali.student.enrollment.acal.dto.AcademicCalendarInfo;
 7  
 import org.kuali.student.enrollment.acal.dto.AcalEventInfo;
 8  
 import org.kuali.student.enrollment.acal.dto.HolidayCalendarInfo;
 9  
 import org.kuali.student.enrollment.acal.dto.HolidayInfo;
 10  
 import org.kuali.student.enrollment.acal.dto.KeyDateInfo;
 11  
 import org.kuali.student.enrollment.acal.dto.TermInfo;
 12  
 import org.kuali.student.r2.common.dto.ContextInfo;
 13  
 import org.kuali.student.r2.common.dto.RichTextInfo;
 14  
 import org.kuali.student.r2.common.exceptions.AlreadyExistsException;
 15  
 import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
 16  
 import org.kuali.student.r2.common.exceptions.DoesNotExistException;
 17  
 import org.kuali.student.r2.common.exceptions.InvalidParameterException;
 18  
 import org.kuali.student.r2.common.exceptions.MissingParameterException;
 19  
 import org.kuali.student.r2.common.exceptions.OperationFailedException;
 20  
 import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
 21  
 import org.kuali.student.r2.common.exceptions.ReadOnlyException;
 22  
 import org.kuali.student.r2.common.util.constants.AtpServiceConstants;
 23  
 import org.kuali.student.r2.core.atp.dto.AtpAtpRelationInfo;
 24  
 
 25  
 import javax.jws.WebParam;
 26  
 import java.util.ArrayList;
 27  
 import java.util.Calendar;
 28  
 import java.util.Date;
 29  
 import java.util.GregorianCalendar;
 30  
 import java.util.HashMap;
 31  
 import java.util.List;
 32  
 import java.util.Map;
 33  
 
 34  0
 public class AcademicCalendarServiceCalculationDecorator extends AcademicCalendarServiceDecorator {
 35  
 
 36  
     @Override
 37  
     public AcademicCalendarInfo copyAcademicCalendar(String academicCalendarId, Date startDate, Date endDate, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException,
 38  
             MissingParameterException, OperationFailedException, PermissionDeniedException {
 39  0
         AcademicCalendarInfo templateAcademicCalendar = getAcademicCalendar(academicCalendarId, contextInfo);
 40  0
         AcademicCalendarInfo academicCalendar = new AcademicCalendarInfo(templateAcademicCalendar);
 41  0
         academicCalendar.setName(templateAcademicCalendar.getName());
 42  0
         academicCalendar.setStartDate(startDate);
 43  0
         academicCalendar.setEndDate(endDate);
 44  0
         academicCalendar.setId(null);
 45  0
         academicCalendar.setStateKey(AtpServiceConstants.ATP_DRAFT_STATE_KEY);
 46  
         try {
 47  0
             academicCalendar.setHolidayCalendarIds(copyHolidayCalendars(templateAcademicCalendar, contextInfo));
 48  0
         } catch (DataValidationErrorException dvEx) {
 49  0
             throw new OperationFailedException(dvEx.getMessage(), dvEx.getCause());
 50  0
         } catch (ReadOnlyException roEx) {
 51  0
             throw new OperationFailedException();
 52  
 
 53  0
         }
 54  
 
 55  
         try {
 56  0
             academicCalendar = createAcademicCalendar(academicCalendar.getTypeKey(), academicCalendar, contextInfo);
 57  0
         } catch (DataValidationErrorException e) {
 58  0
             throw new OperationFailedException("Could not create AcademicCalendar '" + academicCalendar.getId() + "'", e);
 59  0
         } catch (ReadOnlyException e) {
 60  0
             throw new OperationFailedException("Could not create AcademicCalendar '" + academicCalendar.getId() + "'", e);
 61  0
         }
 62  
 
 63  0
         Map<String, KeyDateInfo> oldDatesToNewDates = new HashMap<String, KeyDateInfo>();
 64  
 
 65  0
         List<TermInfo> templateTerms = getTermsForAcademicCalendar(templateAcademicCalendar.getId(), contextInfo);
 66  0
         for (TermInfo templateTerm : templateTerms) {
 67  
             TermInfo term;
 68  0
             term = copyTerm(templateTerm.getId(), oldDatesToNewDates, contextInfo);
 69  
             try {
 70  0
                 addTermToAcademicCalendar(academicCalendar.getId(), term.getId(), contextInfo);
 71  0
             } catch (AlreadyExistsException e) {
 72  0
                 throw new OperationFailedException("AlreadyExistsException  thrown from addTermToAcademicCalendar :" + e.getMessage());
 73  0
             }
 74  0
         }
 75  
 
 76  0
         copyAcalEvents(templateAcademicCalendar.getId(), academicCalendar.getId(), contextInfo);
 77  
 
 78  0
         return academicCalendar;
 79  
     }
 80  
 
 81  
     @Override
 82  
     public HolidayCalendarInfo copyHolidayCalendar( String holidayCalendarId,Date startDate, Date endDate, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
 83  
 
 84  0
             HolidayCalendarInfo templateHolidayCalendar = getHolidayCalendar(holidayCalendarId, contextInfo);
 85  
 
 86  0
             HolidayCalendarInfo holidayCalendar = new HolidayCalendarInfo(templateHolidayCalendar);
 87  0
             holidayCalendar.setName(null);
 88  0
             holidayCalendar.setId(null);
 89  0
             holidayCalendar.setStateKey(AtpServiceConstants.ATP_DRAFT_STATE_KEY);
 90  0
             holidayCalendar.setStartDate(startDate);
 91  0
             holidayCalendar.setEndDate(endDate);
 92  
 
 93  
             try {
 94  0
                   holidayCalendar = createHolidayCalendar(AtpServiceConstants.ATP_HOLIDAY_CALENDAR_TYPE_KEY, holidayCalendar, contextInfo);
 95  0
             } catch (DataValidationErrorException e) {
 96  0
                 throw new OperationFailedException("Exception creating Holiday Calendar.", e);
 97  0
             }  catch (ReadOnlyException re){
 98  0
                 throw new OperationFailedException("Exception creating Holiday Calendar.", re);
 99  0
             }
 100  
 
 101  0
             List<HolidayInfo> holidays = getHolidaysForHolidayCalendar(templateHolidayCalendar.getId(), contextInfo);
 102  
 
 103  0
             for (HolidayInfo holidayInfo : holidays) {
 104  0
                 HolidayInfo newHoliday = new HolidayInfo(holidayInfo);
 105  0
                 newHoliday.setId(null);
 106  0
                 newHoliday.setDescr(new RichTextInfo(holidayInfo.getDescr()));
 107  0
                 newHoliday.setName(holidayInfo.getName());
 108  0
                 newHoliday.setTypeKey(newHoliday.getTypeKey());
 109  0
                 newHoliday.setStateKey(AtpServiceConstants.MILESTONE_DRAFT_STATE_KEY);
 110  
 
 111  
                 try {
 112  0
                     newHoliday = createHoliday(holidayCalendar.getId(), holidayInfo.getTypeKey(), newHoliday, contextInfo);
 113  0
                     calculateHolidayEffectiveDates(newHoliday, holidayCalendar, contextInfo);
 114  0
                 } catch (DataValidationErrorException e) {
 115  0
                     throw new OperationFailedException("Error creating holiday", e);
 116  0
                 } catch (ReadOnlyException e) {
 117  0
                     throw new OperationFailedException("Error creating holiday", e);
 118  0
                 }
 119  0
             }
 120  0
         return holidayCalendar;
 121  
     }
 122  
 
 123  
     private List<String> copyHolidayCalendars(AcademicCalendarInfo academicCalendar, ContextInfo contextInfo) throws OperationFailedException, InvalidParameterException, MissingParameterException,
 124  
             DoesNotExistException, PermissionDeniedException, DataValidationErrorException, ReadOnlyException {
 125  
 
 126  0
         List<String> newHolidayCalendarIds = new ArrayList<String>();
 127  
 
 128  0
         if (academicCalendar.getHolidayCalendarIds().isEmpty()) {
 129  0
             return newHolidayCalendarIds;
 130  
         }
 131  
 
 132  0
         Date startDate = academicCalendar.getStartDate();
 133  0
         Date endDate = academicCalendar.getEndDate();
 134  
 
 135  0
         for (String templateHolidayCalendar : academicCalendar.getHolidayCalendarIds()) {
 136  0
             HolidayCalendarInfo holidayCalendar =   copyHolidayCalendar(templateHolidayCalendar, startDate, endDate, contextInfo);
 137  
 
 138  0
             newHolidayCalendarIds.add(holidayCalendar.getId());
 139  
 
 140  0
             createHolidayCalendarToAcademicCalendarRelations(newHolidayCalendarIds, academicCalendar.getId(), contextInfo);
 141  0
         }
 142  
 
 143  0
         return newHolidayCalendarIds;
 144  
     }
 145  
 
 146  
     private void createHolidayCalendarToAcademicCalendarRelations(List<String> newHolidayCalendarIds, String academicCalendarId, ContextInfo contextInfo) throws DoesNotExistException,
 147  
             DataValidationErrorException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException, ReadOnlyException {
 148  
 
 149  0
         for (String holidayCalendarId : newHolidayCalendarIds) {
 150  
 
 151  0
             AtpAtpRelationInfo atpRelationInfo = new AtpAtpRelationInfo();
 152  0
             atpRelationInfo.setAtpId(academicCalendarId);
 153  0
             atpRelationInfo.setRelatedAtpId(holidayCalendarId);
 154  0
             atpRelationInfo.setEffectiveDate(new Date());
 155  0
             atpRelationInfo.setExpirationDate(null);
 156  0
             atpRelationInfo.setStateKey(AtpServiceConstants.ATP_ATP_RELATION_ACTIVE_STATE_KEY);
 157  0
             atpRelationInfo.setTypeKey(AtpServiceConstants.ATP_ATP_RELATION_ASSOCIATED_TYPE_KEY);
 158  0
             getAtpService().createAtpAtpRelation(academicCalendarId, 
 159  
                     holidayCalendarId, 
 160  
                     atpRelationInfo.getTypeKey(), 
 161  
                     atpRelationInfo, contextInfo);
 162  
 
 163  0
         }
 164  
 
 165  0
     }
 166  
 
 167  
     private TermInfo copyTerm(String templateTermId, Map<String, KeyDateInfo> templateDatesToNewDates, ContextInfo context) throws InvalidParameterException, MissingParameterException,
 168  
             DoesNotExistException, PermissionDeniedException, OperationFailedException {
 169  0
         TermInfo templateTerm = getTerm(templateTermId, context);
 170  
 
 171  0
         TermInfo term = new TermInfo(templateTerm);
 172  0
         term.setId(null);
 173  0
         term.setStateKey(AtpServiceConstants.ATP_DRAFT_STATE_KEY);
 174  
 
 175  
         try {
 176  0
             term = createTerm(term.getTypeKey(), term, context);
 177  0
         } catch (DataValidationErrorException e) {
 178  0
             throw new OperationFailedException("Could not create Term '" + term.getId() + "'", e);
 179  0
         } catch (ReadOnlyException e) {
 180  0
             throw new OperationFailedException("Could not create Term '" + term.getId() + "'", e);
 181  0
         }
 182  
 
 183  
         /*
 184  
          * Copy KeyDates of Term TODO Currently cannot reuse keydates in the
 185  
          * acal service, but the design concept was that a term and subterm may
 186  
          * share dates. A mapping of all KeyDates to their newly created
 187  
          * counterparts is used to determine whether a new KeyDate has already
 188  
          * been created. However, it is not being used at this time and a new
 189  
          * KeyDate will be created for each relationship.
 190  
          */
 191  
 
 192  0
         copyKeyDates(term, templateTermId, templateDatesToNewDates, context);
 193  
         // Recursive call to copy subTerms
 194  0
         List<TermInfo> templateSubTerms = getContainingTerms(templateTermId, context);
 195  0
         for (TermInfo templateSubTerm : templateSubTerms) {
 196  0
             TermInfo subTerm = copyTerm(templateSubTerm.getId(), templateDatesToNewDates, context);
 197  
             try {
 198  0
                 addTermToTerm(term.getId(), subTerm.getId(), context);
 199  0
             } catch (AlreadyExistsException e) {
 200  0
                 throw new OperationFailedException("AlreadyExistsException : " + e.getMessage());
 201  0
             }
 202  0
         }
 203  
 
 204  0
         return term;
 205  
     }
 206  
 
 207  
     private void copyKeyDates(TermInfo createdTerm, String templateTermId, Map<String, KeyDateInfo> templateDatesToNewDates, ContextInfo context) throws DoesNotExistException,
 208  
             InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
 209  0
         List<KeyDateInfo> templateKeyDates = getKeyDatesForTerm(templateTermId, context);
 210  0
         for (KeyDateInfo templateKeyDate : templateKeyDates) {
 211  0
             KeyDateInfo keyDate = templateDatesToNewDates.get(templateKeyDate.getId());
 212  0
             keyDate = null; // TODO Disabling usage of mapping until service
 213  
                             // supports the reuse of dates
 214  
 
 215  0
             if (null == keyDate) {
 216  0
                 keyDate = new KeyDateInfo(templateKeyDate);
 217  0
                 keyDate.setId(null);
 218  0
                 keyDate.setStateKey(AtpServiceConstants.MILESTONE_DRAFT_STATE_KEY);
 219  0
                 keyDate.setName(templateKeyDate.getName());
 220  0
                 keyDate.setDescr(new RichTextInfo(templateKeyDate.getDescr()));
 221  0
                 keyDate.setTypeKey(templateKeyDate.getTypeKey());
 222  
 
 223  
                 try {
 224  
                     // TODO Need a way to only create a KeyDate in order to
 225  
                     // associate it with multiple Terms
 226  0
                     createKeyDate(createdTerm.getId(), keyDate.getTypeKey(), keyDate, context);
 227  
                     // TODO calculate keyDate effective dates
 228  0
                     templateDatesToNewDates.put(templateKeyDate.getId(), keyDate);
 229  0
                 } catch (DataValidationErrorException e) {
 230  0
                     throw new OperationFailedException("Could not create KeyDate '" + keyDate.getId() + "'", e);
 231  0
                 } catch (ReadOnlyException e) {
 232  0
                     throw new OperationFailedException("ReadOnlyException " + keyDate.getId() + "'", e);
 233  0
                 }
 234  
 
 235  
             }
 236  0
         }
 237  
 
 238  0
     }
 239  
 
 240  
     private void copyAcalEvents(String templateAcalId, String newAcalId, ContextInfo contextInfo) throws OperationFailedException {
 241  
 
 242  
         List<AcalEventInfo> acalEventInfos;
 243  
 
 244  
         try {
 245  0
             acalEventInfos = getAcalEventsForAcademicCalendar(templateAcalId, contextInfo);
 246  0
         } catch (Exception e) {
 247  0
             throw new OperationFailedException("Error getting Acal Events", e);
 248  0
         }
 249  
 
 250  0
         for (AcalEventInfo acalEventInfo : acalEventInfos) {
 251  0
             AcalEventInfo newAcalEventInfo = new AcalEventInfo(acalEventInfo);
 252  0
             newAcalEventInfo.setId(UUIDHelper.genStringUUID());
 253  0
             newAcalEventInfo.setDescr(new RichTextInfo(acalEventInfo.getDescr()));
 254  0
             newAcalEventInfo.setName(acalEventInfo.getName());
 255  0
             newAcalEventInfo.setStateKey(AtpServiceConstants.MILESTONE_DRAFT_STATE_KEY);
 256  0
             newAcalEventInfo.setTypeKey(acalEventInfo.getTypeKey());
 257  
 
 258  
             try {
 259  0
                 createAcalEvent(newAcalId, acalEventInfo.getTypeKey(), newAcalEventInfo, contextInfo);
 260  0
             } catch (Exception e) {
 261  0
                 throw new OperationFailedException("Error creating AcalEvent", e);
 262  0
             }
 263  
 
 264  0
         }
 265  0
     }
 266  
 
 267  
     private void calculateHolidayEffectiveDates(HolidayInfo holiday, HolidayCalendarInfo holidayCalendar, ContextInfo contextInfo) throws OperationFailedException {
 268  0
         String typeKey = holiday.getTypeKey();
 269  0
         if (AtpServiceConstants.MILESTONE_LABOR_DAY_TYPE_KEY.equals(typeKey)) {
 270  0
             List<Integer> years = new ArrayList<Integer>();
 271  0
             FastDateFormat format = FastDateFormat.getInstance("yyyy");
 272  0
             int calStartYear = Integer.parseInt(format.format(holidayCalendar.getStartDate()));
 273  0
             int calEndYear = Integer.parseInt(format.format(holidayCalendar.getEndDate()));
 274  0
             for (int i = calStartYear; i <= calEndYear; i++) {
 275  0
                 years.add(i);
 276  
             }
 277  
 
 278  0
             boolean holidayFound = false;
 279  0
             for (Integer year : years) {
 280  0
                 Date laborDayStartTime = getLaborDayForYear(year);
 281  0
                 Calendar cal = Calendar.getInstance();
 282  0
                 cal.setTime(laborDayStartTime);
 283  0
                 cal.add(Calendar.DATE, 1);
 284  0
                 Date laborDayEndTime = cal.getTime();
 285  
 
 286  0
                 if (timespanOccursDuringTimespan(laborDayStartTime, laborDayEndTime, holidayCalendar.getStartDate(), holidayCalendar.getEndDate())) {
 287  0
                     holidayFound = true;
 288  
 
 289  
                     // populate holiday
 290  0
                     holiday.setStartDate(laborDayStartTime);
 291  0
                     holiday.setEndDate(laborDayEndTime);
 292  0
                     holiday.setIsAllDay(true);
 293  0
                     holiday.setIsDateRange(false);
 294  
 
 295  
                     // TODO the milestone is being populated with the first
 296  
                     // possible occurance - it is possible the ATP could span
 297  
                     // more than a years time
 298  0
                     break;
 299  
                 }
 300  0
             }
 301  
 
 302  0
             if (!holidayFound) {
 303  0
                 throw new OperationFailedException("Could not calculate holiday for ATP. Holiday: '" + typeKey + "' ATP: '" + holidayCalendar.getId() + "'");
 304  
             }
 305  
         }
 306  0
     }
 307  
 
 308  
     private Date getNthDayOfWeekInMonth(int n, int dayOfWeek, int month, int year) {
 309  0
         Calendar cal = new GregorianCalendar(year, month, 1);
 310  0
         if (dayOfWeek != cal.get(Calendar.DAY_OF_WEEK)) {
 311  0
             int daysUntil = (dayOfWeek - cal.get(Calendar.DAY_OF_WEEK) + 7) % 7;
 312  0
             cal.add(Calendar.DATE, daysUntil);
 313  
         }
 314  0
         cal.add(Calendar.DATE, (n-1) * 7);
 315  0
         return cal.getTime();
 316  
     }
 317  
 
 318  
     private Date getLaborDayForYear(int year) {
 319  0
         return getNthDayOfWeekInMonth(1, Calendar.MONDAY, Calendar.SEPTEMBER, year);
 320  
     }
 321  
 
 322  
     private boolean timespanOccursDuringTimespan(Date startTime1, Date endTime1, Date startTime2, Date endTime2) {
 323  0
         if (!startTime1.before(startTime2) && startTime1.before(endTime2)) {
 324  
             // holiday starts as/after ATP starts (fully contained or extends
 325  
             // past ATP end)
 326  0
             return true;
 327  
         }
 328  0
         if (!endTime1.before(startTime2) && !endTime1.after(endTime2)) {
 329  
             // holiday ends while ATP is in progress
 330  0
             return true;
 331  
         }
 332  0
         if (!startTime1.after(startTime2) && !endTime1.before(endTime2)) {
 333  
             // holiday encompasses ATP
 334  0
             return true;
 335  
         }
 336  0
         return false;
 337  
     }
 338  
 
 339  
 }