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.Collection;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Set;
024:
025: import org.apache.log4j.MDC;
026:
027: import edu.iu.uis.eden.EdenConstants;
028: import edu.iu.uis.eden.KEWServiceLocator;
029: import edu.iu.uis.eden.actions.asyncservices.MoveDocumentService;
030: import edu.iu.uis.eden.actiontaken.ActionTakenValue;
031: import edu.iu.uis.eden.engine.BlanketApproveEngine;
032: import edu.iu.uis.eden.engine.OrchestrationConfig;
033: import edu.iu.uis.eden.engine.node.RouteNode;
034: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
035: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
036: import edu.iu.uis.eden.exception.InvalidActionTakenException;
037: import edu.iu.uis.eden.messaging.MessageServiceNames;
038: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
039: import edu.iu.uis.eden.user.Recipient;
040: import edu.iu.uis.eden.user.WorkflowUser;
041: import edu.iu.uis.eden.util.Utilities;
042:
043: /**
044: * Returns a document to a previous node in the route.
045: *
046: * Current implementation only supports returning to a node on the main branch of the
047: * document.
048: *
049: * @author ewestfal
050: */
051: public class MoveDocumentAction extends ActionTakenEvent {
052:
053: protected final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
054: .getLogger(getClass());
055:
056: private MovePoint movePoint;
057:
058: public MoveDocumentAction(DocumentRouteHeaderValue routeHeader,
059: WorkflowUser user) {
060: super (routeHeader, user);
061: setActionTakenCode(EdenConstants.ACTION_TAKEN_MOVE_CD);
062: }
063:
064: public MoveDocumentAction(DocumentRouteHeaderValue routeHeader,
065: WorkflowUser user, String annotation, MovePoint movePoint) {
066: super (routeHeader, user, annotation);
067: setActionTakenCode(EdenConstants.ACTION_TAKEN_MOVE_CD);
068: this .movePoint = movePoint;
069: }
070:
071: /* (non-Javadoc)
072: * @see edu.iu.uis.eden.actions.ActionTakenEvent#isActionCompatibleRequest(java.util.List)
073: */
074: @Override
075: public String validateActionRules()
076: throws EdenUserNotFoundException {
077: return validateActionRules(getActionRequestService()
078: .findAllValidRequests(getUser(),
079: routeHeader.getRouteHeaderId(),
080: EdenConstants.ACTION_REQUEST_COMPLETE_REQ),
081: KEWServiceLocator.getRouteNodeService()
082: .getActiveNodeInstances(
083: getRouteHeader().getRouteHeaderId()));
084: }
085:
086: private String validateActionRules(List actionRequests,
087: Collection activeNodes) throws EdenUserNotFoundException {
088: String super Error = super .validateActionTakenRules();
089: if (!Utilities.isEmpty(super Error)) {
090: return super Error;
091: }
092: if (!getRouteHeader().isValidActionToTake(
093: getActionPerformedCode())) {
094: return "Document is not in a state to be moved";
095: }
096: if (activeNodes.isEmpty()) {
097: return "Document has no active nodes.";
098: }
099: if (!isActionCompatibleRequest(actionRequests)) {
100: return "No request for the user is compatible with the MOVE action";
101: }
102: return "";
103: }
104:
105: /* (non-Javadoc)
106: * @see edu.iu.uis.eden.actions.ActionTakenEvent#isActionCompatibleRequest(java.util.List)
107: */
108: public boolean isActionCompatibleRequest(List requests)
109: throws EdenUserNotFoundException {
110: //Move is always correct because the client application has authorized it
111: return true;
112: }
113:
114: public void recordAction() throws InvalidActionTakenException,
115: EdenUserNotFoundException {
116: MDC.put("docId", getRouteHeader().getRouteHeaderId());
117: checkLocking();
118: updateSearchableAttributesIfPossible();
119: LOG.debug("Moving document "
120: + getRouteHeader().getRouteHeaderId() + " to point: "
121: + displayMovePoint(movePoint) + ", annotation: "
122: + annotation);
123:
124: List actionRequests = getActionRequestService()
125: .findAllValidRequests(getUser(), getRouteHeaderId(),
126: EdenConstants.ACTION_REQUEST_COMPLETE_REQ);
127: Collection activeNodes = KEWServiceLocator
128: .getRouteNodeService().getActiveNodeInstances(
129: getRouteHeader().getRouteHeaderId());
130: String errorMessage = validateActionRules(actionRequests,
131: activeNodes);
132: if (!Utilities.isEmpty(errorMessage)) {
133: throw new InvalidActionTakenException(errorMessage);
134: }
135:
136: // if (getRouteHeader().isValidActionToTake(getActionTakenCode())) {
137:
138: RouteNodeInstance startNodeInstance = determineStartNode(
139: activeNodes, movePoint);
140:
141: // List actionRequests = getActionRequestService().findAllValidRequests(getUser(), getRouteHeaderId(), EdenConstants.ACTION_REQUEST_COMPLETE_REQ);
142: // if (! isActionCompatibleRequest(actionRequests, getActionTakenCode())) {
143: // throw new InvalidActionTakenException("No request for the user is compatible with the MOVE action");
144: // }
145: LOG.debug("Record the move action");
146: Recipient delegator = findDelegatorForActionRequests(actionRequests);
147: saveActionTaken(delegator);
148: getActionRequestService().deactivateRequests(actionTaken,
149: actionRequests);
150: notifyActionTaken(this .actionTaken);
151:
152: // TODO this whole bit is a bit hacky at the moment
153: if (movePoint.getStepsToMove() > 0) {
154: Set<String> targetNodeNames = new HashSet<String>();
155: targetNodeNames.add(determineFutureNodeName(
156: startNodeInstance, movePoint));
157:
158: MoveDocumentService moveDocumentProcessor = MessageServiceNames
159: .getMoveDocumentProcessorService(getRouteHeader());
160: moveDocumentProcessor
161: .moveDocument(getUser(), getRouteHeader(),
162: getActionTaken(), targetNodeNames);
163:
164: // SpringServiceLocator.getRouteQueueService().requeueDocument(routeHeader.getRouteHeaderId(),
165: // EdenConstants.ROUTE_QUEUE_BLANKET_APPROVE_PRIORITY, new Long(0), MoveDocumentProcessor.class.getName(),
166: // MoveDocumentProcessor.getMoveDocumentProcessorValue(getUser(), getActionTaken(), targetNodeNames));
167: //BlanketApproveAction blanketAction = new BlanketApproveAction(getRouteHeader(), getUser(), annotation, targetNodeName);
168: //blanketAction.actionTaken = actionTaken;
169: //blanketAction.recordAction();
170: } else {
171: String targetNodeName = determineReturnNodeName(
172: startNodeInstance, movePoint);
173: ReturnToPreviousNodeAction returnAction = new ReturnToPreviousNodeAction(
174: getRouteHeader(), getUser(), annotation,
175: targetNodeName, false);
176: returnAction.actionTaken = actionTaken;
177: returnAction
178: .setActionTakenCode(EdenConstants.ACTION_TAKEN_MOVE_CD);
179: returnAction.recordAction();
180: }
181: // }
182: }
183:
184: public void doMoveDocumentWork(Set nodeNames) throws Exception {
185:
186: if (getRouteHeader().isInException()) {
187: LOG.debug("Moving document back to Enroute from Exception");
188:
189: String oldStatus = getRouteHeader().getDocRouteStatus();
190: getRouteHeader().markDocumentEnroute();
191:
192: String newStatus = getRouteHeader().getDocRouteStatus();
193: notifyStatusChange(newStatus, oldStatus);
194: }
195: OrchestrationConfig config = new OrchestrationConfig();
196: config.setCause(actionTaken);
197: config.setDestinationNodeNames(nodeNames);
198: config.setSendNotifications(false);
199: new BlanketApproveEngine(config).process(getRouteHeader()
200: .getRouteHeaderId(), null);
201: }
202:
203: public void setActionTaken(ActionTakenValue actionTaken) {
204: this .actionTaken = actionTaken;
205: }
206:
207: private RouteNodeInstance determineStartNode(
208: Collection activeNodes, MovePoint movePoint)
209: throws InvalidActionTakenException {
210: RouteNodeInstance startNodeInstance = null;
211: for (Iterator iterator = activeNodes.iterator(); iterator
212: .hasNext();) {
213: RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator
214: .next();
215: if (nodeInstance.getName().equals(
216: movePoint.getStartNodeName())) {
217: if (startNodeInstance != null) {
218: throw new InvalidActionTakenException(
219: "More than one active node exists with the given name: "
220: + movePoint.getStartNodeName());
221: }
222: startNodeInstance = nodeInstance;
223: }
224: }
225: if (startNodeInstance == null) {
226: throw new InvalidActionTakenException(
227: "Could not locate an active node with the given name: "
228: + movePoint.getStartNodeName());
229: }
230: return startNodeInstance;
231: }
232:
233: private String determineFutureNodeName(
234: RouteNodeInstance startNodeInstance, MovePoint movePoint)
235: throws InvalidActionTakenException {
236: return determineFutureNodeName(
237: startNodeInstance.getRouteNode(), movePoint, 0,
238: new HashSet());
239: }
240:
241: private String determineFutureNodeName(RouteNode node,
242: MovePoint movePoint, int currentStep, Set nodesProcessed)
243: throws InvalidActionTakenException {
244: if (nodesProcessed.contains(node.getRouteNodeId())) {
245: throw new InvalidActionTakenException(
246: "Detected a cycle at node "
247: + node.getRouteNodeName()
248: + " when attempting to move document.");
249: }
250: nodesProcessed.add(node.getRouteNodeId());
251: if (currentStep == movePoint.getStepsToMove()) {
252: return node.getRouteNodeName();
253: }
254: List nextNodes = node.getNextNodes();
255: if (nextNodes.size() == 0) {
256: throw new InvalidActionTakenException(
257: "Could not proceed forward, there are no more nodes in the route. Halted on step "
258: + currentStep);
259: }
260: if (nextNodes.size() != 1) {
261: throw new InvalidActionTakenException(
262: "Cannot move forward in a multi-branch path. Located "
263: + nextNodes.size()
264: + " branches. Halted on step "
265: + currentStep);
266: }
267: return determineFutureNodeName((RouteNode) nextNodes.get(0),
268: movePoint, currentStep + 1, nodesProcessed);
269: }
270:
271: private String determineReturnNodeName(
272: RouteNodeInstance startNodeInstance, MovePoint movePoint)
273: throws InvalidActionTakenException {
274: return determineReturnNodeName(
275: startNodeInstance.getRouteNode(), movePoint, 0);
276: }
277:
278: private String determineReturnNodeName(RouteNode node,
279: MovePoint movePoint, int currentStep)
280: throws InvalidActionTakenException {
281: if (currentStep == movePoint.getStepsToMove()) {
282: return node.getRouteNodeName();
283: }
284: List previousNodes = node.getPreviousNodes();
285: if (previousNodes.size() == 0) {
286: throw new InvalidActionTakenException(
287: "Could not locate the named target node in the document's past route. Halted on step "
288: + currentStep);
289: }
290: if (previousNodes.size() != 1) {
291: throw new InvalidActionTakenException(
292: "Located a multi-branch path, could not proceed backward past this point. Halted on step "
293: + currentStep);
294: }
295: return determineReturnNodeName(
296: (RouteNode) previousNodes.get(0), movePoint,
297: currentStep - 1);
298: }
299:
300: private String displayMovePoint(MovePoint movePoint) {
301: return "fromNode=" + movePoint.getStartNodeName()
302: + ", stepsToMove=" + movePoint.getStepsToMove();
303: }
304:
305: }
|