View Javadoc

1   /**
2    * Copyright 2012 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   *
15   * Created by Charles on 5/7/12
16   */
17  package org.kuali.student.enrollment.class2.courseoffering.controller;
18  
19  import org.apache.commons.lang.BooleanUtils;
20  import org.apache.commons.lang.UnhandledException;
21  import org.apache.log4j.Logger;
22  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
23  import org.kuali.rice.krad.uif.UifConstants;
24  import org.kuali.rice.krad.uif.UifParameters;
25  import org.kuali.rice.krad.uif.view.History;
26  import org.kuali.rice.krad.uif.view.HistoryEntry;
27  import org.kuali.rice.krad.util.GlobalVariables;
28  import org.kuali.rice.krad.util.KRADConstants;
29  import org.kuali.rice.krad.util.UrlFactory;
30  import org.kuali.rice.krad.web.controller.UifControllerBase;
31  import org.kuali.rice.krad.web.form.UifFormBase;
32  import org.kuali.student.enrollment.class2.appointment.util.AppointmentConstants;
33  import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingConstants;
34  import org.kuali.student.enrollment.uif.util.GrowlIcon;
35  import org.kuali.student.enrollment.uif.util.KSUifUtils;
36  import org.kuali.student.r2.core.acal.dto.TermInfo;
37  import org.kuali.student.enrollment.class2.courseoffering.dto.SocRolloverResultItemWrapper;
38  import org.kuali.student.enrollment.class2.courseoffering.form.CourseOfferingRolloverManagementForm;
39  import org.kuali.student.enrollment.class2.courseoffering.service.CourseOfferingViewHelperService;
40  import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
41  import org.kuali.student.enrollment.courseoffering.service.CourseOfferingService;
42  import org.kuali.student.enrollment.courseofferingset.dto.SocInfo;
43  import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultInfo;
44  import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultItemInfo;
45  import org.kuali.student.enrollment.courseofferingset.service.CourseOfferingSetService;
46  import org.kuali.student.r2.common.dto.ContextInfo;
47  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
48  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
49  import org.kuali.student.r2.common.exceptions.MissingParameterException;
50  import org.kuali.student.r2.common.exceptions.OperationFailedException;
51  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
52  import org.kuali.student.r2.common.util.ContextUtils;
53  import org.kuali.student.r2.common.util.constants.CourseOfferingServiceConstants;
54  import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants;
55  import org.kuali.student.r2.common.util.date.DateFormatters;
56  import org.kuali.student.r2.core.class1.state.dto.StateInfo;
57  import org.kuali.student.r2.core.class1.state.service.StateService;
58  import org.kuali.student.r2.core.constants.StateServiceConstants;
59  import org.springframework.stereotype.Controller;
60  import org.springframework.validation.BindingResult;
61  import org.springframework.web.bind.annotation.ModelAttribute;
62  import org.springframework.web.bind.annotation.RequestMapping;
63  import org.springframework.web.bind.annotation.RequestMethod;
64  import org.springframework.web.servlet.ModelAndView;
65  
66  import javax.servlet.http.HttpServletRequest;
67  import javax.servlet.http.HttpServletResponse;
68  import javax.xml.namespace.QName;
69  import java.util.Date;
70  import java.util.LinkedHashMap;
71  import java.util.List;
72  import java.util.Map;
73  import java.util.Properties;
74  import java.util.concurrent.CopyOnWriteArrayList;
75  
76  /**
77   * The controller for Perform Rollover, Rollover Details, and Release to Depts page (all within the same view).
78   *
79   * @author Kuali Student Team
80   */
81  @Controller
82  @RequestMapping(value = "/courseOfferingRollover")
83  public class CourseOfferingRolloverController extends UifControllerBase {
84      private CourseOfferingViewHelperService viewHelperService;
85      private CourseOfferingSetService socService;
86      private CourseOfferingService coService;
87      private StateService stateService;
88  
89      private static final Logger LOGGER = Logger.getLogger(CourseOfferingRolloverController.class);
90      public static final String ROLLOVER_DETAILS_PAGEID = "selectTermForRolloverDetails";
91      public static final String ROLLOVER_MANAGEMENT_VIEWID = "courseOfferingRolloverManagementView";
92      public static final String ROLLOVER_CONFIRM_RELEASE = "releaseToDepts";
93  
94      @Override
95      protected UifFormBase createInitialForm(@SuppressWarnings("unused") HttpServletRequest request) {
96          return new CourseOfferingRolloverManagementForm();
97      }
98  
99      @Override
100     @RequestMapping(method = RequestMethod.GET, params = "methodToCall=start")
101     public ModelAndView start(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
102                               @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) {
103         if (!(form instanceof CourseOfferingRolloverManagementForm)) {
104             throw new RuntimeException("Form object passed into start method was not of expected type CourseOfferingRolloverManagementForm. Got " + form.getClass().getSimpleName());
105         }
106         CourseOfferingRolloverManagementForm theForm = (CourseOfferingRolloverManagementForm) form;
107 
108         // check view authorization
109         // TODO: this needs to be invoked for each request
110         if (form.getView() != null) {
111             String methodToCall = request.getParameter(KRADConstants.DISPATCH_REQUEST_PARAMETER);
112             checkViewAuthorization(theForm, methodToCall);
113         }
114 
115         Map paramMap = request.getParameterMap();
116         if (paramMap.containsKey("pageId")) {
117             String pageId = ((String[]) paramMap.get("pageId"))[0];
118             if (pageId.equals("selectTermsForRollover")) {
119                 return _startPerformRollover(form, result, request, response);
120             } else if (pageId.equals("releaseToDepts")) {
121                 return _startReleaseToDepts(theForm, result, request, response);
122             } else if (pageId.equals("selectTermForRolloverDetails")) {
123                 return _startRolloverDetails(form, result, request, response);
124             }
125         }
126         return getUIFModelAndView(theForm);
127         // return super.start(theForm, result, request, response);
128     }
129 
130     private ModelAndView _startPerformRollover(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
131                                                @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) {
132         CourseOfferingRolloverManagementForm theForm = (CourseOfferingRolloverManagementForm) form;
133         LOGGER.info("startPerformRollover");
134         return getUIFModelAndView(theForm);
135         // return super.start(theForm, result, request, response);
136     }
137 
138     private ModelAndView _startRolloverDetails(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
139                                                @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) {
140         CourseOfferingRolloverManagementForm theForm = (CourseOfferingRolloverManagementForm) form;
141         LOGGER.info("startRolloverDetails");
142         String rolloverTerm = theForm.getRolloverTargetTermCode();
143 
144         try {
145             if (rolloverTerm != null && !"".equals(rolloverTerm)) {
146                 return showRolloverResults(theForm, result, request, response);
147             }
148         } catch (Exception ex) {
149             return getUIFModelAndView(theForm);
150         }
151 
152         return getUIFModelAndView(theForm);
153     }
154 
155     private ModelAndView _startReleaseToDepts(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
156                                               @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) {
157         LOGGER.info("startReleaseToDepts");
158         form.computeReleaseToDeptsDisabled();
159         return getUIFModelAndView(form);
160     }
161 
162     @RequestMapping(params = "methodToCall=goTargetTerm")
163     public ModelAndView goTargetTerm(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
164                                      @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
165         CourseOfferingViewHelperService helper = getViewHelperService(form);
166         List<TermInfo> termList = helper.findTermByTermCode(form.getTargetTermCode());
167         if (termList != null && termList.size() == 1) {
168             //validation to check if already rollover target term exists..
169             List<String> coIds = this._getCourseOfferingService().getCourseOfferingIdsByTerm(termList.get(0).getId(), true, new ContextInfo());
170             if (!coIds.isEmpty()) {
171                 // Print error message if there are course offerings in the target term
172                 GlobalVariables.getMessageMap().putError("targetTermCode", "error.courseoffering.rollover.targetTermExists");
173                 form.resetForm();
174                 return getUIFModelAndView(form);
175             }
176             // Get first term
177             TermInfo matchingTerm = termList.get(0);
178             String targetTermCode = matchingTerm.getCode();
179             form.setDisplayedTargetTermCode(targetTermCode);
180             // Set the start date
181             Date startDate = matchingTerm.getStartDate();
182             String startDateStr = DateFormatters.COURSE_OFFERING_VIEW_HELPER_DATE_FORMATTER.format(startDate);
183             form.setTargetTermStartDate(startDateStr);
184             // Set the end date
185             Date endDate = matchingTerm.getEndDate();
186             String endDateStr = DateFormatters.COURSE_OFFERING_VIEW_HELPER_DATE_FORMATTER.format(endDate);
187             form.setTargetTermEndDate(endDateStr);
188             // TODO: Put in last rollover date (Kirk says this may be unnecessary in new wireframes 5/18/2012)
189             form.setTargetTerm(matchingTerm);
190             form.setIsGoSourceButtonDisabled(false); // Make go button for source enabled
191         } else {
192             form.setTargetTerm(null);
193             form.resetForm();
194             GlobalVariables.getMessageMap().putError("targetTermCode", "error.courseoffering.targetTerm.inValid");
195         }
196         return getUIFModelAndView(form);
197     }
198 
199     @RequestMapping(params = "methodToCall=goSourceTerm")
200     public ModelAndView goSourceTerm(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
201                                      @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
202         // validation to check for valid term.
203         if (form.getTargetTermCode() == null || form.getTargetTermCode().length() == 0) {
204             GlobalVariables.getMessageMap().putError("targetTermCode", "error.submit.sourceTerm");
205             return getUIFModelAndView(form);
206         }
207         if (form.getSourceTermCode() == null || form.getSourceTermCode().length() == 0) {
208             GlobalVariables.getMessageMap().putError("sourceTermCode", "error.courseoffering.sourceTerm.inValid");
209             return getUIFModelAndView(form);
210         }
211         CourseOfferingViewHelperService helper = getViewHelperService(form);
212 
213         // validation to check for like terms and target term year comes before source term year.
214         String targetTermCd = form.getTargetTermCode();
215         String sourceTermCd = form.getSourceTermCode();
216         List<TermInfo> targetTermsByCode = helper.findTermByTermCode(targetTermCd);
217         List<TermInfo> sourceTermsByCode = helper.findTermByTermCode(sourceTermCd);
218 
219         //Check that the source and target terms exist in the db
220         if (sourceTermsByCode.isEmpty()) {
221             GlobalVariables.getMessageMap().putError("sourceTermCode", "error.courseoffering.sourceTerm.inValid");
222             form.setIsRolloverButtonDisabled(true);
223             return getUIFModelAndView(form);
224         }
225         if (targetTermsByCode.isEmpty()) {
226             GlobalVariables.getMessageMap().putError("targetTermCode", "error.courseoffering.targetTerm.inValid");
227             form.setIsRolloverButtonDisabled(true);
228             return getUIFModelAndView(form);
229         }
230 
231         TermInfo targetTerm = helper.findTermByTermCode(targetTermCd).get(0);
232         TermInfo sourceTerm = helper.findTermByTermCode(sourceTermCd).get(0);
233         boolean likeTerms = sourceTerm.getTypeKey().equals(targetTerm.getTypeKey());
234         boolean sourcePrecedesTarget = sourceTerm.getStartDate().before(targetTerm.getStartDate());
235         boolean sourceTermHasSoc = helper.termHasSoc(sourceTerm.getId(), form);
236         if (!likeTerms) {
237             GlobalVariables.getMessageMap().putError("sourceTermCode", "error.likeTerms.validation");
238             form.setIsRolloverButtonDisabled(true);
239             return getUIFModelAndView(form);
240         } else if (!sourcePrecedesTarget) {
241             GlobalVariables.getMessageMap().putError("sourceTermCode", "error.years.validation");
242             form.setIsRolloverButtonDisabled(true);
243             return getUIFModelAndView(form);
244         } else if (!sourceTermHasSoc) {
245             GlobalVariables.getMessageMap().putError("sourceTermCode", "error.rollover.sourceTerm.noSoc");
246             form.setIsRolloverButtonDisabled(true);
247             return getUIFModelAndView(form);
248         }
249 
250         List<TermInfo> termList = helper.findTermByTermCode(form.getSourceTermCode());
251         if (termList != null && termList.size() == 1) {
252             // Get first term
253             TermInfo matchingTerm = termList.get(0);
254             String sourceTermCode = matchingTerm.getCode();
255             form.setDisplayedSourceTermCode(sourceTermCode);
256             // Set the start date
257             Date startDate = matchingTerm.getStartDate();
258             String startDateStr = DateFormatters.COURSE_OFFERING_VIEW_HELPER_DATE_FORMATTER.format(startDate);
259             form.setSourceTermStartDate(startDateStr);
260             // Set the end date
261             Date endDate = matchingTerm.getEndDate();
262             String endDateStr = DateFormatters.COURSE_OFFERING_VIEW_HELPER_DATE_FORMATTER.format(endDate);
263             form.setSourceTermEndDate(endDateStr);
264             form.setSourceTerm(matchingTerm);
265             form.setIsRolloverButtonDisabled(false); // Enable the button
266         } else {
267             form.setTargetTerm(null);
268             form.resetForm();
269             GlobalVariables.getMessageMap().putError("soucrceTermCode", "error.courseoffering.sourceTerm.inValid");
270         }
271         return getUIFModelAndView(form);
272     }
273 
274     @RequestMapping(params = "methodToCall=performRollover")
275     public ModelAndView performRollover(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
276                                         @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
277         CourseOfferingViewHelperService helper = getViewHelperService(form);
278 
279         if (form.getSourceTerm() == null || form.getTargetTerm() == null) {
280             form.setStatusField("(setUp) Source/target term objects appear to be missing");
281             return getUIFModelAndView(form);
282         }
283         form.setStatusField("");
284         String sourceTermId = form.getSourceTerm().getId();
285         String targetTermId = form.getTargetTerm().getId();
286 
287         boolean success = helper.performRollover(sourceTermId, targetTermId, form);
288         if (success) {
289             form.setRolloverTargetTermCode(form.getTargetTermCode());
290             showRolloverResults(form, result, request, response); // TODO: Factor out a common method?
291             // Switch to rollover details page
292             return start(form, result, request, response);
293             //return getUIFModelAndView(form, ROLLOVER_DETAILS_PAGEID);
294         } else {
295             // Had problems, stay in the same screen
296             return getUIFModelAndView(form);
297         }
298     }
299 
300     @RequestMapping(params = "methodToCall=performReverseRollover")
301     public ModelAndView performReverseRollover(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
302                                                @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
303         CourseOfferingViewHelperService helper = getViewHelperService(form);
304         if (form.getSourceTerm() == null || form.getTargetTerm() == null) {
305             form.setStatusField("(cleanUp) Source/target term objects appear to be missing");
306             return getUIFModelAndView(form);
307         }
308         form.setStatusField("");
309 
310         String sourceTermId = form.getSourceTerm().getId();
311         String targetTermId = form.getTargetTerm().getId();
312         SocRolloverResultInfo info = helper.performReverseRollover(sourceTermId, targetTermId, form);
313         if (info != null) {
314             form.setStatusField("Num items processed: " + info.getItemsProcessed());
315         }
316         return getUIFModelAndView(form);
317     }
318 
319     public CourseOfferingViewHelperService getViewHelperService(CourseOfferingRolloverManagementForm rolloverForm) {
320         if (viewHelperService == null) {
321             if (rolloverForm.getView().getViewHelperServiceClass() != null) {
322                 viewHelperService = (CourseOfferingViewHelperService) rolloverForm.getView().getViewHelperService();
323             } else {
324                 viewHelperService = (CourseOfferingViewHelperService) rolloverForm.getPostedView().getViewHelperService();
325             }
326         }
327         return viewHelperService;
328     }
329 
330     private void _disableReleaseToDeptsIfNeeded(CourseOfferingViewHelperService helper, String targetTermId,
331                                                 CourseOfferingRolloverManagementForm form) {
332         SocInfo socInfo = helper.getMainSoc(targetTermId);
333         if (socInfo == null) {
334             // Disable if no term found
335             form.setReleaseToDeptsInvalidTerm(true);
336         } else {
337             String stateKey = socInfo.getStateKey();
338             if (!CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY.equals(stateKey)) {
339                 // Assume it's been released if no longer in draft state (TODO: may not be true--revisit)
340                 form.setSocReleasedToDepts(true);
341             } else { // In draft state
342                 form.setSocReleasedToDepts(false);
343             }
344         }
345     }
346 
347     private String _computeRolloverDuration(Date dateInitiated, Date dateCompleted) {
348         long diffInMillis = dateCompleted.getTime() - dateInitiated.getTime();
349         long diffInSeconds = diffInMillis / 1000;
350         int minutes = (int) (diffInSeconds / 60);
351         int seconds = (int) (diffInSeconds % 60);
352         int hours = minutes / 60;
353         minutes = minutes % 60;
354         String result = seconds + "s";
355         if (minutes > 0 || hours > 0) {
356             result = minutes + "m " + result;
357         }
358         if (hours > 0) {
359             result = hours + "h " + result;
360         }
361         return result;
362     }
363 
364     private String _createPlural(int count) {
365         return count == 1 ? "" : "s";
366     }
367 
368     private String _createStatusString(SocRolloverResultInfo socRolloverResultInfo) {
369         String status = "";
370         String stateKey = socRolloverResultInfo.getStateKey();
371         if (CourseOfferingSetServiceConstants.SUBMITTED_RESULT_STATE_KEY.equals(stateKey) ||
372                 CourseOfferingSetServiceConstants.RUNNING_RESULT_STATE_KEY.equals(stateKey)) {
373             status = " (in progress)";
374         } else if (CourseOfferingSetServiceConstants.ABORTED_RESULT_STATE_KEY.equals(stateKey)) {
375             status = " (aborted)";
376         }
377         return status;
378     }
379 
380     private void _setStatus(String stateKey, CourseOfferingRolloverManagementForm form) {
381         if (CourseOfferingSetServiceConstants.FINISHED_RESULT_STATE_KEY.equals(stateKey)) {
382             form.setStatusField("Finished");
383             form.setRolloverCompleted(true);
384         } else if (CourseOfferingSetServiceConstants.RUNNING_RESULT_STATE_KEY.equals(stateKey) ||
385                 CourseOfferingSetServiceConstants.SUBMITTED_RESULT_STATE_KEY.equals(stateKey)) {
386             form.setStatusField("In Progress");
387             form.setRolloverCompleted(false);
388         } else if (CourseOfferingSetServiceConstants.ABORTED_RESULT_STATE_KEY.equals(stateKey)) {
389             form.setRolloverCompleted(true);
390         }
391     }
392 
393     private void _displayRolloverInfo(SocInfo socInfo, SocRolloverResultInfo socRolloverResultInfo,
394                                       CourseOfferingRolloverManagementForm form, CourseOfferingViewHelperService helper,
395                                       String stateKey, String targetTermId) {
396         if (socInfo != null) {
397             // Set some display fields that show friendly, human-readable term data
398             String friendlySourceTermDesc = helper.getTermDesc(socInfo.getTermId());
399             form.setRolloverSourceTermDesc(friendlySourceTermDesc);
400             String friendlyTargetTermDesc = helper.getTermDesc(targetTermId);
401             form.setRolloverTargetTermDesc(friendlyTargetTermDesc);
402         }
403         Date dateInitiated = socRolloverResultInfo.getDateInitiated();
404         String startDateStr = helper.formatDateAndTime(dateInitiated);
405         form.setDateInitiated(startDateStr);
406         // if items skipped is null, then below condition passes and items skipped is calculated
407         if (socRolloverResultInfo.getCourseOfferingsCreated() == null || socRolloverResultInfo.getCourseOfferingsCreated().toString().length() < 1) {
408             Integer temp = socRolloverResultInfo.getItemsExpected() - socRolloverResultInfo.getItemsProcessed();
409             String plural = _createPlural(temp);
410             form.setCourseOfferingsAllowed(socRolloverResultInfo.getItemsProcessed() + " transitioned with " + temp + " exception" + plural);
411         } else {
412             // This is the official way to compute this
413             String plural = _createPlural(socRolloverResultInfo.getCourseOfferingsSkipped());
414             form.setCourseOfferingsAllowed(socRolloverResultInfo.getCourseOfferingsCreated() + " transitioned with " +
415                     socRolloverResultInfo.getCourseOfferingsSkipped() + " exception" + plural);
416         }
417         String plural = _createPlural(socRolloverResultInfo.getActivityOfferingsSkipped());
418         form.setActivityOfferingsAllowed(socRolloverResultInfo.getActivityOfferingsCreated() + " transitioned with " +
419                 socRolloverResultInfo.getActivityOfferingsSkipped() + " exception" + plural);
420         Date dateCompleted = socRolloverResultInfo.getDateCompleted();
421         String updatedDateStr = helper.formatDateAndTime(dateCompleted);
422         // The status displays whether the time is in progress or aborted or nothing if it's completed.
423         String status = _createStatusString(socRolloverResultInfo);
424         if ((CourseOfferingSetServiceConstants.SUBMITTED_RESULT_STATE_KEY.equals(stateKey) ||
425                 CourseOfferingSetServiceConstants.RUNNING_RESULT_STATE_KEY.equals(stateKey))) {
426             form.setDateCompleted("Rollover in progress");  // DanS doesn't want a date completed if still in progress
427         } else {
428             form.setDateCompleted(updatedDateStr + status);
429         }
430         // Set value on how long rollover has been running
431         String rolloverDuration = _computeRolloverDuration(dateInitiated, dateCompleted);
432         form.setRolloverDuration(rolloverDuration + status);
433     }
434 
435     private void _displayRolloverItems(CourseOfferingRolloverManagementForm form,
436                                        List<SocRolloverResultItemInfo> socRolloverResultItemInfos,
437                                        List<SocRolloverResultItemInfo> socRolloverResultItemInfosCopy)
438             throws InvalidParameterException, MissingParameterException, DoesNotExistException, PermissionDeniedException,
439             OperationFailedException {
440         // Clear out the existing list of result items
441         form.getSocRolloverResultItems().clear();
442 
443         for (SocRolloverResultItemInfo socRolloverResultItemInfo : socRolloverResultItemInfosCopy) {
444             if (CourseOfferingSetServiceConstants.SUCCESSFUL_RESULT_ITEM_STATES.contains(socRolloverResultItemInfo.getStateKey())) {
445                 socRolloverResultItemInfos.remove(socRolloverResultItemInfo);
446             } else {
447                 String courseOfferingId = socRolloverResultItemInfo.getTargetCourseOfferingId();
448                 if (courseOfferingId == null || courseOfferingId.isEmpty()) {
449                     courseOfferingId = socRolloverResultItemInfo.getSourceCourseOfferingId();
450                 }
451 
452                 CourseOfferingInfo courseOfferingInfo = _getCourseOfferingService().getCourseOffering(courseOfferingId, new ContextInfo());
453                 SocRolloverResultItemWrapper socRolloverResultItemWrapper = new SocRolloverResultItemWrapper();
454                 socRolloverResultItemWrapper.setCourse(courseOfferingInfo.getCourseOfferingCode());
455                 if (socRolloverResultItemInfo.getMessage() != null) {
456                     socRolloverResultItemWrapper.setMessage(socRolloverResultItemInfo.getMessage().getPlain());
457                 }
458                 socRolloverResultItemWrapper.setState(socRolloverResultItemInfo.getStateKey());
459 
460                 try {
461                     StateInfo stateInfo = this._getStateService().getState(socRolloverResultItemInfo.getStateKey(), ContextUtils.getContextInfo());
462                     if (stateInfo != null) {
463                         socRolloverResultItemWrapper.setStateName((stateInfo.getName() != null) ? stateInfo.getName() : socRolloverResultItemInfo.getStateKey());
464                     }
465                 } catch (DoesNotExistException ex) {
466                     socRolloverResultItemWrapper.setStateName(socRolloverResultItemInfo.getStateKey());
467                 }
468 
469 
470                 form.getSocRolloverResultItems().add(socRolloverResultItemWrapper);
471             }
472         }
473     }
474 
475     // This method displays rollover result Infos for specific target term.
476     @RequestMapping(params = "methodToCall=showRolloverResults")
477     public ModelAndView showRolloverResults(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
478                                             @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
479         //helper class for courseOfferingSetService
480         CourseOfferingViewHelperService helper = getViewHelperService(form);
481         //To fetch Term by code which is desirable.
482         String targetTermCode = form.getRolloverTargetTermCode();
483         List<TermInfo> termList = helper.findTermByTermCode(targetTermCode);
484         if (termList.isEmpty()) {
485             GlobalVariables.getMessageMap().putError("rolloverTargetTermCode", "error.rollover.targetTerm.noResults", targetTermCode);
486             form.resetForm(); // TODO: Does this make sense?  I don't think so. cclin
487             return getUIFModelAndView(form);
488         } else {
489             TermInfo targetTerm = termList.get(0);
490             form.setTargetTerm(targetTerm);
491             form.setTargetTermCode(targetTermCode);
492             String targetTermId = targetTerm.getId();
493             // Get rollover result info for target term
494             List<SocRolloverResultInfo> socRolloverResultInfos = helper.findRolloverByTerm(targetTermId);
495             if (socRolloverResultInfos == null || socRolloverResultInfos.isEmpty()) {
496                 GlobalVariables.getMessageMap().putError("rolloverTargetTermCode", "error.rollover.targetTerm.noResults", targetTermCode);
497                 form.resetForm(); // TODO: Does this make sense?  I don't think so. cclin
498                 return getUIFModelAndView(form);
499             } else {
500                 if (socRolloverResultInfos.size() > 1) {
501                     LOGGER.warn("Multiple Soc Rollover Results Found");
502                 }
503                 _disableReleaseToDeptsIfNeeded(helper, targetTermId, form);
504                 SocRolloverResultInfo socRolloverResultInfo = socRolloverResultInfos.get(0);
505                 String stateKey = socRolloverResultInfo.getStateKey();
506                 _setStatus(stateKey, form);
507                 // SocInfo service to get Source Term Id
508                 SocInfo socInfo = _getSocService().getSoc(socRolloverResultInfo.getSourceSocId(), new ContextInfo());
509                 // Put info in the display fields on the left hand side
510                 _displayRolloverInfo(socInfo, socRolloverResultInfo, form, helper, stateKey, targetTermId);
511 
512                 // CourseOfferingSet service to get Soc Rollover ResultItems by socResultItemInfo id
513                 try {
514                     List<SocRolloverResultItemInfo> socRolloverResultItemInfos =
515                             _getSocService().getSocRolloverResultItemsByResultId(socRolloverResultInfo.getId(), new ContextInfo());
516                     List<SocRolloverResultItemInfo> socRolloverResultItemInfosCopy =
517                             new CopyOnWriteArrayList<SocRolloverResultItemInfo>(socRolloverResultItemInfos);
518 
519                     _displayRolloverItems(form, socRolloverResultItemInfos, socRolloverResultItemInfosCopy);
520                 } catch (UnhandledException ue) {
521                     throw new RuntimeException(ue);
522                 } catch (DoesNotExistException dne) {
523                     throw new RuntimeException(dne);
524                 }
525             }
526         }
527         return getUIFModelAndView(form, ROLLOVER_DETAILS_PAGEID);
528     }
529 
530     /**
531      * This is used in the release to depts page from
532      * CourseOfferingRolloverManagement-ReleaseToDeptsPage.xml
533      */
534     @RequestMapping(params = "methodToCall=releaseToDepts")
535     public ModelAndView releaseToDepts(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
536                                        @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
537         LOGGER.info("releaseToDepts");
538         CourseOfferingViewHelperService helper = getViewHelperService(form);
539         boolean accept = form.getAcceptIndicator();
540         TermInfo targetTerm = form.getTargetTerm();
541         if (!accept) {
542             // Didn't click approval
543             GlobalVariables.getMessageMap().putError("approveCheckbox", "error.rollover.release.notApproved");
544         } else if (targetTerm == null) {
545             // Didn't get term info from Rollover Results page
546             GlobalVariables.getMessageMap().putError("approveCheckbox", "error.rollover.invalidTerm");
547         } else {
548             // We're good!
549             LOGGER.info("Ready to release to depts");
550             SocInfo socInfo = helper.getMainSoc(targetTerm.getId());
551             if (!socInfo.getStateKey().equals(CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY)) {
552                 // If it's not draft, then set variable to disable release to depts in the UI
553                 form.setSocReleasedToDepts(true);
554             } else {
555                 // It's draft, so change to state to open
556                 _getSocService().changeSocState(socInfo.getId(), CourseOfferingSetServiceConstants.OPEN_SOC_STATE_KEY, new ContextInfo());
557                 form.setSocReleasedToDepts(true);
558             }
559             // Do a refresh of the data on rollover details
560             showRolloverResults(form, result, request, response);
561             KSUifUtils.addGrowlMessageIcon(GrowlIcon.SUCCESS, CourseOfferingConstants.COURSEOFFERING_ROLLOVER_RELEASE_TO_DEPTS_SUCCESSFULLY);
562         }
563         return getUIFModelAndView(form);
564     }
565 
566     @RequestMapping(params = "methodToCall=checkApproval")
567     public ModelAndView checkApproval(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
568                                       @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
569         LOGGER.info("checkApproval " + form.getAcceptIndicator());
570         return getUIFModelAndView(form);
571     }
572 
573     @RequestMapping(params = "methodToCall=redoRollover")
574     public ModelAndView redoRollover(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
575                                      @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
576         LOGGER.info("redoRollover ");
577         return getUIFModelAndView(form);
578     }
579 
580     @RequestMapping(params = "methodToCall=confirmReleaseToDepts")
581     public ModelAndView confirmReleaseToDepts(@ModelAttribute("KualiForm") CourseOfferingRolloverManagementForm form, @SuppressWarnings("unused") BindingResult result,
582                                               @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
583         LOGGER.info("confirmReleaseToDepts ");
584         return getUIFModelAndView(form, ROLLOVER_CONFIRM_RELEASE);
585     }
586 
587     private CourseOfferingSetService _getSocService() {
588         if (socService == null) {
589             socService = (CourseOfferingSetService) GlobalResourceLoader.getService(new QName(CourseOfferingSetServiceConstants.NAMESPACE,
590                     CourseOfferingSetServiceConstants.SERVICE_NAME_LOCAL_PART));
591         }
592         return socService;
593     }
594 
595     private CourseOfferingService _getCourseOfferingService() {
596         if (coService == null) {
597             coService = (CourseOfferingService) GlobalResourceLoader.getService(new QName(CourseOfferingServiceConstants.NAMESPACE,
598                     CourseOfferingServiceConstants.SERVICE_NAME_LOCAL_PART));
599         }
600         return coService;
601     }
602 
603     private StateService _getStateService() {
604         if (stateService == null) {
605             stateService = (StateService) GlobalResourceLoader.getService(new QName(StateServiceConstants.NAMESPACE,
606                     StateServiceConstants.SERVICE_NAME_LOCAL_PART));
607         }
608         return stateService;
609     }
610 }