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 | |
|
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | |
|
190 | |
|
191 | |
|
192 | 0 | copyKeyDates(term, templateTermId, templateDatesToNewDates, context); |
193 | |
|
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; |
213 | |
|
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 | |
|
225 | |
|
226 | 0 | createKeyDate(createdTerm.getId(), keyDate.getTypeKey(), keyDate, context); |
227 | |
|
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 | |
|
290 | 0 | holiday.setStartDate(laborDayStartTime); |
291 | 0 | holiday.setEndDate(laborDayEndTime); |
292 | 0 | holiday.setIsAllDay(true); |
293 | 0 | holiday.setIsDateRange(false); |
294 | |
|
295 | |
|
296 | |
|
297 | |
|
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 | |
|
325 | |
|
326 | 0 | return true; |
327 | |
} |
328 | 0 | if (!endTime1.before(startTime2) && !endTime1.after(endTime2)) { |
329 | |
|
330 | 0 | return true; |
331 | |
} |
332 | 0 | if (!startTime1.after(startTime2) && !endTime1.before(endTime2)) { |
333 | |
|
334 | 0 | return true; |
335 | |
} |
336 | 0 | return false; |
337 | |
} |
338 | |
|
339 | |
} |