Coverage Report - org.kuali.student.lum.workflow.KualiStudentPostProcessorBase
 
Classes in this File Line Coverage Branch Coverage Complexity
KualiStudentPostProcessorBase
0%
0/113
0%
0/64
2.75
 
 1  
 /**
 2  
  * Copyright 2010 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  
 
 16  
 package org.kuali.student.lum.workflow;
 17  
 import java.util.List;
 18  
 
 19  
 import javax.xml.namespace.QName;
 20  
 
 21  
 import org.apache.commons.lang.StringUtils;
 22  
 import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
 23  
 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
 24  
 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
 25  
 import org.kuali.rice.kew.dto.ActionRequestDTO;
 26  
 import org.kuali.rice.kew.postprocessor.ActionTakenEvent;
 27  
 import org.kuali.rice.kew.postprocessor.AfterProcessEvent;
 28  
 import org.kuali.rice.kew.postprocessor.BeforeProcessEvent;
 29  
 import org.kuali.rice.kew.postprocessor.DeleteEvent;
 30  
 import org.kuali.rice.kew.postprocessor.DocumentLockingEvent;
 31  
 import org.kuali.rice.kew.postprocessor.DocumentRouteLevelChange;
 32  
 import org.kuali.rice.kew.postprocessor.DocumentRouteStatusChange;
 33  
 import org.kuali.rice.kew.postprocessor.IDocumentEvent;
 34  
 import org.kuali.rice.kew.postprocessor.PostProcessor;
 35  
 import org.kuali.rice.kew.postprocessor.ProcessDocReport;
 36  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 37  
 import org.kuali.rice.kew.service.WorkflowDocument;
 38  
 import org.kuali.rice.kew.util.KEWConstants;
 39  
 import org.kuali.rice.kim.bo.entity.dto.KimPrincipalInfo;
 40  
 import org.kuali.rice.kim.bo.types.dto.AttributeSet;
 41  
 import org.kuali.rice.kim.service.KIMServiceLocator;
 42  
 import org.kuali.rice.student.StudentWorkflowConstants;
 43  
 import org.kuali.rice.student.bo.KualiStudentKimAttributes;
 44  
 import org.kuali.student.common.exceptions.OperationFailedException;
 45  
 import org.kuali.student.common.rice.StudentIdentityConstants;
 46  
 import org.kuali.student.core.proposal.ProposalConstants;
 47  
 import org.kuali.student.core.proposal.dto.ProposalInfo;
 48  
 import org.kuali.student.core.proposal.service.ProposalService;
 49  0
 public class KualiStudentPostProcessorBase implements PostProcessor{
 50  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiStudentPostProcessorBase.class);
 51  
 
 52  
     private ProposalService proposalService;
 53  
 
 54  
     public ProcessDocReport afterProcess(AfterProcessEvent arg0) throws Exception {
 55  0
         return new ProcessDocReport(true);
 56  
         }
 57  
 
 58  
         public ProcessDocReport beforeProcess(BeforeProcessEvent arg0) throws Exception {
 59  0
         return new ProcessDocReport(true);
 60  
         }
 61  
 
 62  
         public ProcessDocReport doActionTaken(ActionTakenEvent actionTakenEvent) throws Exception {
 63  0
                 ActionTakenValue actionTaken = KEWServiceLocator.getActionTakenService().findByActionTakenId(actionTakenEvent.getActionTaken().getActionTakenId());
 64  0
                 if (actionTaken == null) {
 65  0
                     if (LOG.isInfoEnabled()) {
 66  0
                         LOG.info("Could not find valid ActionTakenValue for doc id '" + actionTakenEvent.getRouteHeaderId() + "'" + 
 67  
                                 ((actionTakenEvent.getActionTaken() == null) ? "" : " for action: " + actionTakenEvent.getActionTaken().getActionTakenLabel()));
 68  
                     }
 69  0
                     actionTaken = actionTakenEvent.getActionTaken();
 70  
                 }
 71  0
                 boolean success = true;
 72  
                 // on a save action we may not have access to the proposal object because the transaction may not have committed
 73  0
                 if (!StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, actionTaken.getActionTaken())) {
 74  0
             ProposalInfo proposalInfo = getProposalService().getProposalByWorkflowId(actionTakenEvent.getRouteHeaderId().toString());
 75  0
             if (actionTaken == null) {
 76  0
                 throw new OperationFailedException("No action taken found for document id " + actionTakenEvent.getRouteHeaderId());
 77  
             }
 78  0
                 if (StringUtils.equals(KEWConstants.ACTION_TAKEN_SU_DISAPPROVED_CD, actionTaken.getActionTaken())) {
 79  
                     // the custom method below is needed for the unique problem of the states being set for a Withdraw action in KS
 80  0
                     processSuperUserDisapproveActionTaken(actionTakenEvent, actionTaken, proposalInfo);
 81  
                 }
 82  
             // only attempt to remove the adhoc permission if the action taken was not an adhoc revocation 
 83  0
                 else if (!StringUtils.equals(KEWConstants.ACTION_TAKEN_ADHOC_REVOKED_CD, actionTaken.getActionTaken())) {
 84  0
                             for (ActionRequestValue actionRequest : actionTaken.getActionRequests()) {
 85  0
                             if (actionRequest.isAdHocRequest() && actionRequest.isUserRequest()) {
 86  0
                                 processActionTakenOnAdhocRequest(actionTakenEvent, actionRequest);
 87  
                             }
 88  
                     }
 89  
             }
 90  0
             success = processCustomActionTaken(actionTakenEvent, actionTaken, proposalInfo);
 91  0
                 } else {
 92  0
                     success = processCustomSaveActionTaken(actionTakenEvent, actionTaken);
 93  
                 }
 94  0
         return new ProcessDocReport(success);
 95  
         }
 96  
 
 97  
     protected boolean processCustomActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken, ProposalInfo proposalInfo) throws Exception {
 98  
         // do nothing
 99  0
         return true;
 100  
     }
 101  
 
 102  
     protected boolean processCustomSaveActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken) throws Exception {
 103  
         // do nothing
 104  0
         return true;
 105  
     }
 106  
 
 107  
     protected void processActionTakenOnAdhocRequest(ActionTakenEvent actionTakenEvent, ActionRequestValue actionRequestValue) throws Exception {
 108  0
         WorkflowDocument doc = new WorkflowDocument(getPrincipalIdForSystemUser(), actionTakenEvent.getRouteHeaderId());
 109  0
         LOG.info("Clearing EDIT permissions added via adhoc requests to principal id: " + actionRequestValue.getPrincipalId());
 110  0
         removeEditAdhocPermissions(actionRequestValue.getPrincipalId(), doc);
 111  0
     }
 112  
 
 113  
     protected void processSuperUserDisapproveActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken, ProposalInfo proposalInfo) throws Exception {
 114  0
         LOG.info("Action taken was 'Super User Disapprove' which is a 'Withdraw' in Kuali Student");
 115  0
         LOG.info("Will set proposal state to '" + ProposalConstants.PROPOSAL_STATE_WITHDRAWN + "'");
 116  0
         updateProposal(actionTakenEvent, ProposalConstants.PROPOSAL_STATE_WITHDRAWN, proposalInfo);
 117  0
         processWithdrawActionTaken(actionTakenEvent, proposalInfo);
 118  0
         }
 119  
 
 120  
     protected void processWithdrawActionTaken(ActionTakenEvent actionTakenEvent, ProposalInfo proposalInfo) throws Exception {
 121  
         // do nothing but allow for child classes to override
 122  0
     }
 123  
 
 124  
     public ProcessDocReport doDeleteRouteHeader(DeleteEvent arg0) throws Exception {
 125  0
         return new ProcessDocReport(true);
 126  
         }
 127  
 
 128  
         public ProcessDocReport doRouteLevelChange(DocumentRouteLevelChange documentRouteLevelChange) throws Exception {
 129  0
         ProposalInfo proposalInfo = getProposalService().getProposalByWorkflowId(documentRouteLevelChange.getRouteHeaderId().toString());
 130  
 
 131  
                 // if this is the initial route then clear only edit permissions as per KSLUM-192
 132  0
                 if (StringUtils.equals(StudentWorkflowConstants.DEFAULT_WORKFLOW_DOCUMENT_START_NODE_NAME,documentRouteLevelChange.getOldNodeName())) {
 133  
                         // remove edit perm for all adhoc action requests to a user for the route node we just exited
 134  0
                 WorkflowDocument doc = new WorkflowDocument(getPrincipalIdForSystemUser(), documentRouteLevelChange.getRouteHeaderId());
 135  0
                         for (ActionRequestDTO actionRequestDTO : doc.getActionRequests()) {
 136  0
                                 if (actionRequestDTO.isAdHocRequest() && actionRequestDTO.isUserRequest() && 
 137  
                                                 StringUtils.equals(documentRouteLevelChange.getOldNodeName(),actionRequestDTO.getNodeName())) {
 138  0
                                         LOG.info("Clearing EDIT permissions added via adhoc requests to principal id: " + actionRequestDTO.getPrincipalId());
 139  0
                                         removeEditAdhocPermissions(actionRequestDTO.getPrincipalId(), doc);
 140  
                                 }
 141  
                 }
 142  0
                 }
 143  
                 else {
 144  0
                         LOG.warn("Will not clear any permissions added via adhoc requests");
 145  
                 }
 146  0
                 boolean success = processCustomRouteLevelChange(documentRouteLevelChange, proposalInfo);
 147  0
                 return new ProcessDocReport(success);
 148  
         }
 149  
 
 150  
         protected boolean processCustomRouteLevelChange(
 151  
                         DocumentRouteLevelChange documentRouteLevelChange,
 152  
                         ProposalInfo proposalInfo) throws Exception {
 153  
                 //Update the proposal with the new node name
 154  0
                 proposalInfo.getAttributes().put("workflowNode", documentRouteLevelChange.getNewNodeName());
 155  0
                 getProposalService().updateProposal(proposalInfo.getId(), proposalInfo);
 156  0
                 return true;
 157  
         }
 158  
 
 159  
         public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
 160  0
             boolean success = true;
 161  
             // if document is transitioning from INITIATED to SAVED then transaction prevents us from retrieving the proposal
 162  0
             if (StringUtils.equals(KEWConstants.ROUTE_HEADER_INITIATED_CD, statusChangeEvent.getOldRouteStatus()) && 
 163  
                     StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, statusChangeEvent.getNewRouteStatus())) {
 164  
                 // assume the proposal status is already correct
 165  0
             success = processCustomRouteStatusSavedStatusChange(statusChangeEvent);
 166  
             } else {
 167  0
             ProposalInfo proposalInfo = getProposalService().getProposalByWorkflowId(statusChangeEvent.getRouteHeaderId().toString());
 168  
             
 169  
             // update the proposal state if the proposalState value is not null (allows for clearing of the state)
 170  0
             String proposalState = getProposalStateForRouteStatus(proposalInfo.getState(), statusChangeEvent.getNewRouteStatus());
 171  0
             updateProposal(statusChangeEvent, proposalState, proposalInfo);
 172  0
             success = processCustomRouteStatusChange(statusChangeEvent, proposalInfo);
 173  
             }
 174  0
         return new ProcessDocReport(success);
 175  
         }
 176  
 
 177  
         protected boolean processCustomRouteStatusChange(DocumentRouteStatusChange statusChangeEvent, ProposalInfo proposalInfo) throws Exception {
 178  
             // do nothing but allow override
 179  0
             return true;
 180  
         }
 181  
 
 182  
     protected boolean processCustomRouteStatusSavedStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
 183  
         // do nothing but allow override
 184  0
         return true;
 185  
     }
 186  
 
 187  
         public List<Long> getDocumentIdsToLock(DocumentLockingEvent arg0) throws Exception {
 188  0
                 return null;
 189  
         }
 190  
 
 191  
     /**
 192  
      * @param currentProposalState - the current state set on the proposal
 193  
      * @param newWorkflowStatusCode - the new route status code that is getting set on the workflow document
 194  
      * @return the proposal state to set or null if the proposal does not need it's state changed
 195  
      */
 196  
     protected String getProposalStateForRouteStatus(String currentProposalState, String newWorkflowStatusCode) {
 197  0
         if (StringUtils.equals(ProposalConstants.PROPOSAL_STATE_WITHDRAWN, currentProposalState)) {
 198  
             // if the current proposal state is Withdrawn... don't change the proposal state
 199  0
             return null;
 200  
         }
 201  0
         if (StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, newWorkflowStatusCode)) {
 202  0
             return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_SAVED);
 203  0
         } else if (KEWConstants.ROUTE_HEADER_ENROUTE_CD.equals(newWorkflowStatusCode)) {
 204  0
             return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_ENROUTE);
 205  0
         } else if (KEWConstants.ROUTE_HEADER_CANCEL_CD .equals(newWorkflowStatusCode)) {
 206  0
             return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_CANCELLED);
 207  0
         } else if (KEWConstants.ROUTE_HEADER_DISAPPROVED_CD.equals(newWorkflowStatusCode)) {
 208  0
             return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_REJECTED);
 209  0
         } else if (KEWConstants.ROUTE_HEADER_PROCESSED_CD.equals(newWorkflowStatusCode)) {
 210  0
             return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_APPROVED);
 211  0
         } else if (KEWConstants.ROUTE_HEADER_EXCEPTION_CD.equals(newWorkflowStatusCode)) {
 212  0
             return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_EXCEPTION);
 213  
         } else {
 214  
             // no status to set
 215  0
             return null;
 216  
         }
 217  
     }
 218  
 
 219  
     /**
 220  
      * Default behavior is to return the <code>newProposalState</code> variable only if it differs from the
 221  
      * <code>currentProposalState</code> value. Otherwise <code>null</code> will be returned.
 222  
      */
 223  
     protected String getProposalStateFromNewState(String currentProposalState, String newProposalState) {
 224  0
         if (LOG.isInfoEnabled()) {
 225  0
             LOG.info("current proposal state is '" + currentProposalState + "' and new proposal state will be '" + newProposalState + "'");
 226  
         }
 227  0
         return getStateFromNewState(currentProposalState, newProposalState);
 228  
     }
 229  
 
 230  
     /**
 231  
      * Default behavior is to return the <code>newState</code> variable only if it differs from the
 232  
      * <code>currentState</code> value. Otherwise <code>null</code> will be returned.
 233  
      */
 234  
     protected String getStateFromNewState(String currentState, String newState) {
 235  0
         if (StringUtils.equals(currentState, newState)) {
 236  0
             if (LOG.isInfoEnabled()) {
 237  0
                 LOG.info("returning null as current state and new state are both '" + currentState + "'");
 238  
             }
 239  0
             return null;
 240  
         }
 241  0
         return newState;
 242  
     }
 243  
 
 244  
     protected void removeEditAdhocPermissions(String principalId, WorkflowDocument doc) {
 245  0
         AttributeSet qualifications = new AttributeSet();
 246  0
         qualifications.put(KualiStudentKimAttributes.DOCUMENT_TYPE_NAME,doc.getDocumentType());
 247  0
         qualifications.put(KualiStudentKimAttributes.QUALIFICATION_DATA_ID,doc.getAppDocId());
 248  0
         KIMServiceLocator.getRoleManagementService().removePrincipalFromRole(principalId, StudentWorkflowConstants.ROLE_NAME_ADHOC_EDIT_PERMISSIONS_ROLE_NAMESPACE, StudentWorkflowConstants.ROLE_NAME_ADHOC_EDIT_PERMISSIONS_ROLE_NAME, qualifications);       
 249  0
     }
 250  
 
 251  
     protected void removeCommentAdhocPermissions(String roleNamespace, String roleName, String principalId, WorkflowDocument doc) {
 252  0
         AttributeSet qualifications = new AttributeSet();
 253  0
         qualifications.put(KualiStudentKimAttributes.DOCUMENT_TYPE_NAME,doc.getDocumentType());
 254  0
         qualifications.put(KualiStudentKimAttributes.QUALIFICATION_DATA_ID,doc.getAppDocId());
 255  0
         KIMServiceLocator.getRoleManagementService().removePrincipalFromRole(principalId, StudentWorkflowConstants.ROLE_NAME_ADHOC_ADD_COMMENT_PERMISSIONS_ROLE_NAMESPACE, StudentWorkflowConstants.ROLE_NAME_ADHOC_ADD_COMMENT_PERMISSIONS_ROLE_NAME, qualifications);
 256  0
     }
 257  
 
 258  
     protected String getPrincipalIdForSystemUser() {
 259  0
         KimPrincipalInfo principal = KIMServiceLocator.getIdentityManagementService().getPrincipalByPrincipalName(StudentIdentityConstants.SYSTEM_USER_PRINCIPAL_NAME);
 260  0
         if (principal == null) {
 261  0
             throw new RuntimeException("Cannot find Principal for principal name: " + StudentIdentityConstants.SYSTEM_USER_PRINCIPAL_NAME);
 262  
         }
 263  0
         return principal.getPrincipalId();
 264  
     }
 265  
 
 266  
     protected void updateProposal(IDocumentEvent iDocumentEvent, String proposalState, ProposalInfo proposalInfo) throws Exception {
 267  0
         if (LOG.isInfoEnabled()) {
 268  0
             LOG.info("Setting state '" + proposalState + "' on Proposal with docId='" + proposalInfo.getWorkflowId() + "' and proposalId='" + proposalInfo.getId() + "'");
 269  
         }
 270  0
         boolean requiresSave = false;
 271  0
         if (proposalState != null) {
 272  0
             proposalInfo.setState(proposalState);
 273  0
             requiresSave = true;
 274  
         }
 275  0
         requiresSave |= preProcessProposalSave(iDocumentEvent, proposalInfo);
 276  0
         if (requiresSave) {
 277  0
             getProposalService().updateProposal(proposalInfo.getId(), proposalInfo);
 278  
         }
 279  0
     }
 280  
 
 281  
     protected boolean preProcessProposalSave(IDocumentEvent iDocumentEvent, ProposalInfo proposalInfo) {
 282  0
         return false;
 283  
     }
 284  
 
 285  
     protected ProposalService getProposalService() {
 286  0
         if (this.proposalService == null) {
 287  0
             this.proposalService = (ProposalService) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/proposal","ProposalService"));
 288  
         }
 289  0
         return this.proposalService;
 290  
     }
 291  
 
 292  
 }