View Javadoc

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