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