Coverage Report - org.kuali.student.lum.workflow.CourseStateChangeServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseStateChangeServiceImpl
0%
0/75
0%
0/64
5.571
 
 1  
 package org.kuali.student.lum.workflow;
 2  
 
 3  
 import java.util.Iterator;
 4  
 import java.util.List;
 5  
 
 6  
 import org.kuali.student.common.dto.DtoConstants;
 7  
 import org.kuali.student.common.dto.StatusInfo;
 8  
 import org.kuali.student.common.exceptions.CircularReferenceException;
 9  
 import org.kuali.student.common.exceptions.DataValidationErrorException;
 10  
 import org.kuali.student.common.exceptions.DoesNotExistException;
 11  
 import org.kuali.student.common.exceptions.InvalidParameterException;
 12  
 import org.kuali.student.common.exceptions.MissingParameterException;
 13  
 import org.kuali.student.common.exceptions.OperationFailedException;
 14  
 import org.kuali.student.common.exceptions.PermissionDeniedException;
 15  
 import org.kuali.student.common.exceptions.VersionMismatchException;
 16  
 import org.kuali.student.common.versionmanagement.dto.VersionDisplayInfo;
 17  
 import org.kuali.student.core.statement.dto.StatementTreeViewInfo;
 18  
 import org.kuali.student.lum.course.dto.CourseInfo;
 19  
 import org.kuali.student.lum.course.service.CourseService;
 20  
 import org.kuali.student.lum.course.service.CourseServiceConstants;
 21  
 import org.springframework.transaction.annotation.Transactional;
 22  
 
 23  
 @Transactional(noRollbackFor = { DoesNotExistException.class }, rollbackFor = { Throwable.class })
 24  0
 public class CourseStateChangeServiceImpl {
 25  
         private CourseService courseService;
 26  
 
 27  
         /**
 28  
          * Change the state of a course to a new state.
 29  
          * This method exists to help handle some extra logic that was required
 30  
          * to implement Pilot courses, Administrative Retire and Retire by Proposal.
 31  
          * 
 32  
          * @param courseId id of course
 33  
          * @param newState the new state for the course
 34  
          * @param prevEndTermAtpId the current version end date of course
 35  
          * @return
 36  
          * @throws Exception
 37  
          */
 38  
         public StatusInfo changeState(String courseId, String newState,        String prevEndTermAtpId) throws Exception {
 39  
 
 40  0
                 CourseInfo courseInfo = courseService.getCourse(courseId);
 41  
 
 42  0
                 StatusInfo ret = new StatusInfo();
 43  0
                 if ((newState!=null) && (newState.equals(DtoConstants.STATE_ACTIVE))) {
 44  0
                         if ((courseInfo!=null) && courseInfo.isPilotCourse()){
 45  
                                 // Pilot Course Creates come through here the 2nd time and
 46  
                                 // gets Retired but first, add fields which are required only for Retired State
 47  0
                                 courseInfo.getAttributes().put("retirementRationale", "Pilot Course");
 48  0
                                 courseInfo.getAttributes().put("lastTermOffered", courseInfo.getEndTerm());
 49  0
                                 courseInfo.setState(DtoConstants.STATE_ACTIVE);
 50  0
                                 retireCourse(courseInfo);
 51  
                         }else{
 52  
                                 // Pilot course gets activated the first time through 
 53  0
                                 activateCourse(courseInfo, prevEndTermAtpId);
 54  
                         }
 55  0
                 } else if (newState.equals(DtoConstants.STATE_RETIRED)){
 56  
                               // Admin Retire and Retire by Proposal should both end up here.
 57  0
                                   retireCourse(courseInfo);
 58  
                         } 
 59  
                 
 60  
                         
 61  
                 
 62  
 
 63  0
                 ret.setSuccess(new Boolean(true));
 64  
 
 65  0
                 return ret;
 66  
         }
 67  
 
 68  
         /**
 69  
          * Activate a course version. Only course with a state of "Approved" can be activated.
 70  
          * 
 71  
          * @param courseToActivate
 72  
          * @param prevEndTermAtpId the end term we set on the current version
 73  
          */
 74  
         protected void activateCourse(CourseInfo courseToActivate, String prevEndTermAtpId) throws Exception{
 75  0
             CourseInfo currVerCourse = getCurrentVersionOfCourse(courseToActivate);
 76  0
             String existingState = courseToActivate.getState();
 77  0
                 String currVerState = currVerCourse.getState();
 78  0
                 boolean isCurrVer = (courseToActivate.getId().equals(currVerCourse.getId()));
 79  
                 
 80  0
                 if (existingState.equals(DtoConstants.STATE_DRAFT)) {
 81  
                         // since this is approved if isCurrVer we can assume there are no previously active versions to deal with
 82  0
                         if (isCurrVer) {
 83  
                                 // setstate for thisVerCourse and setCurrentVersion(courseId)
 84  0
                                 updateCourseVersionStates(courseToActivate, DtoConstants.STATE_ACTIVE, currVerCourse, null, true, prevEndTermAtpId);
 85  0
                         } else if (currVerState.equals(DtoConstants.STATE_ACTIVE) ||
 86  
                                         currVerState.equals(DtoConstants.STATE_SUSPENDED) ||
 87  
                                         currVerState.equals(DtoConstants.STATE_RETIRED)
 88  
                         ) {
 89  0
                                 updateCourseVersionStates(courseToActivate, DtoConstants.STATE_ACTIVE, currVerCourse, DtoConstants.STATE_SUPERSEDED, true, prevEndTermAtpId);
 90  
                         }
 91  
                 }
 92  0
         }
 93  
         
 94  
         /**
 95  
          * Retire a course version. Only course with a state of "Active" or "Suspended" can be retired
 96  
          * 
 97  
          * @param courseToRetire the course to retire
 98  
          */
 99  
         protected void retireCourse(CourseInfo courseToRetire) throws Exception{
 100  0
             String existingState = courseToRetire.getState();                
 101  
                 
 102  0
             if (existingState.equals(DtoConstants.STATE_ACTIVE) || existingState.equals(DtoConstants.STATE_SUSPENDED)){
 103  0
                     courseToRetire.setState(DtoConstants.STATE_RETIRED);
 104  
                     
 105  0
                     courseService.updateCourse(courseToRetire);
 106  0
                         updateStatementTreeViewInfoState(courseToRetire);                    
 107  
             }
 108  0
         }
 109  
         
 110  
         /**
 111  
          * Get the current version of course from another version of course
 112  
          * 
 113  
          * @param verIndId
 114  
          */
 115  
         protected CourseInfo getCurrentVersionOfCourse(CourseInfo course)
 116  
                         throws Exception {
 117  
                 // Get version independent id of course
 118  0
                 String verIndId = course.getVersionInfo().getVersionIndId();
 119  
 
 120  
                 // Get id of current version of course given the versionindependen id
 121  0
                 VersionDisplayInfo curVerDisplayInfo = courseService.getCurrentVersion(
 122  
                                 CourseServiceConstants.COURSE_NAMESPACE_URI, verIndId);
 123  0
                 String curVerId = curVerDisplayInfo.getId();
 124  
 
 125  
                 // Return the current version of the course
 126  0
                 CourseInfo currVerCourse = courseService.getCourse(curVerId);
 127  
 
 128  0
                 return currVerCourse;
 129  
         }
 130  
 
 131  
         /**
 132  
          * Based on null values, updates states of thisVerCourse and currVerCourse
 133  
          * and sets thisVerCourse as the current version. Attempts to rollback
 134  
          * transaction on exception.
 135  
          * 
 136  
          * @param thisVerCourse
 137  
          *            this is the version that the user selected to change the state
 138  
          * @param thisVerNewState
 139  
          *            this is state that the user selected to change thisVerCourse
 140  
          *            to
 141  
          * @param currVerCourse
 142  
          *            this is the current version of the course
 143  
          *            (currentVersionStartDt <= now && currentVersionEndDt > now)
 144  
          * @param currVerNewState
 145  
          *            this is the state that we need to set the current version to.
 146  
          *            Set to null to not update the currVerCourse state.
 147  
          * @param makeCurrent
 148  
          *            if true we'll set thisVerCourse as the current version.
 149  
          * @param prevEndTermAtpId
 150  
          *            the end term for the previous version to end on
 151  
          * @throws Exception
 152  
          */
 153  
         @Transactional(readOnly = false)
 154  
         private void updateCourseVersionStates(CourseInfo thisVerCourse,
 155  
                         String thisVerNewState, CourseInfo currVerCourse,
 156  
                         String currVerNewState, boolean makeCurrent,
 157  
                         String prevEndTermAtpId) throws Exception {
 158  0
                 String thisVerPrevState = thisVerCourse.getState();
 159  
 
 160  
                 // if already current, will throw error if you try to make the current
 161  
                 // version the current version.
 162  0
                 boolean isCurrent = thisVerCourse.getId().equals(currVerCourse.getId());
 163  0
                 if(!makeCurrent || !isCurrent || !thisVerCourse.getVersionInfo().getSequenceNumber().equals(1)){
 164  0
                         makeCurrent &= !isCurrent;
 165  
                 }
 166  
 
 167  0
                 if (thisVerNewState == null) {
 168  0
                         throw new InvalidParameterException("new state cannot be null");
 169  
                 } else {
 170  0
                         thisVerCourse.setState(thisVerNewState);
 171  0
                         courseService.updateCourse(thisVerCourse);
 172  0
                         updateStatementTreeViewInfoState(thisVerCourse);
 173  
                 }
 174  
 
 175  
                 // won't get called if previous exception was thrown
 176  0
                 if (currVerNewState != null) {
 177  0
                         currVerCourse.setState(currVerNewState);
 178  0
                         if(currVerCourse.getEndTerm()==null){
 179  0
                                 currVerCourse.setEndTerm(prevEndTermAtpId);
 180  
                         }
 181  0
                         courseService.updateCourse(currVerCourse);
 182  0
                         updateStatementTreeViewInfoState(currVerCourse);
 183  
                 }
 184  
 
 185  0
                 if (makeCurrent == true) {
 186  0
                         courseService.setCurrentCourseVersion(thisVerCourse.getId(),
 187  
                                         null);
 188  
                 }
 189  
 
 190  
                 // for all draft and approved courses set the state to superseded.
 191  
                 // we should only need to evaluated versions with sequence number
 192  
                 // higher than previous active course. If the course you're
 193  
                 // activating is the current course check all versions.
 194  0
                 if (thisVerPrevState.equals(DtoConstants.STATE_APPROVED)
 195  
                                 && thisVerNewState.equals(DtoConstants.STATE_ACTIVE)) {
 196  
 
 197  0
                         List<VersionDisplayInfo> versions = courseService.getVersions(
 198  
                                         CourseServiceConstants.COURSE_NAMESPACE_URI, thisVerCourse
 199  
                                                         .getVersionInfo().getVersionIndId());
 200  0
                         Long startSeq = new Long(1);
 201  
 
 202  0
                         if (!isCurrent && (currVerCourse.getId() != thisVerCourse.getId())) {
 203  0
                                 startSeq = currVerCourse.getVersionInfo().getSequenceNumber() + 1;
 204  
                         }
 205  
 
 206  0
                         for (VersionDisplayInfo versionInfo : versions) {
 207  0
                                 if (versionInfo.getSequenceNumber() >= startSeq) {
 208  0
                                         CourseInfo otherCourse = courseService
 209  
                                                         .getCourse(versionInfo.getId());
 210  0
                                         if (otherCourse.getState().equals(
 211  
                                                         DtoConstants.STATE_APPROVED)
 212  
                                                         || otherCourse.getState().equals(
 213  
                                                                         DtoConstants.STATE_SUBMITTED)
 214  
                                                         || otherCourse.getState().equals(
 215  
                                                                         DtoConstants.STATE_DRAFT)) {
 216  0
                                                 otherCourse.setState(DtoConstants.STATE_SUPERSEDED);
 217  0
                                                 courseService.updateCourse(otherCourse);
 218  0
                                                 updateStatementTreeViewInfoState(otherCourse);
 219  
                                         }
 220  0
                                 }
 221  
                         }
 222  
                 }
 223  
 
 224  0
         }
 225  
 
 226  
         public void setCourseService(CourseService courseService) {
 227  0
                 this.courseService = courseService;
 228  0
         }
 229  
 
 230  
         /**
 231  
          * This method will load all the statements in a course from the course web
 232  
          * service, recursively update the state of each statement in the statement
 233  
          * tree, and save the update statements back to the web service.
 234  
          * 
 235  
          * 
 236  
          * @param courseInfo
 237  
          *            The course to update (call setState() in this object to set
 238  
          *            the state)
 239  
          * @throws DoesNotExistException
 240  
          * @throws InvalidParameterException
 241  
          * @throws MissingParameterException
 242  
          * @throws OperationFailedException
 243  
          * @throws PermissionDeniedException
 244  
          * @throws DataValidationErrorException
 245  
          * @throws CircularReferenceException
 246  
          * @throws VersionMismatchException
 247  
          */
 248  
         public void updateStatementTreeViewInfoState(CourseInfo courseInfo)
 249  
                         throws DoesNotExistException, InvalidParameterException,
 250  
                         MissingParameterException, OperationFailedException,
 251  
                         PermissionDeniedException, DataValidationErrorException,
 252  
                         CircularReferenceException, VersionMismatchException {
 253  
 
 254  
                 // Call course web service to get all requirements/statements for this
 255  
                 // course
 256  0
                 List<StatementTreeViewInfo> statementTreeViewInfos = courseService
 257  
                                 .getCourseStatements(courseInfo.getId(), null, null);
 258  
 
 259  0
                 if(statementTreeViewInfos != null){
 260  
                         // Recursively update state on all requirements/statements in the tree
 261  0
                         for (Iterator<StatementTreeViewInfo> it = statementTreeViewInfos.iterator(); it.hasNext();){
 262  0
                                 StatementUtil.updateStatementTreeViewInfoState(courseInfo.getState(), it.next());
 263  
                         }
 264  
         
 265  
                         // Call the course web service and update the requirement/statement tree
 266  
                         // with the new state
 267  0
                         for (Iterator<StatementTreeViewInfo> it = statementTreeViewInfos.iterator(); it.hasNext();){
 268  0
                                 courseService.updateCourseStatement(courseInfo.getId(), it.next());
 269  
                         }
 270  
                 }
 271  0
         }
 272  
 
 273  
 }