001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.actions;
018:
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Set;
023:
024: import javax.xml.namespace.QName;
025:
026: import org.apache.log4j.MDC;
027:
028: import edu.iu.uis.eden.EdenConstants;
029: import edu.iu.uis.eden.KEWServiceLocator;
030: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
031: import edu.iu.uis.eden.actiontaken.ActionTakenValue;
032: import edu.iu.uis.eden.doctype.DocumentType;
033: import edu.iu.uis.eden.engine.BlanketApproveEngine;
034: import edu.iu.uis.eden.engine.CompatUtils;
035: import edu.iu.uis.eden.engine.node.RouteNode;
036: import edu.iu.uis.eden.engine.node.RouteNodeService;
037: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
038: import edu.iu.uis.eden.exception.InvalidActionTakenException;
039: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
040: import edu.iu.uis.eden.messaging.KEWXMLService;
041: import edu.iu.uis.eden.messaging.MessageServiceNames;
042: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
043: import edu.iu.uis.eden.user.Recipient;
044: import edu.iu.uis.eden.user.WorkflowUser;
045: import edu.iu.uis.eden.util.Utilities;
046:
047: /**
048: * Does the sync work for blanket approves requested by client apps.
049: *
050: * @author ewestfal
051: * @author rkirkend
052: * @author seiffert
053: */
054: public class BlanketApproveAction extends ActionTakenEvent {
055:
056: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
057: .getLogger(BlanketApproveAction.class);
058: private Set nodeNames;
059:
060: public BlanketApproveAction(DocumentRouteHeaderValue rh,
061: WorkflowUser user) {
062: super (rh, user);
063: setActionTakenCode(EdenConstants.ACTION_TAKEN_BLANKET_APPROVE_CD);
064: }
065:
066: public BlanketApproveAction(DocumentRouteHeaderValue rh,
067: WorkflowUser user, String annotation, Integer routeLevel) {
068: this (rh, user, annotation, convertRouteLevel(rh
069: .getDocumentType(), routeLevel));
070: }
071:
072: public BlanketApproveAction(DocumentRouteHeaderValue rh,
073: WorkflowUser user, String annotation, String nodeName) {
074: this (rh, user, annotation, Utilities.asSet(nodeName));
075: }
076:
077: public BlanketApproveAction(DocumentRouteHeaderValue rh,
078: WorkflowUser user, String annotation, Set nodeNames) {
079: super (rh, user, annotation);
080: setActionTakenCode(EdenConstants.ACTION_TAKEN_BLANKET_APPROVE_CD);
081: this .nodeNames = (nodeNames == null ? new HashSet() : nodeNames);
082: }
083:
084: private static Set convertRouteLevel(DocumentType documentType,
085: Integer routeLevel) {
086: Set<String> nodeNames = new HashSet<String>();
087: if (routeLevel == null) {
088: return nodeNames;
089: }
090: RouteNode node = CompatUtils.getNodeForLevel(documentType,
091: routeLevel);
092: if (node == null) {
093: throw new WorkflowRuntimeException(
094: "Could not locate a valid node for the given route level: "
095: + routeLevel);
096: }
097: nodeNames.add(node.getRouteNodeName());
098: return nodeNames;
099: }
100:
101: @Override
102: protected boolean requireInitiatorCheck() {
103: return routeHeader.getDocumentType()
104: .getInitiatorMustBlanketApprovePolicy()
105: .getPolicyValue().booleanValue();
106: }
107:
108: /* (non-Javadoc)
109: * @see edu.iu.uis.eden.actions.ActionTakenEvent#validateActionRules()
110: */
111: @Override
112: public String validateActionRules()
113: throws EdenUserNotFoundException {
114: return validateActionRules(getActionRequestService()
115: .findAllValidRequests(getUser(),
116: routeHeader.getRouteHeaderId(),
117: EdenConstants.ACTION_REQUEST_COMPLETE_REQ));
118: }
119:
120: private String validateActionRules(List actionRequests)
121: throws EdenUserNotFoundException {
122: String super Error = super .validateActionTakenRules();
123: if (!Utilities.isEmpty(super Error)) {
124: return super Error;
125: }
126: if ((getRouteHeader().getDocumentType() != null)
127: && (!getRouteHeader().getDocumentType()
128: .isUserBlanketApprover(getUser()))) {
129: return "User is not authorized to BlanketApprove document";
130: }
131: if ((nodeNames != null) && (!nodeNames.isEmpty())) {
132: String nodeName = isGivenNodeListValid();
133: if (!Utilities.isEmpty(nodeName)) {
134: return "Document already at or beyond route node "
135: + nodeName;
136: }
137: }
138: if (!getRouteHeader().isValidActionToTake(
139: getActionPerformedCode())) {
140: return "Document is not in a state to be approved";
141: }
142: if (!isActionCompatibleRequest(actionRequests)) {
143: return "No request for the user is compatible with the BlanketApprove Action";
144: }
145: return "";
146: }
147:
148: private String isGivenNodeListValid() {
149: for (Iterator iterator = nodeNames.iterator(); iterator
150: .hasNext();) {
151: String nodeName = (String) iterator.next();
152: if (nodeName == null) {
153: iterator.remove();
154: continue;
155: }
156: if (!getRouteNodeService().isNodeInPath(getRouteHeader(),
157: nodeName)) {
158: return nodeName;
159: }
160: }
161: return "";
162: }
163:
164: public void recordAction() throws InvalidActionTakenException,
165: EdenUserNotFoundException {
166: MDC.put("docId", getRouteHeader().getRouteHeaderId());
167: checkLocking();
168: updateSearchableAttributesIfPossible();
169:
170: List actionRequests = getActionRequestService()
171: .findAllValidRequests(getUser(), getRouteHeaderId(),
172: EdenConstants.ACTION_REQUEST_COMPLETE_REQ);
173: String errorMessage = validateActionRules(actionRequests);
174: if (!Utilities.isEmpty(errorMessage)) {
175: throw new InvalidActionTakenException(errorMessage);
176: }
177:
178: // for (Iterator iterator = nodeNames.iterator(); iterator.hasNext();) {
179: // String nodeName = (String) iterator.next();
180: // if (nodeName == null) {
181: // iterator.remove();
182: // continue;
183: // }
184: // if (!getRouteNodeService().isNodeInPath(getRouteHeader(), nodeName)) {
185: // throw new InvalidActionTakenException("Document already at or beyond route node " + nodeName);
186: // }
187: // }
188: LOG.debug("Checking to see if the action is legal");
189:
190: // //find all current activated/initialized action requests
191: // if (! getRouteHeader().getDocumentType().getBlanketApproveWorkgroup().hasMember(getUser())) {
192: // throw new InvalidActionTakenException("User is not authorized to BlanketApprove document");
193: // } else if (getRouteHeader().isValidActionToTake(getActionTakenCode())) {
194:
195: LOG.debug("Blanket approving document : " + annotation);
196:
197: if (getRouteHeader().isStateInitiated()
198: || getRouteHeader().isStateSaved()) {
199: markDocumentEnroute(getRouteHeader());
200: }
201:
202: // List actionRequests = getActionRequestService().findAllValidRequests(getUser(), getRouteHeaderId(), EdenConstants.ACTION_REQUEST_COMPLETE_REQ);
203: // if (!isActionCompatibleRequest(actionRequests, getActionTakenCode())) {
204: // throw new InvalidActionTakenException("No request for the user is compatible with the BlanketApprove Action");
205: // }
206:
207: LOG.debug("Record the blanket approval action");
208: Recipient delegator = findDelegatorForActionRequests(actionRequests);
209: saveActionTaken(delegator);
210:
211: LOG.debug("Deactivate pending action requests for user");
212: getActionRequestService().deactivateRequests(actionTaken,
213: actionRequests);
214: notifyActionTaken(this .actionTaken);
215:
216: getRouteHeaderService().saveRouteHeader(getRouteHeader());
217:
218: // } else {
219: // LOG.warn("Document not in state to be approved.");
220: // throw new InvalidActionTakenException("Document is not in a state to be approved");
221: // }
222: }
223:
224: public void doBlanketApproveWork() throws Exception {
225:
226: if (getRouteHeader().isInException()) {
227: LOG.debug("Moving document back to Enroute from Exception");
228:
229: String oldStatus = getRouteHeader().getDocRouteStatus();
230: getRouteHeader().markDocumentEnroute();
231:
232: String newStatus = getRouteHeader().getDocRouteStatus();
233: notifyStatusChange(newStatus, oldStatus);
234: }
235: new BlanketApproveEngine(nodeNames, actionTaken).process(
236: getRouteHeader().getRouteHeaderId(), null);
237: }
238:
239: protected void markDocumentEnroute(
240: DocumentRouteHeaderValue routeHeader)
241: throws InvalidActionTakenException {
242: String oldStatus = getRouteHeader().getDocRouteStatus();
243: getRouteHeader().markDocumentEnroute();
244:
245: String newStatus = getRouteHeader().getDocRouteStatus();
246: notifyStatusChange(newStatus, oldStatus);
247: getRouteHeaderService().saveRouteHeader(getRouteHeader());
248: }
249:
250: public void queueDocument() {
251: QName documentServiceName = new QName(getRouteHeader()
252: .getDocumentType().getMessageEntity(),
253: MessageServiceNames.DOCUMENT_ROUTING_SERVICE);
254: KEWXMLService documentRoutingService = (KEWXMLService) MessageServiceNames
255: .getServiceAsynchronously(documentServiceName,
256: getRouteHeader());
257: try {
258: documentRoutingService.invoke(String
259: .valueOf(getRouteHeaderId()));
260: } catch (Exception e) {
261: throw new WorkflowRuntimeException(e);
262: }
263:
264: }
265:
266: public void setActionTaken(ActionTakenValue actionTaken) {
267: this .actionTaken = actionTaken;
268: }
269:
270: private RouteNodeService getRouteNodeService() {
271: return KEWServiceLocator.getRouteNodeService();
272: }
273: }
|