Coverage Report - org.kuali.student.lum.workflow.CoursePostProcessorBase
 
Classes in this File Line Coverage Branch Coverage Complexity
CoursePostProcessorBase
0%
0/67
0%
0/38
3.6
 
 1  
 /**
 2  
  * 
 3  
  */
 4  
 package org.kuali.student.lum.workflow;
 5  
 
 6  
 import java.util.Iterator;
 7  
 import java.util.List;
 8  
 
 9  
 import javax.xml.namespace.QName;
 10  
 
 11  
 import org.apache.commons.lang.StringUtils;
 12  
 import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
 13  
 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
 14  
 import org.kuali.rice.kew.postprocessor.ActionTakenEvent;
 15  
 import org.kuali.rice.kew.postprocessor.DocumentRouteStatusChange;
 16  
 import org.kuali.rice.kew.postprocessor.IDocumentEvent;
 17  
 import org.kuali.rice.kew.util.KEWConstants;
 18  
 import org.kuali.student.common.dto.DtoConstants;
 19  
 import org.kuali.student.common.exceptions.OperationFailedException;
 20  
 import org.kuali.student.core.proposal.dto.ProposalInfo;
 21  
 import org.kuali.student.core.statement.dto.ReqComponentInfo;
 22  
 import org.kuali.student.core.statement.dto.StatementTreeViewInfo;
 23  
 import org.kuali.student.lum.course.dto.CourseInfo;
 24  
 import org.kuali.student.lum.course.service.CourseService;
 25  
 import org.kuali.student.lum.course.service.CourseServiceConstants;
 26  
 import org.springframework.transaction.annotation.Transactional;
 27  
 
 28  
 /**
 29  
  * A base post processor class for Course document types in Workflow.
 30  
  *
 31  
  */
 32  
 @Transactional(readOnly=true, rollbackFor={Throwable.class})
 33  0
 public class CoursePostProcessorBase extends KualiStudentPostProcessorBase {
 34  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CoursePostProcessorBase.class);
 35  
 
 36  
     private CourseService courseService;
 37  
 
 38  
     @Override
 39  
     protected void processWithdrawActionTaken(ActionTakenEvent actionTakenEvent, ProposalInfo proposalInfo) throws Exception {
 40  0
         LOG.info("Will set CLU state to '" + DtoConstants.STATE_SUBMITTED + "'");
 41  0
         CourseInfo courseInfo = getCourseService().getCourse(getCourseId(proposalInfo));
 42  0
         updateCourse(actionTakenEvent, DtoConstants.STATE_SUBMITTED, courseInfo);
 43  0
     }
 44  
 
 45  
     @Override
 46  
     protected boolean processCustomActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken, ProposalInfo proposalInfo) throws Exception {
 47  0
         String cluId = getCourseId(proposalInfo);
 48  0
         CourseInfo courseInfo = getCourseService().getCourse(cluId);
 49  0
         updateCourse(actionTakenEvent, null, courseInfo);
 50  0
         return true;
 51  
     }
 52  
 
 53  
     @Override
 54  
     protected boolean processCustomRouteStatusChange(DocumentRouteStatusChange statusChangeEvent, ProposalInfo proposalInfo) throws Exception {
 55  
         // update the course state if the cluState value is not null (allows for clearing of the state)
 56  0
         String courseId = getCourseId(proposalInfo);
 57  0
         CourseInfo courseInfo = getCourseService().getCourse(courseId);
 58  0
         String courseState = getCluStateForRouteStatus(courseInfo.getState(), statusChangeEvent.getNewRouteStatus());
 59  0
         updateCourse(statusChangeEvent, courseState, courseInfo);
 60  0
         return true;
 61  
     }
 62  
 
 63  
     protected String getCourseId(ProposalInfo proposalInfo) throws OperationFailedException {
 64  0
         if (proposalInfo.getProposalReference().size() != 1) {
 65  0
             LOG.error("Found " + proposalInfo.getProposalReference().size() + " CLU objects linked to proposal with proposalId='" + proposalInfo.getId() + "'. Must have exactly 1 linked.");
 66  0
             throw new OperationFailedException("Found " + proposalInfo.getProposalReference().size() + " CLU objects linked to proposal with docId='" + proposalInfo.getWorkflowId() + "' and proposalId='" + proposalInfo.getId() + "'. Must have exactly 1 linked.");
 67  
         }
 68  0
         return proposalInfo.getProposalReference().get(0);
 69  
     }
 70  
 
 71  
     /**
 72  
      * @param currentCluState - the current state set on the CLU
 73  
      * @param newWorkflowStatusCode - the new route status code that is getting set on the workflow document
 74  
      * @return the CLU state to set or null if the CLU does not need it's state changed
 75  
      */
 76  
     protected String getCluStateForRouteStatus(String currentCluState, String newWorkflowStatusCode) {
 77  0
         if (StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, newWorkflowStatusCode)) {
 78  0
             return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_DRAFT);
 79  0
         } else if (KEWConstants.ROUTE_HEADER_CANCEL_CD .equals(newWorkflowStatusCode)) {
 80  0
             return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_DRAFT);
 81  0
         } else if (KEWConstants.ROUTE_HEADER_ENROUTE_CD.equals(newWorkflowStatusCode)) {
 82  0
             return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_SUBMITTED);
 83  0
         } else if (KEWConstants.ROUTE_HEADER_DISAPPROVED_CD.equals(newWorkflowStatusCode)) {
 84  
             /* current requirements state that on a Withdraw (which is a KEW Disapproval) the 
 85  
              * CLU state should be submitted so no special handling required here
 86  
              */
 87  0
             return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_SUBMITTED);
 88  0
         } else if (KEWConstants.ROUTE_HEADER_PROCESSED_CD.equals(newWorkflowStatusCode)) {
 89  0
             return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_APPROVED);
 90  0
         } else if (KEWConstants.ROUTE_HEADER_EXCEPTION_CD.equals(newWorkflowStatusCode)) {
 91  0
             return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_SUBMITTED);
 92  
         } else {
 93  
             // no status to set
 94  0
             return null;
 95  
         }
 96  
     }
 97  
 
 98  
     /**
 99  
      * Default behavior is to return the <code>newCluState</code> variable only if it differs from the
 100  
      * <code>currentCluState</code> value. Otherwise <code>null</code> will be returned.
 101  
      */
 102  
     protected String getCourseStateFromNewState(String currentCourseState, String newCourseState) {
 103  0
         if (LOG.isInfoEnabled()) {
 104  0
             LOG.info("current CLU state is '" + currentCourseState + "' and new CLU state will be '" + newCourseState + "'");
 105  
         }
 106  0
         return getStateFromNewState(currentCourseState, newCourseState);
 107  
     }
 108  
 
 109  
     @Transactional(readOnly=false)
 110  
     protected void updateCourse(IDocumentEvent iDocumentEvent, String courseState, CourseInfo courseInfo) throws Exception {
 111  
         // only change the state if the course is not currently set to that state
 112  0
         boolean requiresSave = false;
 113  0
         if (courseState != null) {
 114  0
             if (LOG.isInfoEnabled()) {
 115  0
                 LOG.info("Setting state '" + courseState + "' on CLU with cluId='" + courseInfo.getId() + "'");
 116  
             }
 117  0
             courseInfo.setState(courseState);
 118  0
             requiresSave = true;
 119  
         }
 120  0
         if (LOG.isInfoEnabled()) {
 121  0
             LOG.info("Running preProcessCluSave with cluId='" + courseInfo.getId() + "'");
 122  
         }
 123  0
         requiresSave |= preProcessCourseSave(iDocumentEvent, courseInfo);
 124  
 
 125  0
         if (requiresSave) {
 126  0
             getCourseService().updateCourse(courseInfo);
 127  
             
 128  
             //For a newly approved course (w/no prior active versions), make the new course the current version.
 129  0
             if (DtoConstants.STATE_APPROVED.equals(courseState) && courseInfo.getVersionInfo().getCurrentVersionStart() == null){
 130  
                     // TODO: set states of other approved courses to superseded                
 131  
                 
 132  
                     // if current version's state is not active then we can set this course as the active course
 133  0
                     if (!DtoConstants.STATE_ACTIVE.equals(getCourseService().getCourse(getCourseService().getCurrentVersion(CourseServiceConstants.COURSE_NAMESPACE_URI, courseInfo.getVersionInfo().getVersionIndId()).getId()).getState())) { 
 134  0
                             getCourseService().setCurrentCourseVersion(courseInfo.getId(), null);
 135  
                     }
 136  
             }
 137  
             
 138  0
             List<StatementTreeViewInfo> statementTreeViewInfos = courseService.getCourseStatements(courseInfo.getId(), null, null);
 139  
             
 140  0
             statementTreeViewInfoStateSetter(courseInfo.getState(), statementTreeViewInfos.iterator());
 141  
             
 142  0
             for(Iterator<StatementTreeViewInfo> it = statementTreeViewInfos.iterator(); it.hasNext();)
 143  0
                         courseService.updateCourseStatement(courseInfo.getId(), it.next());
 144  
         }
 145  
         
 146  0
     }
 147  
 
 148  
     protected boolean preProcessCourseSave(IDocumentEvent iDocumentEvent, CourseInfo courseInfo) {
 149  0
         return false;
 150  
     }
 151  
 
 152  
     protected CourseService getCourseService() {
 153  0
         if (this.courseService == null) {
 154  0
             this.courseService = (CourseService) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/course","CourseService")); 
 155  
         }
 156  0
         return this.courseService;
 157  
     }
 158  
     
 159  
     /*
 160  
      * Recursively set state for StatementTreeViewInfo
 161  
      * TODO: We are not able to reuse the code in CourseStateUtil for dependency reason.
 162  
      */   
 163  
     public void statementTreeViewInfoStateSetter(String courseState, Iterator<StatementTreeViewInfo> itr) {
 164  0
             while(itr.hasNext()) {
 165  0
                 StatementTreeViewInfo statementTreeViewInfo = (StatementTreeViewInfo)itr.next();
 166  0
                 statementTreeViewInfo.setState(courseState);
 167  0
                 List<ReqComponentInfo> reqComponents = statementTreeViewInfo.getReqComponents();
 168  0
                 for(Iterator<ReqComponentInfo> it = reqComponents.iterator(); it.hasNext();)
 169  0
                         it.next().setState(courseState);
 170  
 
 171  0
                 statementTreeViewInfoStateSetter(courseState, statementTreeViewInfo.getStatements().iterator());
 172  0
         }
 173  0
     }  
 174  
     
 175  
 
 176  
 }