0001: /*
0002: * Copyright 2005-2007 The Kuali Foundation.
0003: *
0004: *
0005: * Licensed under the Educational Community License, Version 1.0 (the "License");
0006: * you may not use this file except in compliance with the License.
0007: * You may obtain a copy of the License at
0008: *
0009: * http://www.opensource.org/licenses/ecl1.php
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package edu.iu.uis.eden.server;
0018:
0019: import java.rmi.RemoteException;
0020: import java.util.ArrayList;
0021: import java.util.Arrays;
0022: import java.util.Collection;
0023: import java.util.HashMap;
0024: import java.util.HashSet;
0025: import java.util.Iterator;
0026: import java.util.List;
0027: import java.util.Map;
0028: import java.util.Set;
0029:
0030: import org.apache.commons.lang.StringUtils;
0031: import org.apache.log4j.Logger;
0032: import org.kuali.rice.resourceloader.GlobalResourceLoader;
0033:
0034: import edu.iu.uis.eden.EdenConstants;
0035: import edu.iu.uis.eden.KEWServiceLocator;
0036: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
0037: import edu.iu.uis.eden.actiontaken.ActionTakenValue;
0038: import edu.iu.uis.eden.clientapp.vo.ActionRequestVO;
0039: import edu.iu.uis.eden.clientapp.vo.ActionTakenVO;
0040: import edu.iu.uis.eden.clientapp.vo.DocumentContentVO;
0041: import edu.iu.uis.eden.clientapp.vo.DocumentDetailVO;
0042: import edu.iu.uis.eden.clientapp.vo.DocumentTypeVO;
0043: import edu.iu.uis.eden.clientapp.vo.ReportCriteriaVO;
0044: import edu.iu.uis.eden.clientapp.vo.RouteHeaderVO;
0045: import edu.iu.uis.eden.clientapp.vo.RouteNodeInstanceVO;
0046: import edu.iu.uis.eden.clientapp.vo.RouteTemplateEntryVO;
0047: import edu.iu.uis.eden.clientapp.vo.RuleExtensionVO;
0048: import edu.iu.uis.eden.clientapp.vo.RuleReportCriteriaVO;
0049: import edu.iu.uis.eden.clientapp.vo.RuleVO;
0050: import edu.iu.uis.eden.clientapp.vo.UserIdVO;
0051: import edu.iu.uis.eden.clientapp.vo.UserVO;
0052: import edu.iu.uis.eden.clientapp.vo.WorkflowAttributeDefinitionVO;
0053: import edu.iu.uis.eden.clientapp.vo.WorkflowAttributeValidationErrorVO;
0054: import edu.iu.uis.eden.clientapp.vo.WorkgroupIdVO;
0055: import edu.iu.uis.eden.clientapp.vo.WorkgroupVO;
0056: import edu.iu.uis.eden.definition.AttributeDefinition;
0057: import edu.iu.uis.eden.doctype.DocumentType;
0058: import edu.iu.uis.eden.engine.ActivationContext;
0059: import edu.iu.uis.eden.engine.CompatUtils;
0060: import edu.iu.uis.eden.engine.RouteContext;
0061: import edu.iu.uis.eden.engine.node.KeyValuePair;
0062: import edu.iu.uis.eden.engine.node.RouteNode;
0063: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
0064: import edu.iu.uis.eden.engine.simulation.SimulationCriteria;
0065: import edu.iu.uis.eden.engine.simulation.SimulationEngine;
0066: import edu.iu.uis.eden.engine.simulation.SimulationResults;
0067: import edu.iu.uis.eden.exception.DocumentTypeNotFoundException;
0068: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
0069: import edu.iu.uis.eden.exception.WorkflowException;
0070: import edu.iu.uis.eden.plugin.attributes.WorkflowAttribute;
0071: import edu.iu.uis.eden.plugin.attributes.WorkflowAttributeXmlValidator;
0072: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
0073: import edu.iu.uis.eden.routetemplate.FlexRM;
0074: import edu.iu.uis.eden.routetemplate.RuleBaseValues;
0075: import edu.iu.uis.eden.routetemplate.WorkflowAttributeValidationError;
0076: import edu.iu.uis.eden.user.WorkflowUser;
0077: import edu.iu.uis.eden.util.Utilities;
0078: import edu.iu.uis.eden.workgroup.Workgroup;
0079:
0080: @SuppressWarnings("deprecation")
0081: public class WorkflowUtilityWebServiceImpl implements WorkflowUtility {
0082:
0083: private static final Logger LOG = Logger
0084: .getLogger(WorkflowUtilityWebServiceImpl.class);
0085:
0086: public RouteHeaderVO getRouteHeaderWithUser(UserIdVO userId,
0087: Long documentId) throws WorkflowException,
0088: EdenUserNotFoundException {
0089: if (documentId == null) {
0090: LOG
0091: .error("null routeHeaderId passed in. Throwing RuntimeExcpetion");
0092: throw new RuntimeException("Null documentId passed in.");
0093: }
0094: if (userId == null) {
0095: LOG.error("null userId passed in.");
0096: throw new RuntimeException("null userId passed in");
0097: }
0098: LOG.debug("Fetching RouteHeaderVO [id=" + documentId
0099: + ", user=" + userId + "]");
0100: DocumentRouteHeaderValue document = loadDocument(documentId);
0101: WorkflowUser user = null;
0102: if (userId != null) {
0103: user = KEWServiceLocator.getUserService().getWorkflowUser(
0104: userId);
0105: }
0106: RouteHeaderVO routeHeaderVO = BeanConverter.convertRouteHeader(
0107: document, user);
0108: if (routeHeaderVO == null) {
0109: LOG.error("Returning null RouteHeaderVO [id=" + documentId
0110: + ", user=" + userId + "]");
0111: }
0112: LOG.debug("Returning RouteHeaderVO [id=" + documentId
0113: + ", user=" + userId + "]");
0114: return routeHeaderVO;
0115: }
0116:
0117: public RouteHeaderVO getRouteHeader(Long documentId)
0118: throws WorkflowException, EdenUserNotFoundException {
0119: if (documentId == null) {
0120: LOG.error("null routeHeaderId passed in.");
0121: throw new RuntimeException("null routeHeaderId passed in");
0122: }
0123: LOG.debug("Fetching RouteHeaderVO [id=" + documentId + "]");
0124: DocumentRouteHeaderValue document = loadDocument(documentId);
0125: RouteHeaderVO routeHeaderVO = BeanConverter.convertRouteHeader(
0126: document, null);
0127: if (routeHeaderVO == null) {
0128: LOG.error("Returning null RouteHeaderVO [id=" + documentId
0129: + "]");
0130: }
0131: LOG.debug("Returning RouteHeaderVO [id=" + documentId + "]");
0132: return routeHeaderVO;
0133: }
0134:
0135: public DocumentDetailVO getDocumentDetail(Long documentId)
0136: throws WorkflowException, EdenUserNotFoundException {
0137: if (documentId == null) {
0138: LOG.error("null documentId passed in.");
0139: throw new RuntimeException("null documentId passed in");
0140: }
0141: LOG.debug("Fetching DocumentDetailVO [id=" + documentId + "]");
0142: DocumentRouteHeaderValue document = loadDocument(documentId);
0143: DocumentDetailVO documentDetailVO = BeanConverter
0144: .convertDocumentDetail(document);
0145: if (documentDetailVO == null) {
0146: LOG.error("Returning null DocumentDetailVO [id="
0147: + documentId + "]");
0148: }
0149: LOG.debug("Returning DocumentDetailVO [id=" + documentId + "]");
0150: return documentDetailVO;
0151: }
0152:
0153: public RouteNodeInstanceVO getNodeInstance(Long nodeInstanceId)
0154: throws RemoteException, WorkflowException {
0155: if (nodeInstanceId == null) {
0156: LOG.error("null nodeInstanceId passed in.");
0157: throw new RuntimeException("null nodeInstanceId passed in");
0158: }
0159: LOG.debug("Fetching RouteNodeInstanceVO [id=" + nodeInstanceId
0160: + "]");
0161: RouteNodeInstance nodeInstance = KEWServiceLocator
0162: .getRouteNodeService().findRouteNodeInstanceById(
0163: nodeInstanceId);
0164: return BeanConverter.convertRouteNodeInstance(nodeInstance);
0165: }
0166:
0167: public WorkgroupVO getWorkgroup(WorkgroupIdVO workgroupId) {
0168: if (workgroupId == null) {
0169: LOG.error("null workgroupId passed in.");
0170: throw new RuntimeException("null workgroupId passed in.");
0171: }
0172: LOG.debug("Fetching WorkgroupVO [id=" + workgroupId + "]");
0173: Workgroup workgroup = KEWServiceLocator.getWorkgroupService()
0174: .getWorkgroup(workgroupId);
0175: WorkgroupVO workgroupVO = BeanConverter
0176: .convertWorkgroup(workgroup);
0177: if (workgroupVO == null) {
0178: LOG.error("Returning null WorkgroupVO [id=" + workgroupId
0179: + "]");
0180: } else {
0181: LOG.debug("Returning WorkgroupVO [id=" + workgroupId
0182: + ", memberCount="
0183: + workgroupVO.getMembers().length + "]");
0184: }
0185: return workgroupVO;
0186: }
0187:
0188: public UserVO getWorkflowUser(UserIdVO userId)
0189: throws EdenUserNotFoundException {
0190: if (userId == null) {
0191: LOG.error("null userId passed in.");
0192: throw new RuntimeException("null userId passed in.");
0193: }
0194: LOG.debug("Fetching UserVO [id=" + userId + "]");
0195: WorkflowUser user = KEWServiceLocator.getUserService()
0196: .getWorkflowUser(userId);
0197: UserVO userVO = BeanConverter.convertUser(user);
0198: if (userVO == null) {
0199: LOG.error("Returning null UserVO [id=" + userId + "]");
0200: }
0201: return userVO;
0202: }
0203:
0204: public RouteTemplateEntryVO[] getDocRoute(String docName)
0205: throws WorkflowException {
0206: if (docName == null) {
0207: LOG.error("null docName passed in.");
0208: throw new RuntimeException("null docName passed in.");
0209: }
0210: LOG.debug("Fetching RouteTemplateEntryVOs [docName=" + docName
0211: + "]");
0212: return KEWServiceLocator.getDocumentTypeService()
0213: .getDocumentTypeVO(docName).getRouteTemplates();
0214: }
0215:
0216: public DocumentTypeVO getDocumentType(Long documentTypeId)
0217: throws DocumentTypeNotFoundException {
0218: if (documentTypeId == null) {
0219: LOG.error("null documentTypeId passed in.");
0220: throw new RuntimeException("null documentTypeId passed in.");
0221: }
0222: LOG.debug("Fetching DocumentTypeVO [documentTypeId="
0223: + documentTypeId + "]");
0224: return KEWServiceLocator.getDocumentTypeService()
0225: .getDocumentTypeVO(documentTypeId);
0226: }
0227:
0228: public DocumentTypeVO getDocumentTypeByName(String documentTypeName)
0229: throws DocumentTypeNotFoundException {
0230: if (documentTypeName == null) {
0231: LOG.error("null documentTypeName passed in.");
0232: throw new RuntimeException(
0233: "null documentTypeName passed in");
0234: }
0235: LOG.debug("Fetching DocumentTypeVO [documentTypeName="
0236: + documentTypeName + "]");
0237: DocumentTypeVO documentType = KEWServiceLocator
0238: .getDocumentTypeService().getDocumentTypeVO(
0239: documentTypeName);
0240: return documentType;
0241: }
0242:
0243: public Long getNewResponsibilityId() {
0244: LOG.debug("Getting new responsibility id.");
0245: Long rid = KEWServiceLocator.getResponsibilityIdService()
0246: .getNewResponsibilityId();
0247: LOG.debug("returning responsibility Id " + rid);
0248: return rid;
0249: }
0250:
0251: public WorkgroupVO[] getUserWorkgroups(UserIdVO userId)
0252: throws EdenUserNotFoundException, WorkflowException {
0253:
0254: if (userId == null) {
0255: LOG.error("null userId passed in.");
0256: throw new RuntimeException("null userId passed in.");
0257: }
0258: LOG.debug("Fetching user's workgroups [userId=" + userId + "]");
0259: WorkflowUser user = KEWServiceLocator.getUserService()
0260: .getWorkflowUser(userId);
0261: List workgroups = KEWServiceLocator.getWorkgroupService()
0262: .getUsersGroups(user);
0263:
0264: WorkgroupVO[] workgroupVOs = new WorkgroupVO[workgroups.size()];
0265: int i = 0;
0266: for (Iterator iter = workgroups.iterator(); iter.hasNext(); i++) {
0267: Workgroup workgroup = (Workgroup) iter.next();
0268: workgroupVOs[i] = BeanConverter.convertWorkgroup(workgroup);
0269: }
0270: return workgroupVOs;
0271: }
0272:
0273: public ActionRequestVO[] getActionRequests(Long routeHeaderId)
0274: throws EdenUserNotFoundException {
0275: return getActionRequests(routeHeaderId, null, null);
0276: }
0277:
0278: public ActionRequestVO[] getActionRequests(Long routeHeaderId,
0279: String nodeName, UserIdVO userId)
0280: throws EdenUserNotFoundException {
0281: if (routeHeaderId == null) {
0282: LOG.error("null routeHeaderId passed in.");
0283: throw new RuntimeException("null routeHeaderId passed in.");
0284: }
0285: LOG.debug("Fetching ActionRequestVOs [docId=" + routeHeaderId
0286: + "]");
0287: List actionRequests = KEWServiceLocator
0288: .getActionRequestService()
0289: .findAllActionRequestsByRouteHeaderId(routeHeaderId);
0290: List matchingActionRequests = new ArrayList();
0291: for (Iterator iterator = actionRequests.iterator(); iterator
0292: .hasNext();) {
0293: ActionRequestValue actionRequestValue = (ActionRequestValue) iterator
0294: .next();
0295: if (actionRequestMatches(actionRequestValue, nodeName,
0296: userId)) {
0297: matchingActionRequests.add(actionRequestValue);
0298: }
0299: }
0300: ActionRequestVO[] actionRequestVOs = new ActionRequestVO[matchingActionRequests
0301: .size()];
0302: int i = 0;
0303: for (Iterator iter = matchingActionRequests.iterator(); iter
0304: .hasNext(); i++) {
0305: ActionRequestValue actionRequest = (ActionRequestValue) iter
0306: .next();
0307: actionRequestVOs[i] = BeanConverter
0308: .convertActionRequest(actionRequest);
0309: }
0310: return actionRequestVOs;
0311: }
0312:
0313: private boolean actionRequestMatches(
0314: ActionRequestValue actionRequest, String nodeName,
0315: UserIdVO userId) throws EdenUserNotFoundException {
0316: boolean matchesUserId = true; // assume a match in case user is empty
0317: boolean matchesNodeName = true; // assume a match in case node name is empty
0318: if (StringUtils.isNotBlank(nodeName)) {
0319: matchesNodeName = nodeName.equals(actionRequest
0320: .getPotentialNodeName());
0321: }
0322: if (userId != null) {
0323: matchesUserId = actionRequest
0324: .isRecipientRoutedRequest(KEWServiceLocator
0325: .getUserService().getWorkflowUser(userId));
0326: }
0327: return matchesNodeName && matchesUserId;
0328: }
0329:
0330: public ActionTakenVO[] getActionsTaken(Long routeHeaderId)
0331: throws EdenUserNotFoundException {
0332: if (routeHeaderId == null) {
0333: LOG.error("null routeHeaderId passed in.");
0334: throw new RuntimeException("null routeHeaderId passed in.");
0335: }
0336: LOG.debug("Fetching ActionTakenVOs [docId=" + routeHeaderId
0337: + "]");
0338: Collection actionsTaken = KEWServiceLocator
0339: .getActionTakenService().findByRouteHeaderId(
0340: routeHeaderId);
0341: ActionTakenVO[] actionTakenVOs = new ActionTakenVO[actionsTaken
0342: .size()];
0343: int i = 0;
0344: for (Iterator iter = actionsTaken.iterator(); iter.hasNext(); i++) {
0345: ActionTakenValue actionTaken = (ActionTakenValue) iter
0346: .next();
0347: actionTakenVOs[i] = BeanConverter
0348: .convertActionTaken(actionTaken);
0349: }
0350: return actionTakenVOs;
0351: }
0352:
0353: /**
0354: * This work is also being done in the bowels of convertDocumentContentVO in BeanConverter so some code
0355: * could be reduced.
0356: *
0357: * @param definition
0358: * @return WorkflowAttributeValidationErrorVO[] errors from client input into attribute
0359: */
0360: public WorkflowAttributeValidationErrorVO[] validateWorkflowAttributeDefinitionVO(
0361: WorkflowAttributeDefinitionVO definition)
0362: throws WorkflowException {
0363: if (definition == null) {
0364: LOG.error("null definition passed in.");
0365: throw new RuntimeException("null definition passed in.");
0366: }
0367: LOG
0368: .debug("Validating WorkflowAttributeDefinitionVO [attributeName="
0369: + definition.getAttributeName() + "]");
0370: AttributeDefinition attributeDefinition = BeanConverter
0371: .convertWorkflowAttributeDefinitionVO(definition, null);
0372: WorkflowAttribute attribute = null;
0373: if (attributeDefinition != null) {
0374: attribute = (WorkflowAttribute) GlobalResourceLoader
0375: .getObject(attributeDefinition
0376: .getObjectDefinition());
0377: }
0378: //validate inputs from client application if the attribute is capable
0379: if (attribute instanceof WorkflowAttributeXmlValidator) {
0380: List errors = ((WorkflowAttributeXmlValidator) attribute)
0381: .validateClientRoutingData();
0382: WorkflowAttributeValidationErrorVO[] errorVOs = new WorkflowAttributeValidationErrorVO[errors
0383: .size()];
0384: for (int i = 0; i < errorVOs.length; i++) {
0385: errorVOs[i] = BeanConverter
0386: .convertWorkflowAttributeValidationError((WorkflowAttributeValidationError) errors
0387: .get(i));
0388: }
0389: return errorVOs;
0390: } else {
0391: // WORKAROUND: if it is not validatable, then just quietly succeed
0392: return new WorkflowAttributeValidationErrorVO[0];
0393: }
0394: }
0395:
0396: public RouteNodeInstanceVO[] getDocumentRouteNodeInstances(
0397: Long documentId) throws RemoteException, WorkflowException {
0398: LOG.debug("Fetching RouteNodeInstanceVOs [docId=" + documentId
0399: + "]");
0400: return convertRouteNodeInstances(KEWServiceLocator
0401: .getRouteNodeService().getFlattenedNodeInstances(
0402: loadDocument(documentId), true));
0403: }
0404:
0405: public RouteNodeInstanceVO[] getActiveNodeInstances(Long documentId)
0406: throws RemoteException, WorkflowException {
0407: LOG.debug("Fetching active RouteNodeInstanceVOs [docId="
0408: + documentId + "]");
0409: loadDocument(documentId);
0410: return convertRouteNodeInstances(KEWServiceLocator
0411: .getRouteNodeService().getActiveNodeInstances(
0412: documentId));
0413: }
0414:
0415: public RouteNodeInstanceVO[] getTerminalNodeInstances(
0416: Long documentId) throws RemoteException, WorkflowException {
0417: LOG.debug("Fetching terminal RouteNodeInstanceVOs [docId="
0418: + documentId + "]");
0419: loadDocument(documentId);
0420: return convertRouteNodeInstances(KEWServiceLocator
0421: .getRouteNodeService().getTerminalNodeInstances(
0422: documentId));
0423: }
0424:
0425: private RouteNodeInstanceVO[] convertRouteNodeInstances(
0426: List nodeInstances) throws WorkflowException {
0427: RouteNodeInstanceVO[] nodeInstanceVOs = new RouteNodeInstanceVO[nodeInstances
0428: .size()];
0429: int i = 0;
0430: for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
0431: nodeInstanceVOs[i++] = BeanConverter
0432: .convertRouteNodeInstance((RouteNodeInstance) iter
0433: .next());
0434: }
0435: return nodeInstanceVOs;
0436: }
0437:
0438: public boolean isUserInRouteLog(Long routeHeaderId,
0439: UserIdVO userId, boolean lookFuture) throws RemoteException {
0440: if (routeHeaderId == null) {
0441: LOG.error("null routeHeaderId passed in.");
0442: throw new RuntimeException("null routeHeaderId passed in.");
0443: }
0444: if (userId == null) {
0445: LOG.error("null userId passed in.");
0446: throw new RuntimeException("null userId passed in.");
0447: }
0448: boolean authorized = false;
0449: try {
0450: LOG.debug("Evaluating isUserInRouteLog [docId="
0451: + routeHeaderId + ", userId=" + userId
0452: + ", lookFuture=" + lookFuture + "]");
0453: DocumentRouteHeaderValue routeHeader = loadDocument(routeHeaderId);
0454: WorkflowUser user = KEWServiceLocator.getUserService()
0455: .getWorkflowUser(userId);
0456: List actionsTaken = KEWServiceLocator
0457: .getActionTakenService()
0458: .findByRouteHeaderIdWorkflowId(routeHeaderId,
0459: user.getWorkflowUserId().getWorkflowId());
0460:
0461: if (routeHeader.getInitiatorWorkflowId().equals(
0462: user.getWorkflowId())) {
0463: return true;
0464: }
0465:
0466: if (actionsTaken.size() > 0) {
0467: LOG.debug("found action taken by user");
0468: authorized = true;
0469: }
0470:
0471: List actionRequests = KEWServiceLocator
0472: .getActionRequestService()
0473: .findAllActionRequestsByRouteHeaderId(routeHeaderId);
0474: if (actionRequestListHasUser(user, actionRequests)) {
0475: authorized = true;
0476: }
0477:
0478: //using app constant to turn the future look off if need be
0479: //TODO remove this app constant it has out lived it's usefulness
0480: lookFuture = lookFuture
0481: && new Boolean(
0482: Utilities
0483: .getApplicationConstant(EdenConstants.CHECK_ROUTE_LOG_AUTH_FUTURE))
0484: .booleanValue();
0485: if (!lookFuture) {
0486: return authorized;
0487: }
0488:
0489: SimulationEngine simulationEngine = new SimulationEngine();
0490: SimulationCriteria criteria = new SimulationCriteria(
0491: routeHeaderId);
0492: criteria.setDestinationNodeName(null); // process entire document to conclusion
0493: criteria.getDestinationRecipients().add(user);
0494: SimulationResults results = simulationEngine
0495: .runSimulation(criteria);
0496: if (actionRequestListHasUser(user, results
0497: .getSimulatedActionRequests())) {
0498: authorized = true;
0499: }
0500: } catch (Exception ex) {
0501: LOG.warn("Problems evaluating isUserInRouteLog: "
0502: + ex.getMessage(), ex);
0503: }
0504: return authorized;
0505: }
0506:
0507: private boolean actionRequestListHasUser(WorkflowUser user,
0508: List actionRequests) throws EdenUserNotFoundException {
0509: for (Iterator iter = actionRequests.iterator(); iter.hasNext();) {
0510: ActionRequestValue actionRequest = (ActionRequestValue) iter
0511: .next();
0512: if (actionRequest.isRecipientRoutedRequest(user)) {
0513: return true;
0514: }
0515: }
0516: return false;
0517: }
0518:
0519: public boolean documentWillHaveAtLeastOneActionRequest(
0520: ReportCriteriaVO reportCriteriaVO,
0521: String[] actionRequestedCodes) throws RemoteException {
0522: try {
0523: SimulationEngine simulationEngine = new SimulationEngine();
0524: SimulationCriteria criteria = BeanConverter
0525: .convertReportCriteriaVO(reportCriteriaVO);
0526: SimulationResults results = simulationEngine
0527: .runSimulation(criteria);
0528: List actionRequestsToProcess = results
0529: .getSimulatedActionRequests();
0530: actionRequestsToProcess.addAll(results.getDocument()
0531: .getActionRequests());
0532: for (Iterator iter = actionRequestsToProcess.iterator(); iter
0533: .hasNext();) {
0534: ActionRequestValue actionRequest = (ActionRequestValue) iter
0535: .next();
0536: if (actionRequest.isDone()) {
0537: // an action taken has eliminated this request from being active
0538: continue;
0539: }
0540: // if no action request codes are passed in.... assume any request found is
0541: if ((actionRequestedCodes == null)
0542: || (actionRequestedCodes.length == 0)) {
0543: // we found an action request
0544: return true;
0545: }
0546: // check the action requested codes passed in
0547: for (int i = 0; i < actionRequestedCodes.length; i++) {
0548: String requestedActionRequestCode = actionRequestedCodes[i];
0549: if (requestedActionRequestCode.equals(actionRequest
0550: .getActionRequested())) {
0551: if (StringUtils.isBlank(reportCriteriaVO
0552: .getTargetNodeName())) {
0553: return true;
0554: } else if (reportCriteriaVO.getTargetNodeName()
0555: .equals(
0556: actionRequest.getNodeInstance()
0557: .getName())) {
0558: return true;
0559: }
0560: }
0561: }
0562: }
0563: return false;
0564: } catch (Exception ex) {
0565: String error = "Problems evaluating documentWillHaveAtLeastOneActionRequest: "
0566: + ex.getMessage();
0567: LOG.error(error, ex);
0568: throw new RemoteException(error, ex);
0569: }
0570: }
0571:
0572: public boolean isLastApproverInRouteLevel(Long routeHeaderId,
0573: UserIdVO userId, Integer routeLevel)
0574: throws RemoteException, WorkflowException {
0575: if (routeLevel == null) {
0576: LOG.error("null routeLevel passed in.");
0577: throw new RuntimeException("null routeLevel passed in.");
0578: }
0579: LOG.debug("Evaluating isLastApproverInRouteLevel [docId="
0580: + routeHeaderId + ", userId=" + userId
0581: + ", routeLevel=" + routeLevel + "]");
0582: DocumentRouteHeaderValue document = loadDocument(routeHeaderId);
0583: RouteNode node = CompatUtils.getNodeForLevel(document
0584: .getDocumentType(), routeLevel);
0585: if (node == null) {
0586: throw new RuntimeException(
0587: "Cannot resolve given route level to an approriate node name: "
0588: + routeLevel);
0589: }
0590: return isLastApproverAtNode(routeHeaderId, userId, node
0591: .getRouteNodeName());
0592: }
0593:
0594: public boolean isLastApproverAtNode(Long routeHeaderId,
0595: UserIdVO userId, String nodeName)
0596: throws EdenUserNotFoundException {
0597: if (routeHeaderId == null) {
0598: LOG.error("null routeHeaderId passed in.");
0599: throw new RuntimeException("null routeHeaderId passed in.");
0600: }
0601: if (userId == null) {
0602: LOG.error("null userId passed in.");
0603: throw new RuntimeException("null userId passed in.");
0604: }
0605: LOG.debug("Evaluating isLastApproverAtNode [docId="
0606: + routeHeaderId + ", userId=" + userId + ", nodeName="
0607: + nodeName + "]");
0608: loadDocument(routeHeaderId);
0609: // If this app constant is set to true, then we will attempt to simulate activation of non-active requests before
0610: // attempting to deactivate them, this is in order to address the ignore previous issue reported by EPIC in issue
0611: // http://fms.dfa.cornell.edu:8080/browse/KULWF-366
0612: boolean activateFirst = false;
0613: String activateFirstValue = Utilities
0614: .getApplicationConstant(EdenConstants.IS_LAST_APPROVER_ACTIVATE_FIRST);
0615: if (!Utilities.isEmpty(activateFirstValue)) {
0616: activateFirst = new Boolean(activateFirstValue)
0617: .booleanValue();
0618: }
0619: WorkflowUser user = KEWServiceLocator.getUserService()
0620: .getWorkflowUser(userId);
0621: List requests = KEWServiceLocator.getActionRequestService()
0622: .findPendingByDocRequestCdNodeName(routeHeaderId,
0623: EdenConstants.ACTION_REQUEST_APPROVE_REQ,
0624: nodeName);
0625: if (requests == null || requests.isEmpty()) {
0626: return false;
0627: }
0628: ActivationContext activationContext = new ActivationContext(
0629: ActivationContext.CONTEXT_IS_SIMULATION);
0630: for (Iterator iterator = requests.iterator(); iterator
0631: .hasNext();) {
0632: ActionRequestValue request = (ActionRequestValue) iterator
0633: .next();
0634: if (activateFirst && !request.isActive()) {
0635: KEWServiceLocator.getActionRequestService()
0636: .activateRequest(request, activationContext);
0637: }
0638: if (request.isUserRequest()
0639: && request.getWorkflowId().equals(
0640: user.getWorkflowUserId().getWorkflowId())) {
0641: KEWServiceLocator.getActionRequestService()
0642: .deactivateRequest(null, request,
0643: activationContext);
0644: } else if (request.isWorkgroupRequest()
0645: && request.getWorkgroup().hasMember(user)) {
0646: KEWServiceLocator.getActionRequestService()
0647: .deactivateRequest(null, request,
0648: activationContext);
0649: }
0650: }
0651: boolean allDeactivated = true;
0652: for (Iterator iter = requests.iterator(); iter.hasNext();) {
0653: ActionRequestValue actionRequest = (ActionRequestValue) iter
0654: .next();
0655: allDeactivated = allDeactivated
0656: && actionRequest.isDeactivated();
0657: }
0658: return allDeactivated;
0659: }
0660:
0661: /**
0662: * Used to determine if a given route level will produce Approve Action Requests.
0663: *
0664: * @deprecated use routeNodeHasApproverActionRequest instead
0665: */
0666: public boolean routeLevelHasApproverActionRequest(
0667: String documentTypeName, String docContent,
0668: Integer routeLevel) throws WorkflowException {
0669: if (documentTypeName == null) {
0670: LOG.error("null document type name passed in.");
0671: throw new RuntimeException("null document type passed in.");
0672: }
0673: if (routeLevel == null) {
0674: LOG.error("null routeLevel passed in.");
0675: throw new RuntimeException("null routeLevel passed in.");
0676: }
0677: LOG
0678: .debug("Evaluating routeLevelHasApproverActionRequest [docTypeName="
0679: + documentTypeName
0680: + ", routeLevel="
0681: + routeLevel + "]");
0682: DocumentType documentType = KEWServiceLocator
0683: .getDocumentTypeService().findByName(documentTypeName);
0684: if (!CompatUtils.isRouteLevelCompatible(documentType)) {
0685: throw new WorkflowException(
0686: "The given document type is not route level compatible: "
0687: + documentTypeName);
0688: }
0689: RouteNode routeNode = CompatUtils.getNodeForLevel(documentType,
0690: routeLevel);
0691: return routeNodeHasApproverActionRequest(documentType,
0692: docContent, routeNode, routeLevel);
0693: }
0694:
0695: public boolean routeNodeHasApproverActionRequest(
0696: String documentTypeName, String docContent, String nodeName)
0697: throws WorkflowException {
0698: if (documentTypeName == null) {
0699: LOG.error("null docType passed in.");
0700: throw new RuntimeException("null docType passed in.");
0701: }
0702: if (nodeName == null) {
0703: LOG.error("null nodeName passed in.");
0704: throw new RuntimeException("null nodeName passed in.");
0705: }
0706: LOG
0707: .debug("Evaluating routeNodeHasApproverActionRequest [docTypeName="
0708: + documentTypeName
0709: + ", nodeName="
0710: + nodeName
0711: + "]");
0712: DocumentType documentType = KEWServiceLocator
0713: .getDocumentTypeService().findByName(documentTypeName);
0714: RouteNode routeNode = KEWServiceLocator.getRouteNodeService()
0715: .findRouteNodeByName(documentType.getDocumentTypeId(),
0716: nodeName);
0717: return routeNodeHasApproverActionRequest(documentType,
0718: docContent, routeNode, new Integer(
0719: EdenConstants.INVALID_ROUTE_LEVEL));
0720: }
0721:
0722: /**
0723: * Really this method needs to be implemented using the routingReport functionality (the SimulationEngine).
0724: * This would get rid of the needs for us to call to FlexRM directly.
0725: */
0726: private boolean routeNodeHasApproverActionRequest(
0727: DocumentType documentType, String docContent,
0728: RouteNode node, Integer routeLevel)
0729: throws WorkflowException {
0730: if (documentType == null) {
0731: LOG.error("could not locate document type.");
0732: throw new RuntimeException(
0733: "could not locate document type.");
0734: }
0735: if (docContent == null) {
0736: LOG.error("null docContent passed in.");
0737: throw new RuntimeException("null docContent passed in.");
0738: }
0739: if (node == null) {
0740: LOG.error("could not locate route node.");
0741: throw new RuntimeException("could not locate route node.");
0742: }
0743:
0744: DocumentRouteHeaderValue routeHeader = new DocumentRouteHeaderValue();
0745: routeHeader.setRouteHeaderId(new Long(0));
0746: routeHeader.setDocumentTypeId(documentType.getDocumentTypeId());
0747: routeHeader.setDocRouteLevel(routeLevel);
0748: routeHeader.setDocVersion(new Integer(
0749: EdenConstants.CURRENT_DOCUMENT_VERSION));
0750:
0751: if (node.getRuleTemplate() != null && node.isFlexRM()) {
0752: String ruleTemplateName = node.getRuleTemplate().getName();
0753: routeHeader.setDocContent(docContent);
0754: routeHeader
0755: .setDocRouteStatus(EdenConstants.ROUTE_HEADER_INITIATED_CD);
0756: FlexRM flexRM = new FlexRM();
0757: RouteContext context = RouteContext
0758: .getCurrentRouteContext();
0759: context.setDocument(routeHeader);
0760: try {
0761: List actionRequests = flexRM.getActionRequests(
0762: routeHeader, ruleTemplateName);
0763: for (Iterator iter = actionRequests.iterator(); iter
0764: .hasNext();) {
0765: ActionRequestValue actionRequest = (ActionRequestValue) iter
0766: .next();
0767: if (actionRequest.isApproveOrCompleteRequest()) {
0768: return true;
0769: }
0770: }
0771: } finally {
0772: RouteContext.clearCurrentRouteContext();
0773: }
0774: }
0775: return false;
0776: }
0777:
0778: private void incomingParamCheck(Object object, String name) {
0779: if (object == null) {
0780: LOG.error("null " + name + " passed in.");
0781: throw new RuntimeException("null " + name + " passed in.");
0782: }
0783: }
0784:
0785: public void reResolveRole(String documentTypeName, String roleName,
0786: String qualifiedRoleNameLabel) throws WorkflowException {
0787: incomingParamCheck(documentTypeName, "documentTypeName");
0788: incomingParamCheck(roleName, "roleName");
0789: incomingParamCheck(qualifiedRoleNameLabel,
0790: "qualifiedRoleNameLabel");
0791: LOG.debug("Re-resolving Role [docTypeName=" + documentTypeName
0792: + ", roleName=" + roleName
0793: + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel
0794: + "]");
0795: DocumentType documentType = KEWServiceLocator
0796: .getDocumentTypeService().findByName(documentTypeName);
0797: if (Utilities.isEmpty(qualifiedRoleNameLabel)) {
0798: KEWServiceLocator.getRoleService().reResolveRole(
0799: documentType, roleName);
0800: } else {
0801: KEWServiceLocator.getRoleService().reResolveQualifiedRole(
0802: documentType, roleName, qualifiedRoleNameLabel);
0803: }
0804: }
0805:
0806: public void reResolveRoleByDocumentId(Long documentId,
0807: String roleName, String qualifiedRoleNameLabel)
0808: throws WorkflowException {
0809: incomingParamCheck(documentId, "documentId");
0810: incomingParamCheck(roleName, "roleName");
0811: incomingParamCheck(qualifiedRoleNameLabel,
0812: "qualifiedRoleNameLabel");
0813: LOG.debug("Re-resolving Role [documentId=" + documentId
0814: + ", roleName=" + roleName
0815: + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel
0816: + "]");
0817: DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
0818: if (Utilities.isEmpty(qualifiedRoleNameLabel)) {
0819: KEWServiceLocator.getRoleService().reResolveRole(
0820: routeHeader, roleName);
0821: } else {
0822: KEWServiceLocator.getRoleService().reResolveQualifiedRole(
0823: routeHeader, roleName, qualifiedRoleNameLabel);
0824: }
0825: }
0826:
0827: public DocumentDetailVO routingReport(
0828: ReportCriteriaVO reportCriteria) throws WorkflowException {
0829: incomingParamCheck(reportCriteria, "reportCriteria");
0830: LOG.debug("Executing routing report [docId="
0831: + reportCriteria.getRouteHeaderId() + ", docTypeName="
0832: + reportCriteria.getDocumentTypeName() + "]");
0833: SimulationCriteria criteria = BeanConverter
0834: .convertReportCriteriaVO(reportCriteria);
0835: return BeanConverter.convertDocumentDetail(KEWServiceLocator
0836: .getRoutingReportService().report(criteria));
0837: }
0838:
0839: public boolean isFinalApprover(Long routeHeaderId, UserIdVO userId)
0840: throws WorkflowException {
0841: incomingParamCheck(routeHeaderId, "routeHeaderId");
0842: incomingParamCheck(userId, "userId");
0843: LOG.debug("Evaluating isFinalApprover [docId=" + routeHeaderId
0844: + ", userId=" + userId + "]");
0845: DocumentRouteHeaderValue routeHeader = loadDocument(routeHeaderId);
0846: List requests = KEWServiceLocator.getActionRequestService()
0847: .findPendingByDoc(routeHeaderId);
0848: List finalApproverNodes = KEWServiceLocator
0849: .getRouteNodeService().findFinalApprovalRouteNodes(
0850: routeHeader.getDocumentType()
0851: .getDocumentTypeId());
0852: if (finalApproverNodes.isEmpty()) {
0853: LOG
0854: .debug("Could not locate final approval nodes for document "
0855: + routeHeaderId);
0856: return false;
0857: }
0858: Set finalApproverNodeNames = new HashSet();
0859: for (Iterator iterator = finalApproverNodes.iterator(); iterator
0860: .hasNext();) {
0861: RouteNode node = (RouteNode) iterator.next();
0862: finalApproverNodeNames.add(node.getRouteNodeName());
0863: }
0864:
0865: WorkflowUser user = KEWServiceLocator.getUserService()
0866: .getWorkflowUser(userId);
0867: int approveRequest = 0;
0868: for (Iterator iter = requests.iterator(); iter.hasNext();) {
0869: ActionRequestValue request = (ActionRequestValue) iter
0870: .next();
0871: RouteNodeInstance nodeInstance = request.getNodeInstance();
0872: if (nodeInstance == null) {
0873: LOG
0874: .debug("Found an action request on the document with a null node instance, indicating EXCEPTION routing.");
0875: return false;
0876: }
0877: if (finalApproverNodeNames.contains(nodeInstance
0878: .getRouteNode().getRouteNodeName())) {
0879: if (request.isApproveOrCompleteRequest()) {
0880: approveRequest++;
0881: LOG.debug("Found request is approver "
0882: + request.getActionRequestId());
0883: if (!request.isRecipientRoutedRequest(user)) {
0884: LOG.debug("Action Request not for user "
0885: + user.getAuthenticationUserId()
0886: .getAuthenticationId());
0887: return false;
0888: }
0889: }
0890: }
0891: }
0892:
0893: if (approveRequest == 0) {
0894: return false;
0895: }
0896: LOG.debug("User " + userId + " is final approver for document "
0897: + routeHeaderId);
0898: return true;
0899: }
0900:
0901: public boolean isSuperUserForDocumentType(UserIdVO userId,
0902: Long documentTypeId) throws WorkflowException {
0903: LOG.debug("Determining super user status [userId=" + userId
0904: + ", documentTypeId=" + documentTypeId + "]");
0905: DocumentType documentType = KEWServiceLocator
0906: .getDocumentTypeService().findById(documentTypeId);
0907: WorkflowUser user = KEWServiceLocator.getUserService()
0908: .getWorkflowUser(userId);
0909: boolean isSuperUser = documentType.getSuperUserWorkgroup()
0910: .hasMember(user);
0911: LOG.debug("Super user status is " + isSuperUser + ".");
0912: return isSuperUser;
0913: }
0914:
0915: private DocumentRouteHeaderValue loadDocument(Long documentId) {
0916: KEWServiceLocator.getRouteHeaderService().lockRouteHeader(
0917: documentId, true);
0918: return KEWServiceLocator.getRouteHeaderService()
0919: .getRouteHeader(documentId);
0920: }
0921:
0922: public DocumentContentVO getDocumentContent(Long routeHeaderId)
0923: throws WorkflowException {
0924: LOG.debug("Fetching document content [docId=" + routeHeaderId
0925: + "]");
0926: DocumentRouteHeaderValue document = KEWServiceLocator
0927: .getRouteHeaderService().getRouteHeader(routeHeaderId);
0928: return BeanConverter.convertDocumentContent(document
0929: .getDocContent(), routeHeaderId);
0930: }
0931:
0932: public String[] getPreviousRouteNodeNames(Long documentId)
0933: throws RemoteException, WorkflowException {
0934: LOG.debug("Fetching previous node names [docId=" + documentId
0935: + "]");
0936: DocumentRouteHeaderValue document = KEWServiceLocator
0937: .getRouteHeaderService().getRouteHeader(documentId);
0938: //going conservative for now. if the doc isn't enroute or exception nothing will be returned.
0939: if (document.isEnroute() || document.isInException()) {
0940:
0941: List activeNodeInstances = KEWServiceLocator
0942: .getRouteNodeService().getActiveNodeInstances(
0943: document);
0944: long largetActivatedNodeId = 0;
0945: for (Iterator iter = activeNodeInstances.iterator(); iter
0946: .hasNext();) {
0947: RouteNodeInstance routeNodeInstance = (RouteNodeInstance) iter
0948: .next();
0949: if (routeNodeInstance.getRouteNode().getRouteNodeId()
0950: .longValue() > largetActivatedNodeId) {
0951: largetActivatedNodeId = routeNodeInstance
0952: .getRouteNode().getRouteNodeId()
0953: .longValue();
0954: }
0955: }
0956:
0957: List routeNodes = KEWServiceLocator.getRouteNodeService()
0958: .getFlattenedNodeInstances(document, false);
0959: Set nodeNames = new HashSet();
0960: for (Iterator iter = routeNodes.iterator(); iter.hasNext();) {
0961: RouteNodeInstance routeNode = (RouteNodeInstance) iter
0962: .next();
0963: if (routeNode.isComplete()
0964: && !nodeNames.contains(routeNode.getName())) {
0965: //if the prototype of the nodeInstance we're analyzing is less than the largest id of all our active prototypes
0966: //then add it to the list. This is an attempt to account for return to previous hitting a single node multiple times
0967: if (routeNode.getRouteNode().getRouteNodeId()
0968: .longValue() < largetActivatedNodeId) {
0969: nodeNames.add(routeNode.getName());
0970: }
0971: }
0972: }
0973: return (String[]) nodeNames.toArray(new String[nodeNames
0974: .size()]);
0975: } else {
0976: return new String[0];
0977: }
0978: }
0979:
0980: public RuleVO[] ruleReport(RuleReportCriteriaVO ruleReportCriteria)
0981: throws RemoteException, WorkflowException,
0982: EdenUserNotFoundException {
0983: incomingParamCheck(ruleReportCriteria, "ruleReportCriteria");
0984: if (ruleReportCriteria == null) {
0985: throw new IllegalArgumentException(
0986: "At least one criterion must be sent in a RuleReportCriteriaVO object");
0987: }
0988: LOG.debug("Executing rule report [responsibleUser="
0989: + ruleReportCriteria.getResponsibleUser()
0990: + ", responsibleWorkgroup="
0991: + ruleReportCriteria.getResponsibleWorkgroup() + "]");
0992: Map extensionValues = new HashMap();
0993: if (ruleReportCriteria.getRuleExtensionVOs() != null) {
0994: for (int i = 0; i < ruleReportCriteria
0995: .getRuleExtensionVOs().length; i++) {
0996: RuleExtensionVO ruleExtensionVO = ruleReportCriteria
0997: .getRuleExtensionVOs()[i];
0998: KeyValuePair ruleExtension = BeanConverter
0999: .convertRuleExtensionVO(ruleExtensionVO);
1000: extensionValues.put(ruleExtension.getKey(),
1001: ruleExtension.getValue());
1002: }
1003: }
1004: Collection<String> actionRequestCodes = null;
1005: if ((ruleReportCriteria.getActionRequestCodes() != null)
1006: && (ruleReportCriteria.getActionRequestCodes().length != 0)) {
1007: actionRequestCodes = Arrays.asList(ruleReportCriteria
1008: .getActionRequestCodes());
1009: }
1010: Collection rulesFound = KEWServiceLocator
1011: .getRuleService()
1012: .search(
1013: ruleReportCriteria.getDocumentTypeName(),
1014: ruleReportCriteria.getRuleTemplateName(),
1015: ruleReportCriteria.getRuleDescription(),
1016: BeanConverter
1017: .convertWorkgroupIdVO(ruleReportCriteria
1018: .getResponsibleWorkgroup()),
1019: BeanConverter
1020: .convertUserIdVO(ruleReportCriteria
1021: .getResponsibleUser()),
1022: ruleReportCriteria.getResponsibleRoleName(),
1023: ruleReportCriteria
1024: .isConsiderWorkgroupMembership(),
1025: ruleReportCriteria.isIncludeDelegations(),
1026: ruleReportCriteria.isActiveIndicator(),
1027: extensionValues, actionRequestCodes);
1028: RuleVO[] returnableRules = new RuleVO[rulesFound.size()];
1029: int i = 0;
1030: for (Iterator iter = rulesFound.iterator(); iter.hasNext();) {
1031: RuleBaseValues rule = (RuleBaseValues) iter.next();
1032: returnableRules[i] = BeanConverter.convertRule(rule);
1033: i++;
1034: }
1035: return returnableRules;
1036: }
1037: }
|