View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.actions;
17  
18  import org.apache.log4j.MDC;
19  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
20  import org.kuali.rice.kew.actiontaken.ActionTakenValue;
21  import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
22  import org.kuali.rice.kew.doctype.DocumentTypePolicy;
23  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
24  import org.kuali.rice.kew.service.KEWServiceLocator;
25  import org.kuali.rice.kew.api.KewApiConstants;
26  import org.kuali.rice.kim.api.identity.principal.PrincipalContract;
27  
28  
29  import java.util.Iterator;
30  import java.util.List;
31  
32  
33  /**
34   * CompleteAction records and process a complete action
35   *
36   * The routeheader is first checked to make sure the action is valid for the document.
37   * Next the user is checked to make sure he/she has not taken a previous action on this
38   * document at the actions responsibility or below. The action is recorded. Any requests
39   * related to this user are deactivated.
40   *
41   * @author Kuali Rice Team (rice.collab@kuali.org)
42   */
43  public class CompleteAction extends ActionTakenEvent {
44      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CompleteAction.class);
45  
46      /**
47       * @param rh
48       *            RouteHeader for the document upon which the action is taken.
49       * @param principal
50       *            User taking the action.
51       */
52      public CompleteAction(DocumentRouteHeaderValue rh, PrincipalContract principal) {
53          super(KewApiConstants.ACTION_TAKEN_COMPLETED_CD, rh, principal);
54      }
55  
56      /**
57       * @param rh
58       *            RouteHeader for the document upon which the action is taken.
59       * @param principal
60       *            User taking the action.
61       * @param annotation
62       *            User comment on the action taken
63       */
64      public CompleteAction(DocumentRouteHeaderValue rh, PrincipalContract principal, String annotation) {
65          super(KewApiConstants.ACTION_TAKEN_COMPLETED_CD, rh, principal, annotation);
66      }
67  
68      /* (non-Javadoc)
69       * @see org.kuali.rice.kew.actions.ActionTakenEvent#isActionCompatibleRequest(java.util.List)
70       */
71      @Override
72      public String validateActionRules() {
73          return validateActionRules(getActionRequestService().findAllPendingRequests(routeHeader.getDocumentId()));
74      }
75  
76      public String validateActionRules(List<ActionRequestValue> actionRequests) {
77          if (!getRouteHeader().isValidActionToTake(getActionPerformedCode())) {
78              return "Document is not in a state to be completed";
79          }
80          List<ActionRequestValue> filteredActionRequests = filterActionRequestsByCode(actionRequests, KewApiConstants.ACTION_REQUEST_COMPLETE_REQ);
81          if (!isActionCompatibleRequest(filteredActionRequests)) {
82              return "No request for the user is compatible " + "with the COMPLETE action";
83          }
84          return "";
85      }
86  
87      /* (non-Javadoc)
88       * @see org.kuali.rice.kew.actions.ActionTakenEvent#isActionCompatibleRequest(java.util.List)
89       */
90      @Override
91      public boolean isActionCompatibleRequest(List requests) {
92          // we allow pre-approval
93          if (requests.isEmpty()) {
94              return true;
95          }
96  
97          // can always cancel saved or initiated document
98          if (routeHeader.isStateInitiated() || routeHeader.isStateSaved()) {
99              return true;
100         }
101 
102         boolean actionCompatible = false;
103         Iterator ars = requests.iterator();
104         ActionRequestValue actionRequest = null;
105 
106         while (ars.hasNext()) {
107             actionRequest = (ActionRequestValue) ars.next();
108             String request = actionRequest.getActionRequested();
109 
110             // Complete action matches Complete, Approve, FYI, and ACK requests
111             if ( (KewApiConstants.ACTION_REQUEST_FYI_REQ.equals(request)) ||
112                     (KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(request)) ||
113                     (KewApiConstants.ACTION_REQUEST_APPROVE_REQ.equals(request)) ||
114                     (KewApiConstants.ACTION_REQUEST_COMPLETE_REQ.equals(request)) ) {
115                 actionCompatible = true;
116                 break;
117             }
118         }
119         return actionCompatible;
120     }
121 
122     /**
123      * Records the complete 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
124      *
125      * @throws org.kuali.rice.kew.api.exception.InvalidActionTakenException
126      * @throws org.kuali.rice.kew.api.exception.ResourceUnavailableException
127      */
128     public void recordAction() throws InvalidActionTakenException {
129         MDC.put("docId", getRouteHeader().getDocumentId());
130         updateSearchableAttributesIfPossible();
131         LOG.debug("Completing document : " + annotation);
132 
133         List actionRequests = getActionRequestService().findAllValidRequests(getPrincipal().getPrincipalId(), getDocumentId(), KewApiConstants.ACTION_REQUEST_COMPLETE_REQ);
134         if (actionRequests == null || actionRequests.isEmpty()) {
135             DocumentTypePolicy allowUnrequested = getRouteHeader().getDocumentType().getAllowUnrequestedActionPolicy();
136             if (allowUnrequested != null) {
137             	if (!allowUnrequested.getPolicyValue()) {
138             		throw new InvalidActionTakenException("No request for the user is compatible " + "with the COMPLETE action. " + "Doctype policy ALLOW_UNREQUESTED_ACTION is set to false and someone else likely just took action on the document.");
139             	}
140             }
141         }
142         LOG.debug("Checking to see if the action is legal");
143         String errorMessage = validateActionRules(actionRequests);
144         if (!org.apache.commons.lang.StringUtils.isEmpty(errorMessage)) {
145             throw new InvalidActionTakenException(errorMessage);
146         }
147 
148         LOG.debug("Record the complete action");
149         ActionTakenValue actionTaken = saveActionTaken(findDelegatorForActionRequests(actionRequests));
150 
151         LOG.debug("Deactivate all pending action requests");
152         getActionRequestService().deactivateRequests(actionTaken, actionRequests);
153         notifyActionTaken(actionTaken);
154 
155         boolean isException = getRouteHeader().isInException();
156         boolean isSaved = getRouteHeader().isStateSaved();
157         if (isException || isSaved) {
158             String oldStatus = getRouteHeader().getDocRouteStatus();
159             LOG.debug("Moving document back to Enroute from "+KewApiConstants.DOCUMENT_STATUSES.get(oldStatus));
160             getRouteHeader().markDocumentEnroute();
161             String newStatus = getRouteHeader().getDocRouteStatus();
162             notifyStatusChange(newStatus, oldStatus);
163             DocumentRouteHeaderValue routeHeaderValue = KEWServiceLocator.getRouteHeaderService().
164                     saveRouteHeader(getRouteHeader());
165             setRouteHeader(routeHeaderValue);
166         }
167     }
168 
169 }