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