001 /** 002 * Copyright 2005-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.kew.actions; 017 018 import org.apache.log4j.MDC; 019 import org.kuali.rice.kew.actionrequest.ActionRequestValue; 020 import org.kuali.rice.kew.actionrequest.Recipient; 021 import org.kuali.rice.kew.actiontaken.ActionTakenValue; 022 import org.kuali.rice.kew.api.exception.InvalidActionTakenException; 023 import org.kuali.rice.kew.doctype.DocumentTypePolicy; 024 import org.kuali.rice.kew.api.exception.ResourceUnavailableException; 025 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 026 import org.kuali.rice.kew.api.KewApiConstants; 027 import org.kuali.rice.kim.api.identity.principal.PrincipalContract; 028 029 030 import java.util.Iterator; 031 import java.util.List; 032 033 /** 034 * <p> 035 * AcknowledegeAction records the users acknowledgement of a document 036 * </p> 037 * The routeheader is first checked to make sure the action is valid for the document. 038 * Next the user is checked to make sure he/she has not taken a previous action on this 039 * document at the actions responsibility or below. The action is recorded. Any requests 040 * related to this user are deactivated. 041 * </p> 042 * 043 * @author Kuali Rice Team (rice.collab@kuali.org) 044 */ 045 public class AcknowledgeAction extends ActionTakenEvent { 046 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AcknowledgeAction.class); 047 048 /** 049 * @param rh 050 * RouteHeader for the document upon which the action is taken. 051 * @param principal 052 * User taking the action. 053 */ 054 public AcknowledgeAction(DocumentRouteHeaderValue rh, PrincipalContract principal) { 055 super(KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD, rh, principal); 056 } 057 058 /** 059 * @param rh 060 * RouteHeader for the document upon which the action is taken. 061 * @param principal 062 * User taking the action. 063 * @param annotation 064 * User comment on the action taken 065 */ 066 public AcknowledgeAction(DocumentRouteHeaderValue rh, PrincipalContract principal, String annotation) { 067 super(KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD, rh, principal, annotation); 068 } 069 070 /** 071 * Method to check if the Action is currently valid on the given document 072 * @return returns an error message to give system better identifier for problem 073 */ 074 public String validateActionRules() { 075 return validateActionRules(getActionRequestService().findAllPendingRequests(routeHeader.getDocumentId())); 076 } 077 078 public String validateActionRules(List<ActionRequestValue> actionRequests) { 079 if (!getRouteHeader().isValidActionToTake(getActionPerformedCode())) { 080 return "Document is not in a state to be acknowledged"; 081 } 082 List<ActionRequestValue> filteredActionRequests = filterActionRequestsByCode(actionRequests, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ); 083 if (!isActionCompatibleRequest(filteredActionRequests)) { 084 return "No request for the user is compatible " + "with the ACKNOWLEDGE action"; 085 } 086 return ""; 087 } 088 089 /* (non-Javadoc) 090 * @see org.kuali.rice.kew.actions.ActionTakenEvent#isActionCompatibleRequest(java.util.List, java.lang.String) 091 */ 092 @Override 093 public boolean isActionCompatibleRequest(List requests) { 094 095 // we allow pre-approval 096 if (requests.isEmpty()) { 097 return true; 098 } 099 100 // can always cancel saved or initiated document 101 if (routeHeader.isStateInitiated() || routeHeader.isStateSaved()) { 102 return true; 103 } 104 105 boolean actionCompatible = false; 106 Iterator ars = requests.iterator(); 107 ActionRequestValue actionRequest = null; 108 109 while (ars.hasNext()) { 110 actionRequest = (ActionRequestValue) ars.next(); 111 String request = actionRequest.getActionRequested(); 112 113 // Acknowledge Taken Code matches Fyi and Ack 114 if ( (KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(request)) || (KewApiConstants.ACTION_REQUEST_FYI_REQ.equals(request)) ) { 115 actionCompatible = true; 116 break; 117 } 118 } 119 120 return actionCompatible; 121 } 122 123 /** 124 * Records the Acknowldege action. - Checks to make sure the document status allows the action. - Checks that the user has not taken a previous action. - Deactivates the pending requests for this user - Records the action 125 * 126 * @throws InvalidActionTakenException 127 * @throws ResourceUnavailableException 128 */ 129 public void recordAction() throws InvalidActionTakenException { 130 MDC.put("docId", getRouteHeader().getDocumentId()); 131 updateSearchableAttributesIfPossible(); 132 133 LOG.debug("Acknowledging document : " + annotation); 134 135 LOG.debug("Checking to see if the action is legal"); 136 List actionRequests = getActionRequestService().findAllValidRequests(getPrincipal().getPrincipalId(), routeHeader.getDocumentId(), KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ); 137 if (actionRequests == null || actionRequests.isEmpty()) { 138 DocumentTypePolicy allowUnrequested = getRouteHeader().getDocumentType().getAllowUnrequestedActionPolicy(); 139 if (allowUnrequested != null) { 140 if (!allowUnrequested.getPolicyValue()) { 141 throw new InvalidActionTakenException("No request for the user is compatible " + "with the ACKNOWLEDGE action. " + "Doctype policy ALLOW_UNREQUESTED_ACTION is set to false and someone else likely just took action on the document."); 142 } 143 } 144 } 145 146 String errorMessage = validateActionRules(actionRequests); 147 if (!org.apache.commons.lang.StringUtils.isEmpty(errorMessage)) { 148 throw new InvalidActionTakenException(errorMessage); 149 } 150 151 LOG.debug("Record the acknowledge action"); 152 Recipient delegator = findDelegatorForActionRequests(actionRequests); 153 ActionTakenValue actionTaken = saveActionTaken(delegator); 154 LOG.debug("Deactivate all pending action requests"); 155 getActionRequestService().deactivateRequests(actionTaken, actionRequests); 156 notifyActionTaken(actionTaken); 157 } 158 }