Coverage Report - org.kuali.rice.kew.service.impl.WorkflowUtilityWebServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
WorkflowUtilityWebServiceImpl
0%
0/572
0%
0/330
4.571
 
 1  
 /*
 2  
  * Copyright 2006-2011 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  
 
 17  
 package org.kuali.rice.kew.service.impl;
 18  
 
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.apache.log4j.Logger;
 21  
 import org.kuali.rice.core.api.exception.RiceRuntimeException;
 22  
 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
 23  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 24  
 import org.kuali.rice.core.util.KeyValue;
 25  
 import org.kuali.rice.kew.actionitem.ActionItem;
 26  
 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
 27  
 import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
 28  
 import org.kuali.rice.kew.actionrequest.Recipient;
 29  
 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
 30  
 import org.kuali.rice.kew.api.KewApiConstants;
 31  
 import org.kuali.rice.kew.definition.AttributeDefinition;
 32  
 import org.kuali.rice.kew.docsearch.DocSearchCriteriaDTO;
 33  
 import org.kuali.rice.kew.docsearch.DocumentSearchResultComponents;
 34  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 35  
 import org.kuali.rice.kew.documentlink.DocumentLink;
 36  
 import org.kuali.rice.kew.dto.ActionItemDTO;
 37  
 import org.kuali.rice.kew.dto.ActionRequestDTO;
 38  
 import org.kuali.rice.kew.dto.ActionTakenDTO;
 39  
 import org.kuali.rice.kew.dto.DTOConverter;
 40  
 import org.kuali.rice.kew.dto.DocumentContentDTO;
 41  
 import org.kuali.rice.kew.dto.DocumentDetailDTO;
 42  
 import org.kuali.rice.kew.dto.DocumentLinkDTO;
 43  
 import org.kuali.rice.kew.dto.DocumentSearchCriteriaDTO;
 44  
 import org.kuali.rice.kew.dto.DocumentSearchResultDTO;
 45  
 import org.kuali.rice.kew.dto.DocumentStatusTransitionDTO;
 46  
 import org.kuali.rice.kew.dto.PropertyDefinitionDTO;
 47  
 import org.kuali.rice.kew.dto.ReportCriteriaDTO;
 48  
 import org.kuali.rice.kew.dto.RouteNodeInstanceDTO;
 49  
 import org.kuali.rice.kew.dto.RuleDTO;
 50  
 import org.kuali.rice.kew.dto.RuleExtensionDTO;
 51  
 import org.kuali.rice.kew.dto.RuleReportCriteriaDTO;
 52  
 import org.kuali.rice.kew.dto.WorkflowAttributeDefinitionDTO;
 53  
 import org.kuali.rice.kew.dto.WorkflowAttributeValidationErrorDTO;
 54  
 import org.kuali.rice.kew.engine.ActivationContext;
 55  
 import org.kuali.rice.kew.engine.CompatUtils;
 56  
 import org.kuali.rice.kew.engine.RouteContext;
 57  
 import org.kuali.rice.kew.engine.node.RouteNode;
 58  
 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
 59  
 import org.kuali.rice.kew.engine.simulation.SimulationCriteria;
 60  
 import org.kuali.rice.kew.engine.simulation.SimulationResults;
 61  
 import org.kuali.rice.kew.engine.simulation.SimulationWorkflowEngine;
 62  
 import org.kuali.rice.kew.exception.WorkflowException;
 63  
 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
 64  
 import org.kuali.rice.kew.routeheader.DocumentStatusTransition;
 65  
 import org.kuali.rice.kew.rule.FlexRM;
 66  
 import org.kuali.rice.kew.rule.RuleBaseValues;
 67  
 import org.kuali.rice.kew.rule.WorkflowAttribute;
 68  
 import org.kuali.rice.kew.rule.WorkflowAttributeValidationError;
 69  
 import org.kuali.rice.kew.rule.WorkflowAttributeXmlValidator;
 70  
 import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
 71  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 72  
 import org.kuali.rice.kew.service.WorkflowUtility;
 73  
 import org.kuali.rice.kew.util.KEWConstants;
 74  
 import org.kuali.rice.kew.util.KEWWebServiceConstants;
 75  
 import org.kuali.rice.kim.api.identity.principal.Principal;
 76  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 77  
 import org.kuali.rice.krad.UserSession;
 78  
 import org.kuali.rice.krad.util.GlobalVariables;
 79  
 import org.kuali.rice.krad.util.KRADConstants;
 80  
 import org.kuali.rice.krad.util.ObjectUtils;
 81  
 
 82  
 import javax.jws.WebService;
 83  
 import java.math.BigDecimal;
 84  
 import java.sql.Timestamp;
 85  
 import java.util.ArrayList;
 86  
 import java.util.Arrays;
 87  
 import java.util.Collection;
 88  
 import java.util.Collections;
 89  
 import java.util.Date;
 90  
 import java.util.HashMap;
 91  
 import java.util.HashSet;
 92  
 import java.util.Iterator;
 93  
 import java.util.LinkedHashSet;
 94  
 import java.util.List;
 95  
 import java.util.Map;
 96  
 import java.util.Set;
 97  
 
 98  
 @SuppressWarnings({"unchecked"})
 99  
 @WebService(endpointInterface = KEWWebServiceConstants.WorkflowUtility.INTERFACE_CLASS,
 100  
         serviceName = KEWWebServiceConstants.WorkflowUtility.WEB_SERVICE_NAME,
 101  
         portName = KEWWebServiceConstants.WorkflowUtility.WEB_SERVICE_PORT,
 102  
         targetNamespace = KEWWebServiceConstants.MODULE_TARGET_NAMESPACE)
 103  0
 public class WorkflowUtilityWebServiceImpl implements WorkflowUtility {
 104  
 
 105  0
     private static final Logger LOG = Logger.getLogger(WorkflowUtilityWebServiceImpl.class);
 106  
 
 107  
     public Map<String, String> getActionsRequested(String principalId, String documentId) {
 108  0
         if (documentId == null) {
 109  0
             LOG.error("null documentId passed in.  Throwing RuntimeExcpetion");
 110  0
             throw new RuntimeException("Null documentId passed in.");
 111  
         }
 112  0
         if (principalId == null) {
 113  0
             LOG.error("null principalId passed in.");
 114  0
             throw new RuntimeException("null principalId passed in");
 115  
         }
 116  0
         if ( LOG.isDebugEnabled() ) {
 117  0
             LOG.debug("Fetching DocumentRouteHeaderValue [id="+documentId+", user="+principalId+"]");
 118  
         }
 119  0
         DocumentRouteHeaderValue document = loadDocument(documentId);
 120  0
         return KEWServiceLocator.getActionRequestService().getActionsRequested(document, principalId, true);
 121  
     }
 122  
 
 123  
     public String getDocumentStatus(String documentId) throws WorkflowException {
 124  0
         if (documentId == null) {
 125  0
             LOG.error("null documentId passed in.");
 126  0
             throw new IllegalArgumentException("null documentId passed in");
 127  
         }
 128  0
         String documentStatus = KEWServiceLocator.getRouteHeaderService().getDocumentStatus(documentId);
 129  0
         if (StringUtils.isEmpty(documentStatus)) {
 130  0
             throw new WorkflowException("Could not locate a document with the ID " + documentId);
 131  
         }
 132  0
         return documentStatus;
 133  
     }
 134  
 
 135  
     public DocumentDetailDTO getDocumentDetail(String documentId) throws WorkflowException {
 136  0
         if (documentId == null) {
 137  0
             LOG.error("null documentId passed in.");
 138  0
             throw new RuntimeException("null documentId passed in");
 139  
         }
 140  0
         if ( LOG.isDebugEnabled() ) {
 141  0
                 LOG.debug("Fetching DocumentDetailVO [id="+documentId+"]");
 142  
         }
 143  0
         DocumentRouteHeaderValue document = loadDocument(documentId);
 144  0
         DocumentDetailDTO documentDetailVO = DTOConverter.convertDocumentDetail(document);
 145  0
         if (documentDetailVO == null) {
 146  0
                 LOG.error("Returning null DocumentDetailVO [id=" + documentId + "]");
 147  
         }
 148  0
         if ( LOG.isDebugEnabled() ) {
 149  0
                 LOG.debug("Returning DocumentDetailVO [id=" + documentId + "]");
 150  
         }
 151  0
         return documentDetailVO;
 152  
     }
 153  
 
 154  
     public RouteNodeInstanceDTO getNodeInstance(String nodeInstanceId) throws WorkflowException {
 155  0
         if (nodeInstanceId == null) {
 156  0
             LOG.error("null nodeInstanceId passed in.");
 157  0
             throw new RuntimeException("null nodeInstanceId passed in");
 158  
         }
 159  0
         if ( LOG.isDebugEnabled() ) {
 160  0
                 LOG.debug("Fetching RouteNodeInstanceVO [id="+nodeInstanceId+"]");
 161  
         }
 162  0
         RouteNodeInstance nodeInstance = KEWServiceLocator.getRouteNodeService().findRouteNodeInstanceById(nodeInstanceId);
 163  0
         return DTOConverter.convertRouteNodeInstance(nodeInstance);
 164  
     }
 165  
 
 166  
     public String getNewResponsibilityId() {
 167  0
             LOG.debug("Getting new responsibility id.");
 168  0
         String rid = KEWServiceLocator.getResponsibilityIdService().getNewResponsibilityId();
 169  0
         if ( LOG.isDebugEnabled() ) {
 170  0
                 LOG.debug("returning responsibility Id " + rid);
 171  
         }
 172  0
         return rid;
 173  
     }
 174  
 
 175  
     public Integer getUserActionItemCount(String principalId) throws WorkflowException {
 176  0
         return Integer.valueOf(KEWServiceLocator.getActionListService().getCount(principalId));
 177  
     }
 178  
 
 179  
         public ActionItemDTO[] getActionItemsForPrincipal(String principalId) throws WorkflowException {
 180  
         //added by Derek
 181  0
         Collection<ActionItem> actionItems = KEWServiceLocator.getActionListService().getActionList(principalId, null);
 182  0
         ActionItemDTO[] actionItemVOs = new ActionItemDTO[actionItems.size()];
 183  0
         int i = 0;
 184  0
         for (Iterator<ActionItem> iterator = actionItems.iterator(); iterator.hasNext(); i++) {
 185  0
             ActionItem actionItem = iterator.next();
 186  0
             actionItemVOs[i] = DTOConverter.convertActionItem(actionItem);
 187  
         }
 188  0
         return actionItemVOs;
 189  
     }
 190  
 
 191  
     public ActionItemDTO[] getAllActionItems(String documentId) throws WorkflowException {
 192  0
         Collection actionItems = KEWServiceLocator.getActionListService().getActionListForSingleDocument(documentId);
 193  0
         ActionItemDTO[] actionItemVOs = new ActionItemDTO[actionItems.size()];
 194  0
         int i = 0;
 195  0
         for (Iterator iterator = actionItems.iterator(); iterator.hasNext(); i++) {
 196  0
             ActionItem actionItem = (ActionItem) iterator.next();
 197  0
             actionItemVOs[i] = DTOConverter.convertActionItem(actionItem);
 198  
         }
 199  0
         return actionItemVOs;
 200  
     }
 201  
 
 202  
     public ActionItemDTO[] getActionItems(String documentId, String[] actionRequestedCodes) throws WorkflowException {
 203  0
         List<String> actionRequestedCds = Arrays.asList(actionRequestedCodes);
 204  0
         ActionItemDTO[] actionItems = getAllActionItems(documentId);
 205  0
         List<ActionItemDTO> matchingActionitems = new ArrayList<ActionItemDTO>();
 206  0
         for (ActionItemDTO actionItemVO : actionItems) {
 207  0
             if (actionRequestedCds.contains(actionItemVO.getActionRequestCd())) {
 208  0
                 matchingActionitems.add(actionItemVO);
 209  
             }
 210  
         }
 211  0
         ActionItemDTO[] returnActionItems = new ActionItemDTO[matchingActionitems.size()];
 212  0
         int j = 0;
 213  0
         for (ActionItemDTO actionItemVO : matchingActionitems) {
 214  0
             returnActionItems[j] = actionItemVO;
 215  0
             j++;
 216  
         }
 217  0
         return returnActionItems;
 218  
     }
 219  
 
 220  
     public ActionRequestDTO[] getAllActionRequests(String documentId) throws WorkflowException {
 221  0
         return getActionRequests(documentId, null, null);
 222  
     }
 223  
 
 224  
     /**
 225  
      * Returns a flattened list of ActionRequests which match the given criteria.
 226  
      * Because the list is flattened, that means that all children requests from
 227  
      * all graphs are returned in the top-level list.
 228  
      */
 229  
     public ActionRequestDTO[] getActionRequests(String documentId, String nodeName, String principalId) throws WorkflowException {
 230  0
         if (documentId == null) {
 231  0
             LOG.error("null documentId passed in.");
 232  0
             throw new RuntimeException("null documentId passed in.");
 233  
         }
 234  0
         if ( LOG.isDebugEnabled() ) {
 235  0
                 LOG.debug("Fetching ActionRequestVOs [docId="+documentId+"]");
 236  
         }
 237  0
         List actionRequests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
 238  0
         List matchingActionRequests = new ArrayList();
 239  0
         for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
 240  0
             ActionRequestValue actionRequestValue = (ActionRequestValue) iterator.next();
 241  0
             if (actionRequestMatches(actionRequestValue, nodeName, principalId)) {
 242  0
                 matchingActionRequests.add(actionRequestValue);
 243  
             }
 244  0
         }
 245  0
         ActionRequestDTO[] actionRequestVOs = new ActionRequestDTO[matchingActionRequests.size()];
 246  0
         int i = 0;
 247  0
         for (Iterator iter = matchingActionRequests.iterator(); iter.hasNext(); i++) {
 248  0
             ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
 249  0
             actionRequestVOs[i] = DTOConverter.convertActionRequest(actionRequest);
 250  
         }
 251  0
         return actionRequestVOs;
 252  
     }
 253  
 
 254  
     private boolean actionRequestMatches(ActionRequestValue actionRequest, String nodeName, String principalId) throws WorkflowException {
 255  0
         boolean matchesUserId = true;  // assume a match in case user is empty
 256  0
         boolean matchesNodeName = true;  // assume a match in case node name is empty
 257  0
         if (StringUtils.isNotBlank(nodeName)) {
 258  0
             matchesNodeName = nodeName.equals(actionRequest.getPotentialNodeName());
 259  
         }
 260  0
         if (principalId != null) {
 261  0
             matchesUserId = actionRequest.isRecipientRoutedRequest(principalId);
 262  
         }
 263  0
         return matchesNodeName && matchesUserId;
 264  
     }
 265  
 
 266  
     public ActionTakenDTO[] getActionsTaken(String documentId) throws WorkflowException {
 267  0
         if (documentId == null) {
 268  0
             LOG.error("null documentId passed in.");
 269  0
             throw new RuntimeException("null documentId passed in.");
 270  
         }
 271  0
         if ( LOG.isDebugEnabled() ) {
 272  0
                 LOG.debug("Fetching ActionTakenVOs [docId="+documentId+"]");
 273  
         }
 274  0
         Collection actionsTaken = KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
 275  0
         ActionTakenDTO[] actionTakenVOs = new ActionTakenDTO[actionsTaken.size()];
 276  0
         int i = 0;
 277  0
         for (Iterator iter = actionsTaken.iterator(); iter.hasNext(); i++) {
 278  0
             ActionTakenValue actionTaken = (ActionTakenValue) iter.next();
 279  0
             actionTakenVOs[i] = DTOConverter.convertActionTakenWithActionRequests(actionTaken);
 280  
         }
 281  0
         return actionTakenVOs;
 282  
     }
 283  
 
 284  
     /**
 285  
      * This work is also being done in the bowels of convertDocumentContentVO in DTOConverter so some code
 286  
      * could be reduced.
 287  
      *
 288  
      * @param definition
 289  
      * @return WorkflowAttributeValidationErrorVO[] errors from client input into attribute
 290  
      */
 291  
     public WorkflowAttributeValidationErrorDTO[] validateWorkflowAttributeDefinitionVO(WorkflowAttributeDefinitionDTO definition) throws WorkflowException {
 292  0
         if (definition == null) {
 293  0
             LOG.error("null definition passed in.");
 294  0
             throw new RuntimeException("null definition passed in.");
 295  
         }
 296  0
         if ( LOG.isDebugEnabled() ) {
 297  0
                 LOG.debug("Validating WorkflowAttributeDefinitionVO [attributeName="+definition.getAttributeName()+"]");
 298  
         }
 299  0
         AttributeDefinition attributeDefinition = DTOConverter.convertWorkflowAttributeDefinitionVO(definition, null);
 300  0
         WorkflowAttribute attribute = null;
 301  0
         if (attributeDefinition != null) {
 302  0
                 attribute = (WorkflowAttribute) GlobalResourceLoader.getObject(attributeDefinition.getObjectDefinition());
 303  
         }
 304  0
         if (attribute instanceof GenericXMLRuleAttribute) {
 305  0
             Map<String, String> attributePropMap = new HashMap<String, String>();
 306  0
             GenericXMLRuleAttribute xmlAttribute = (GenericXMLRuleAttribute)attribute;
 307  0
             xmlAttribute.setRuleAttribute(attributeDefinition.getRuleAttribute());
 308  0
             for (int i = 0; i < definition.getProperties().length; i++) {
 309  0
                 PropertyDefinitionDTO property = definition.getProperties()[i];
 310  0
                 attributePropMap.put(property.getName(), property.getValue());
 311  
             }
 312  0
             xmlAttribute.setParamMap(attributePropMap);
 313  
         }
 314  
         //validate inputs from client application if the attribute is capable
 315  0
         if (attribute instanceof WorkflowAttributeXmlValidator) {
 316  0
             List errors = ((WorkflowAttributeXmlValidator)attribute).validateClientRoutingData();
 317  0
             WorkflowAttributeValidationErrorDTO[] errorVOs = new WorkflowAttributeValidationErrorDTO[errors.size()];
 318  0
             for (int i = 0; i < errorVOs.length; i++) {
 319  0
                 errorVOs[i] = DTOConverter.convertWorkflowAttributeValidationError((WorkflowAttributeValidationError)errors.get(i));
 320  
             }
 321  0
             return errorVOs;
 322  
         } else {
 323  
             // WORKAROUND: if it is not validatable, then just quietly succeed
 324  0
             return new WorkflowAttributeValidationErrorDTO[0];
 325  
         }
 326  
     }
 327  
 
 328  
     public RouteNodeInstanceDTO[] getDocumentRouteNodeInstances(String documentId) throws WorkflowException {
 329  0
             if ( LOG.isDebugEnabled() ) {
 330  0
                     LOG.debug("Fetching RouteNodeInstanceVOs [docId=" + documentId + "]");
 331  
             }
 332  0
             return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getFlattenedNodeInstances(loadDocument(documentId), true));
 333  
     }
 334  
 
 335  
     public RouteNodeInstanceDTO[] getActiveNodeInstances(String documentId) throws WorkflowException {
 336  0
             if ( LOG.isDebugEnabled() ) {
 337  0
                     LOG.debug("Fetching active RouteNodeInstanceVOs [docId=" + documentId + "]");
 338  
             }
 339  0
         loadDocument(documentId);
 340  0
         return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(documentId));
 341  
     }
 342  
 
 343  
     public RouteNodeInstanceDTO[] getTerminalNodeInstances(String documentId) throws WorkflowException {
 344  0
             if ( LOG.isDebugEnabled() ) {
 345  0
                     LOG.debug("Fetching terminal RouteNodeInstanceVOs [docId=" + documentId + "]");
 346  
             }
 347  0
             loadDocument(documentId);
 348  0
         return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getTerminalNodeInstances(documentId));
 349  
     }
 350  
 
 351  
     public RouteNodeInstanceDTO[] getCurrentNodeInstances(String documentId) throws WorkflowException {
 352  0
             if ( LOG.isDebugEnabled() ) {
 353  0
                     LOG.debug("Fetching current RouteNodeInstanceVOs [docId=" + documentId + "]");
 354  
             }
 355  0
             loadDocument(documentId);
 356  0
             return convertRouteNodeInstances(KEWServiceLocator.getRouteNodeService().getCurrentNodeInstances(documentId));
 357  
     }
 358  
 
 359  
     private RouteNodeInstanceDTO[] convertRouteNodeInstances(List nodeInstances) throws WorkflowException {
 360  0
         RouteNodeInstanceDTO[] nodeInstanceVOs = new RouteNodeInstanceDTO[nodeInstances.size()];
 361  0
         int i = 0;
 362  0
         for (Iterator iter = nodeInstances.iterator(); iter.hasNext(); ) {
 363  0
             nodeInstanceVOs[i++] = DTOConverter.convertRouteNodeInstance((RouteNodeInstance) iter.next());
 364  
         }
 365  0
         return nodeInstanceVOs;
 366  
     }
 367  
 
 368  
     public boolean isUserInRouteLog(String documentId, String principalId, boolean lookFuture) throws WorkflowException {
 369  0
             return isUserInRouteLogWithOptionalFlattening(documentId, principalId, lookFuture, false);
 370  
     }
 371  
     
 372  
     public boolean isUserInRouteLogWithOptionalFlattening(String documentId, String principalId, boolean lookFuture, boolean flattenNodes) throws WorkflowException {
 373  0
         if (documentId == null) {
 374  0
             LOG.error("null documentId passed in.");
 375  0
             throw new RuntimeException("null documentId passed in.");
 376  
         }
 377  0
         if (principalId == null ){
 378  0
             LOG.error("null principalId passed in.");
 379  0
             throw new RiceRuntimeException("null principalId passed in.");
 380  
         }
 381  0
         boolean authorized = false;
 382  0
         if ( LOG.isDebugEnabled() ) {
 383  0
                 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", principalId=" + principalId + ", lookFuture=" + lookFuture + "]");
 384  
         }
 385  0
         DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
 386  0
         Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
 387  0
         List actionsTaken = KEWServiceLocator.getActionTakenService().findByDocumentIdWorkflowId(documentId, principal.getPrincipalId());
 388  
 
 389  0
         if(routeHeader.getInitiatorWorkflowId().equals(principal.getPrincipalId())){
 390  0
                 return true;
 391  
         }
 392  
 
 393  0
         if (actionsTaken.size() > 0) {
 394  0
                 LOG.debug("found action taken by user");
 395  0
                 authorized = true;
 396  
         }
 397  
 
 398  0
         List actionRequests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
 399  0
         if (actionRequestListHasPrincipal(principal, actionRequests)) {
 400  0
                 authorized = true;
 401  
         }
 402  
 
 403  0
         if (!lookFuture) {
 404  0
                 return authorized;
 405  
         }
 406  
 
 407  
 
 408  0
         SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
 409  0
         SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
 410  0
         criteria.setDestinationNodeName(null); // process entire document to conclusion
 411  0
         criteria.getDestinationRecipients().add(new KimPrincipalRecipient(principal));
 412  0
         criteria.setFlattenNodes(flattenNodes);
 413  
 
 414  
         try {
 415  0
                 SimulationResults results = simulationEngine.runSimulation(criteria);
 416  0
                 if (actionRequestListHasPrincipal(principal, results.getSimulatedActionRequests())) {
 417  0
                         authorized = true;
 418  
                 }
 419  0
         } catch (Exception e) {
 420  0
                 throw new RiceRuntimeException(e);
 421  0
         }
 422  
 
 423  0
         return authorized;
 424  
     }
 425  
 
 426  
     /**
 427  
      * @see org.kuali.rice.kew.service.WorkflowUtility#getPrincipalIdsInRouteLog(java.lang.Long, boolean)
 428  
      */
 429  
     public String[] getPrincipalIdsInRouteLog(String documentId, boolean lookFuture) throws WorkflowException {
 430  0
         if (documentId == null) {
 431  0
             LOG.error("null documentId passed in.");
 432  0
             throw new RuntimeException("null documentId passed in.");
 433  
         }
 434  0
             Set<String> principalIds = new HashSet<String>();
 435  
         try {
 436  0
                 if ( LOG.isDebugEnabled() ) {
 437  0
                         LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", lookFuture=" + lookFuture + "]");
 438  
                 }
 439  0
             DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
 440  0
             List<ActionTakenValue> actionsTakens =
 441  
                     (List<ActionTakenValue>)KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
 442  
             //TODO: confirm that the initiator is not already there in the actionstaken
 443  0
             principalIds.add(routeHeader.getInitiatorWorkflowId());
 444  0
             for(ActionTakenValue actionTaken: actionsTakens){
 445  0
                     principalIds.add(actionTaken.getPrincipalId());
 446  
             }
 447  0
             List<ActionRequestValue> actionRequests =
 448  
                     KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
 449  0
             for(ActionRequestValue actionRequest: actionRequests){
 450  0
                     principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
 451  
             }
 452  0
             if (!lookFuture) {
 453  0
                     return principalIds.toArray(new String[]{});
 454  
             }
 455  0
             SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
 456  0
             SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
 457  0
             criteria.setDestinationNodeName(null); // process entire document to conclusion
 458  0
             SimulationResults results = simulationEngine.runSimulation(criteria);
 459  0
             actionRequests = (List<ActionRequestValue>)results.getSimulatedActionRequests();
 460  0
             for(ActionRequestValue actionRequest: actionRequests){
 461  0
                     principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
 462  
             }
 463  0
         } catch (Exception ex) {
 464  0
             LOG.warn("Problems getting principalIds in Route Log for documentId: "+documentId+". Exception:"+ex.getMessage(),ex);
 465  0
         }
 466  0
             return principalIds.toArray(new String[]{});
 467  
     }
 468  
 
 469  
         /**
 470  
          * This method gets all of the principalIds for the given ActionRequestValue.  It drills down into
 471  
          * groups if need be.
 472  
          * 
 473  
          * @param actionRequest
 474  
          */
 475  
         private List<String> getPrincipalIdsForActionRequest(ActionRequestValue actionRequest) {
 476  0
                 List<String> results = Collections.emptyList();
 477  0
                 if (actionRequest.getPrincipalId() != null) {
 478  0
                         results = Collections.singletonList(actionRequest.getPrincipalId());
 479  0
                 } else if (actionRequest.getGroupId() != null) {
 480  0
                         List<String> principalIdsForGroup = 
 481  
                                 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId());
 482  0
                         if (principalIdsForGroup != null) {
 483  0
                                 results = principalIdsForGroup;
 484  
                         }
 485  
                 }
 486  0
                 return results;
 487  
         }
 488  
 
 489  
     /***
 490  
      * @see org.kuali.rice.kew.service.WorkflowUtility#getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(java.lang.String, java.lang.Long)
 491  
      */
 492  
     public String[] getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(String actionRequestedCd, String documentId){
 493  0
             List<String> results = KEWServiceLocator.getActionRequestService().
 494  
                                     getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(actionRequestedCd, documentId);
 495  0
             if (ObjectUtils.isNull(results)) {
 496  0
                     return null;
 497  
             }
 498  0
             return results.toArray(new String[]{});
 499  
     }
 500  
 
 501  
     private boolean actionRequestListHasPrincipal(Principal principal, List actionRequests) throws WorkflowException {
 502  0
         for (Iterator iter = actionRequests.iterator(); iter.hasNext();) {
 503  0
             ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
 504  0
             if (actionRequest.isRecipientRoutedRequest(new KimPrincipalRecipient(principal))) {
 505  0
                 return true;
 506  
             }
 507  0
         }
 508  0
         return false;
 509  
     }
 510  
 
 511  
     private boolean isRecipientRoutedRequest(ActionRequestValue actionRequest, List<Recipient> recipients) throws WorkflowException {
 512  0
         for (Recipient recipient : recipients) {
 513  0
             if (actionRequest.isRecipientRoutedRequest(recipient)) {
 514  0
                 return true;
 515  
             }
 516  
         }
 517  0
         return false;
 518  
     }
 519  
 
 520  
     /**
 521  
      * @see org.kuali.rice.kew.service.WorkflowUtility#documentWillHaveAtLeastOneActionRequest(org.kuali.rice.kew.dto.ReportCriteriaDTO, java.lang.String[], boolean)
 522  
      */
 523  
     public boolean documentWillHaveAtLeastOneActionRequest(ReportCriteriaDTO reportCriteriaDTO, String[] actionRequestedCodes, boolean ignoreCurrentActionRequests) {
 524  
         try {
 525  0
                 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
 526  0
                 SimulationCriteria criteria = DTOConverter.convertReportCriteriaDTO(reportCriteriaDTO);
 527  
                 // set activate requests to true by default so force action works correctly
 528  0
                 criteria.setActivateRequests(Boolean.TRUE);
 529  0
                 SimulationResults results = simulationEngine.runSimulation(criteria);
 530  0
             List actionRequestsToProcess = results.getSimulatedActionRequests();
 531  0
             if (!ignoreCurrentActionRequests) {
 532  0
                 actionRequestsToProcess.addAll(results.getDocument().getActionRequests());
 533  
             }
 534  0
             for (Iterator iter = actionRequestsToProcess.iterator(); iter.hasNext();) {
 535  0
                                 ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
 536  0
                 if (actionRequest.isDone()) {
 537  
                     // an action taken has eliminated this request from being active
 538  0
                     continue;
 539  
                 }
 540  
                                 // if no action request codes are passed in.... assume any request found is
 541  0
                             if ( (actionRequestedCodes == null) || (actionRequestedCodes.length == 0) ) {
 542  
                                     // we found an action request
 543  0
                                     return true;
 544  
                             }
 545  
                             // check the action requested codes passed in
 546  0
                             for (String requestedActionRequestCode : actionRequestedCodes) {
 547  0
                                         if (requestedActionRequestCode.equals(actionRequest.getActionRequested())) {
 548  0
                                             boolean satisfiesDestinationUserCriteria = (criteria.getDestinationRecipients().isEmpty()) || (isRecipientRoutedRequest(actionRequest,criteria.getDestinationRecipients()));
 549  0
                                             if (satisfiesDestinationUserCriteria) {
 550  0
                                                 if (StringUtils.isBlank(criteria.getDestinationNodeName())) {
 551  0
                                                     return true;
 552  0
                                                 } else if (StringUtils.equals(criteria.getDestinationNodeName(),actionRequest.getNodeInstance().getName())) {
 553  0
                                                     return true;
 554  
                                                 }
 555  
                                             }
 556  
                                         }
 557  
                                 }
 558  0
                         }
 559  0
                 return false;
 560  0
         } catch (Exception ex) {
 561  0
                 String error = "Problems evaluating documentWillHaveAtLeastOneActionRequest: " + ex.getMessage();
 562  0
             LOG.error(error,ex);
 563  0
             if (ex instanceof RuntimeException) {
 564  0
                     throw (RuntimeException)ex;
 565  
             }
 566  0
             throw new RuntimeException(error, ex);
 567  
         }
 568  
     }
 569  
 
 570  
     public boolean isLastApproverInRouteLevel(String documentId, String principalId, Integer routeLevel) throws WorkflowException {
 571  0
         if (routeLevel == null) {
 572  0
             LOG.error("null routeLevel passed in.");
 573  0
             throw new RuntimeException("null routeLevel passed in.");
 574  
         }
 575  0
         if ( LOG.isDebugEnabled() ) {
 576  0
                 LOG.debug("Evaluating isLastApproverInRouteLevel [docId=" + documentId + ", principalId=" + principalId + ", routeLevel=" + routeLevel + "]");
 577  
         }
 578  0
         DocumentRouteHeaderValue document = loadDocument(documentId);
 579  0
         RouteNode node = CompatUtils.getNodeForLevel(document.getDocumentType(), routeLevel);
 580  0
         if (node == null) {
 581  0
             throw new RuntimeException("Cannot resolve given route level to an approriate node name: " + routeLevel);
 582  
         }
 583  0
         return isLastApproverAtNode(documentId, principalId, node.getRouteNodeName());
 584  
     }
 585  
 
 586  
     public boolean isLastApproverAtNode(String documentId, String principalId, String nodeName) throws WorkflowException {
 587  0
         if (documentId == null) {
 588  0
             LOG.error("null documentId passed in.");
 589  0
             throw new RuntimeException("null documentId passed in.");
 590  
         }
 591  0
         if (principalId == null ){
 592  0
             LOG.error("null principalId passed in.");
 593  0
             throw new RuntimeException("null principalId passed in.");
 594  
         }
 595  0
         if ( LOG.isDebugEnabled() ) {
 596  0
                 LOG.debug("Evaluating isLastApproverAtNode [docId=" + documentId + ", principalId=" + principalId + ", nodeName=" + nodeName + "]");
 597  
         }
 598  0
         loadDocument(documentId);
 599  
         // If this app constant is set to true, then we will attempt to simulate activation of non-active requests before
 600  
         // attempting to deactivate them, this is in order to address the force action issue reported by EPIC in issue
 601  
         // http://fms.dfa.cornell.edu:8080/browse/KULWF-366
 602  0
         Boolean activateFirst = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KEWConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.FEATURE_DETAIL_TYPE, KEWConstants.IS_LAST_APPROVER_ACTIVATE_FIRST_IND);
 603  0
         if (activateFirst == null) {
 604  0
             activateFirst = Boolean.FALSE;
 605  
         }
 606  
 
 607  0
         List requests = KEWServiceLocator.getActionRequestService().findPendingByDocRequestCdNodeName(documentId, KEWConstants.ACTION_REQUEST_APPROVE_REQ, nodeName);
 608  0
         if (requests == null || requests.isEmpty()) {
 609  0
             return false;
 610  
         }
 611  
         
 612  
         // Deep-copy the action requests for the simulation.
 613  0
         for (int i = requests.size() - 1; i >= 0; i--) {
 614  0
                 ActionRequestValue actionRequest = (ActionRequestValue) ObjectUtils.deepCopy((ActionRequestValue)requests.get(i));
 615  
                 // Deep-copy the action items as well, since they are indirectly retrieved from the action request via service calls.
 616  0
                 for (ActionItem actionItem : actionRequest.getActionItems()) {
 617  0
                         actionRequest.getSimulatedActionItems().add((ActionItem) ObjectUtils.deepCopy(actionItem));
 618  
                 }
 619  0
                 requests.set(i, actionRequest);
 620  
         }
 621  
         
 622  0
         ActivationContext activationContext = new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION);
 623  0
         for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
 624  0
             ActionRequestValue request = (ActionRequestValue) iterator.next();
 625  0
             if (activateFirst && !request.isActive()) {
 626  0
                 KEWServiceLocator.getActionRequestService().activateRequest(request, activationContext);
 627  
             }
 628  0
             if (request.isUserRequest() && request.getPrincipalId().equals(principalId)) {
 629  0
                 KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
 630  0
             } else if (request.isGroupRequest() && KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, request.getGroup().getId())) {
 631  0
                 KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
 632  
             }
 633  0
         }
 634  0
         boolean allDeactivated = true;
 635  0
         for (Iterator iter = requests.iterator(); iter.hasNext();) {
 636  0
             ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
 637  0
             allDeactivated = allDeactivated && actionRequest.isDeactivated();
 638  0
         }
 639  0
         return allDeactivated;
 640  
     }
 641  
 
 642  
     /**
 643  
      * Used to determine if a given route level will produce Approve Action Requests.
 644  
      *
 645  
      * @deprecated use routeNodeHasApproverActionRequest instead
 646  
      */
 647  
     public boolean routeLevelHasApproverActionRequest(String documentTypeName, String docContent, Integer routeLevel) throws WorkflowException {
 648  0
         if (documentTypeName == null) {
 649  0
             LOG.error("null document type name passed in.");
 650  0
             throw new RuntimeException("null document type passed in.");
 651  
         }
 652  0
         if (routeLevel == null) {
 653  0
             LOG.error("null routeLevel passed in.");
 654  0
             throw new RuntimeException("null routeLevel passed in.");
 655  
         }
 656  0
         if ( LOG.isDebugEnabled() ) {
 657  0
                 LOG.debug("Evaluating routeLevelHasApproverActionRequest [docTypeName=" + documentTypeName + ", routeLevel=" + routeLevel + "]");
 658  
         }
 659  0
         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
 660  0
         if (!CompatUtils.isRouteLevelCompatible(documentType)) {
 661  0
             throw new WorkflowException("The given document type is not route level compatible: " + documentTypeName);
 662  
         }
 663  0
         RouteNode routeNode = CompatUtils.getNodeForLevel(documentType, routeLevel);
 664  0
         return routeNodeHasApproverActionRequest(documentType, docContent, routeNode, routeLevel);
 665  
     }
 666  
 
 667  
     public boolean routeNodeHasApproverActionRequest(String documentTypeName, String docContent, String nodeName) throws WorkflowException {
 668  0
         if (documentTypeName == null) {
 669  0
             LOG.error("null docType passed in.");
 670  0
             throw new RuntimeException("null docType passed in.");
 671  
         }
 672  0
         if (nodeName == null) {
 673  0
             LOG.error("null nodeName passed in.");
 674  0
             throw new RuntimeException("null nodeName passed in.");
 675  
         }
 676  0
         if ( LOG.isDebugEnabled() ) {
 677  0
                 LOG.debug("Evaluating routeNodeHasApproverActionRequest [docTypeName=" + documentTypeName + ", nodeName=" + nodeName + "]");
 678  
         }
 679  0
         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
 680  0
         RouteNode routeNode = KEWServiceLocator.getRouteNodeService().findRouteNodeByName(documentType.getDocumentTypeId(), nodeName);
 681  0
         return routeNodeHasApproverActionRequest(documentType, docContent, routeNode, new Integer(KEWConstants.INVALID_ROUTE_LEVEL));
 682  
     }
 683  
 
 684  
     /**
 685  
      * Really this method needs to be implemented using the routingReport functionality (the SimulationEngine).
 686  
      * This would get rid of the needs for us to call to FlexRM directly.
 687  
      */
 688  
     private boolean routeNodeHasApproverActionRequest(DocumentType documentType, String docContent, RouteNode node, Integer routeLevel) throws WorkflowException {
 689  0
         if (documentType == null) {
 690  0
             LOG.error("could not locate document type.");
 691  0
             throw new RuntimeException("could not locate document type.");
 692  
         }
 693  0
         if (docContent == null) {
 694  0
             LOG.error("null docContent passed in.");
 695  0
             throw new RuntimeException("null docContent passed in.");
 696  
         }
 697  0
         if (node == null) {
 698  0
             LOG.error("could not locate route node.");
 699  0
             throw new RuntimeException("could not locate route node.");
 700  
         }
 701  
 
 702  0
         DocumentRouteHeaderValue routeHeader = new DocumentRouteHeaderValue();
 703  0
         routeHeader.setDocumentId("");
 704  0
         routeHeader.setDocumentTypeId(documentType.getDocumentTypeId());
 705  0
         routeHeader.setDocRouteLevel(routeLevel);
 706  0
         routeHeader.setDocVersion(new Integer(KewApiConstants.DocumentContentVersions.CURRENT));
 707  
 
 708  0
         if (node.getRuleTemplate() != null && node.isFlexRM()) {
 709  0
             String ruleTemplateName = node.getRuleTemplate().getName();
 710  0
             routeHeader.setDocContent(docContent);
 711  0
             routeHeader.setDocRouteStatus(KEWConstants.ROUTE_HEADER_INITIATED_CD);
 712  0
             FlexRM flexRM = new FlexRM();
 713  0
                     RouteContext context = RouteContext.getCurrentRouteContext();
 714  0
                     context.setDocument(routeHeader);
 715  
                     try {
 716  0
                             List actionRequests = flexRM.getActionRequests(routeHeader, node, null, ruleTemplateName);
 717  0
                             for (Iterator iter = actionRequests.iterator(); iter.hasNext();) {
 718  0
                                     ActionRequestValue actionRequest = (ActionRequestValue) iter.next();
 719  0
                                     if (actionRequest.isApproveOrCompleteRequest()) {
 720  0
                                             return true;
 721  
                                     }
 722  0
                             }
 723  
                     } finally {
 724  0
                             RouteContext.clearCurrentRouteContext();
 725  0
                     }
 726  
         }
 727  0
         return false;
 728  
     }
 729  
 
 730  
     private void incomingParamCheck(Object object, String name) {
 731  0
         if (object == null) {
 732  0
             LOG.error("null " + name + " passed in.");
 733  0
             throw new RuntimeException("null " + name + " passed in.");
 734  
         }
 735  0
     }
 736  
 
 737  
     public void reResolveRoleByDocTypeName(String documentTypeName, String roleName, String qualifiedRoleNameLabel) throws WorkflowException {
 738  0
         incomingParamCheck(documentTypeName, "documentTypeName");
 739  0
         incomingParamCheck(roleName, "roleName");
 740  0
         incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
 741  0
         if ( LOG.isDebugEnabled() ) {
 742  0
                 LOG.debug("Re-resolving Role [docTypeName=" + documentTypeName + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
 743  
         }
 744  0
             DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
 745  0
             if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
 746  0
                     KEWServiceLocator.getRoleService().reResolveRole(documentType, roleName);
 747  
             } else {
 748  0
                     KEWServiceLocator.getRoleService().reResolveQualifiedRole(documentType, roleName, qualifiedRoleNameLabel);
 749  
             }
 750  0
     }
 751  
 
 752  
     public void reResolveRoleByDocumentId(String documentId, String roleName, String qualifiedRoleNameLabel) throws WorkflowException {
 753  0
         incomingParamCheck(documentId, "documentId");
 754  0
         incomingParamCheck(roleName, "roleName");
 755  0
         incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
 756  0
         if ( LOG.isDebugEnabled() ) {
 757  0
                 LOG.debug("Re-resolving Role [documentId=" + documentId + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
 758  
         }
 759  0
         DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
 760  0
             if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
 761  0
                     KEWServiceLocator.getRoleService().reResolveRole(routeHeader, roleName);
 762  
             } else {
 763  0
                     KEWServiceLocator.getRoleService().reResolveQualifiedRole(routeHeader, roleName, qualifiedRoleNameLabel);
 764  
             }
 765  0
     }
 766  
 
 767  
     public DocumentDetailDTO routingReport(ReportCriteriaDTO reportCriteria) throws WorkflowException {
 768  0
         incomingParamCheck(reportCriteria, "reportCriteria");
 769  0
         if ( LOG.isDebugEnabled() ) {
 770  0
                 LOG.debug("Executing routing report [docId=" + reportCriteria.getDocumentId() + ", docTypeName=" + reportCriteria.getDocumentTypeName() + "]");
 771  
         }
 772  0
         SimulationCriteria criteria = DTOConverter.convertReportCriteriaDTO(reportCriteria);
 773  0
         return DTOConverter.convertDocumentDetail(KEWServiceLocator.getRoutingReportService().report(criteria));
 774  
     }
 775  
 
 776  
     public boolean isFinalApprover(String documentId, String principalId) throws WorkflowException {
 777  0
         incomingParamCheck(documentId, "documentId");
 778  0
         incomingParamCheck(principalId, "principalId");
 779  0
         if ( LOG.isDebugEnabled() ) {
 780  0
                 LOG.debug("Evaluating isFinalApprover [docId=" + documentId + ", principalId=" + principalId + "]");
 781  
         }
 782  0
         DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
 783  0
         List requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
 784  0
         List finalApproverNodes = KEWServiceLocator.getRouteNodeService().findFinalApprovalRouteNodes(routeHeader.getDocumentType().getDocumentTypeId());
 785  0
         if (finalApproverNodes.isEmpty()) {
 786  0
                 if ( LOG.isDebugEnabled() ) {
 787  0
                         LOG.debug("Could not locate final approval nodes for document " + documentId);
 788  
                 }
 789  0
             return false;
 790  
         }
 791  0
         Set finalApproverNodeNames = new HashSet();
 792  0
         for (Iterator iterator = finalApproverNodes.iterator(); iterator.hasNext();) {
 793  0
             RouteNode node = (RouteNode) iterator.next();
 794  0
             finalApproverNodeNames.add(node.getRouteNodeName());
 795  0
         }
 796  
 
 797  0
         int approveRequest = 0;
 798  0
         for (Iterator iter = requests.iterator(); iter.hasNext();) {
 799  0
             ActionRequestValue request = (ActionRequestValue) iter.next();
 800  0
             RouteNodeInstance nodeInstance = request.getNodeInstance();
 801  0
             if (nodeInstance == null) {
 802  0
                     if ( LOG.isDebugEnabled() ) {
 803  0
                             LOG.debug("Found an action request on the document with a null node instance, indicating EXCEPTION routing.");
 804  
                     }
 805  0
                 return false;
 806  
             }
 807  0
             if (finalApproverNodeNames.contains(nodeInstance.getRouteNode().getRouteNodeName())) {
 808  0
                 if (request.isApproveOrCompleteRequest()) {
 809  0
                     approveRequest++;
 810  0
                     if ( LOG.isDebugEnabled() ) {
 811  0
                             LOG.debug("Found request is approver " + request.getActionRequestId());
 812  
                     }
 813  0
                     if (! request.isRecipientRoutedRequest(principalId)) {
 814  0
                             if ( LOG.isDebugEnabled() ) {
 815  0
                                     LOG.debug("Action Request not for user " + principalId);
 816  
                             }
 817  0
                         return false;
 818  
                     }
 819  
                 }
 820  
             }
 821  0
         }
 822  
 
 823  0
         if (approveRequest == 0) {
 824  0
             return false;
 825  
         }
 826  0
         if ( LOG.isDebugEnabled() ) {
 827  0
                 LOG.debug("Principal "+principalId+" is final approver for document " + documentId);
 828  
         }
 829  0
         return true;
 830  
     }
 831  
 
 832  
     public boolean isSuperUserForDocumentType(String principalId, String documentTypeId) throws WorkflowException {
 833  0
             if ( LOG.isDebugEnabled() ) {
 834  0
                     LOG.debug("Determining super user status [principalId=" + principalId + ", documentTypeId=" + documentTypeId + "]");
 835  
             }
 836  0
             DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findById(documentTypeId);
 837  0
             boolean isSuperUser = KEWServiceLocator.getDocumentTypePermissionService().canAdministerRouting(principalId, documentType);
 838  0
             if ( LOG.isDebugEnabled() ) {
 839  0
                     LOG.debug("Super user status is " + isSuperUser + ".");
 840  
             }
 841  0
             return isSuperUser;
 842  
     }
 843  
 
 844  
     private DocumentRouteHeaderValue loadDocument(String documentId) {
 845  0
         return KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
 846  
     }
 847  
 
 848  
     public DocumentContentDTO getDocumentContent(String documentId) throws WorkflowException {
 849  0
             if ( LOG.isDebugEnabled() ) {
 850  0
                     LOG.debug("Fetching document content [docId=" + documentId + "]");
 851  
             }
 852  0
             DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
 853  0
             return DTOConverter.convertDocumentContent(document.getDocContent(), documentId);
 854  
     }
 855  
 
 856  
         public String[] getPreviousRouteNodeNames(String documentId) throws WorkflowException {
 857  0
                 if ( LOG.isDebugEnabled() ) {
 858  0
                         LOG.debug("Fetching previous node names [docId=" + documentId + "]");
 859  
                 }
 860  0
                 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
 861  
                 //going conservative for now.  if the doc isn't enroute or exception nothing will be returned.
 862  0
                 if (document.isEnroute() || document.isInException()) {
 863  
 
 864  
                         // TODO: KULRICE-5329 verify that the rewrite of the numeric logic below is reasonable -- I'm guessing it's not -- this one's a fairly radical change since I had to throw
 865  
                         // away the whole premise of using the longValue of the id as a strategy, so I think I'm massively oversimplifying the original goal of the logic
 866  0
                         List<RouteNodeInstance> routeNodeInstances = KEWServiceLocator.getRouteNodeService().getFlattenedNodeInstances(document, false);
 867  0
                         Set<String> routeNodeNames = new LinkedHashSet<String>();
 868  0
                         if (routeNodeInstances != null) {
 869  0
                                 for (RouteNodeInstance routeNodeInstance : routeNodeInstances) {
 870  0
                                         if (routeNodeInstance.isComplete()) {
 871  0
                                                 routeNodeNames.add(routeNodeInstance.getName());
 872  
                                         }
 873  
                                 }
 874  
                         }
 875  0
                         return routeNodeNames.toArray(new String[routeNodeNames.size()]);
 876  
                         
 877  
 //                        List<RouteNodeInstance> activeNodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document);
 878  
 //                        long largetActivatedNodeId = 0;
 879  
 //                        for (Iterator iter = activeNodeInstances.iterator(); iter.hasNext();) {
 880  
 //                                RouteNodeInstance routeNodeInstance = (RouteNodeInstance) iter.next();
 881  
 //                                if (routeNodeInstance.getRouteNode().getRouteNodeId().longValue() > largetActivatedNodeId) {
 882  
 //                                        largetActivatedNodeId = routeNodeInstance.getRouteNode().getRouteNodeId().longValue();
 883  
 //                                }
 884  
 //                        }
 885  
 //
 886  
 //                        List<RouteNodeInstance> routeNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodeInstances(document, false);
 887  
 //                        List<String> nodeNames = new ArrayList<String>();
 888  
 //
 889  
 //                        for (RouteNodeInstance routeNode : routeNodes) {
 890  
 //                                if (routeNode.isComplete() && !nodeNames.contains(routeNode.getName())) {
 891  
 //                                        //if the prototype of the nodeInstance we're analyzing is less than the largest id of all our active prototypes
 892  
 //                                        //then add it to the list.  This is an attempt to account for return to previous hitting a single node multiple times
 893  
 //                                        if (routeNode.getRouteNode().getRouteNodeId().longValue() < largetActivatedNodeId) {
 894  
 //                                                nodeNames.add(routeNode.getName());
 895  
 //                                        }
 896  
 //                                }
 897  
 //                        }
 898  
 //                        return (String[]) nodeNames.toArray(new String[nodeNames.size()]);
 899  
                 } else {
 900  0
                         return new String[0];
 901  
                 }
 902  
         }
 903  
 
 904  
     public RuleDTO[] ruleReport(RuleReportCriteriaDTO ruleReportCriteria) throws WorkflowException {
 905  0
         incomingParamCheck(ruleReportCriteria, "ruleReportCriteria");
 906  0
         if (ruleReportCriteria == null) {
 907  0
             throw new IllegalArgumentException("At least one criterion must be sent in a RuleReportCriteriaDTO object");
 908  
         }
 909  0
         if ( LOG.isDebugEnabled() ) {
 910  0
                 LOG.debug("Executing rule report [responsibleUser=" + ruleReportCriteria.getResponsiblePrincipalId() + ", responsibleWorkgroup=" +
 911  
                     ruleReportCriteria.getResponsibleGroupId() + "]");
 912  
         }
 913  0
         Map extensionValues = new HashMap();
 914  0
         if (ruleReportCriteria.getRuleExtensionVOs() != null) {
 915  0
             for (int i = 0; i < ruleReportCriteria.getRuleExtensionVOs().length; i++) {
 916  0
                 RuleExtensionDTO ruleExtensionVO = ruleReportCriteria.getRuleExtensionVOs()[i];
 917  0
                 KeyValue ruleExtension = DTOConverter.convertRuleExtensionVO(ruleExtensionVO);
 918  0
                 extensionValues.put(ruleExtension.getKey(), ruleExtension.getValue());
 919  
             }
 920  
         }
 921  0
         Collection<String> actionRequestCodes = new ArrayList<String>();
 922  0
         if ( (ruleReportCriteria.getActionRequestCodes() != null) && (ruleReportCriteria.getActionRequestCodes().length != 0) ) {
 923  0
             actionRequestCodes = Arrays.asList(ruleReportCriteria.getActionRequestCodes());
 924  
         }
 925  0
         Collection rulesFound = KEWServiceLocator.getRuleService().searchByTemplate(
 926  
                 ruleReportCriteria.getDocumentTypeName(), ruleReportCriteria.getRuleTemplateName(),
 927  
                 ruleReportCriteria.getRuleDescription(), ruleReportCriteria.getResponsibleGroupId(),
 928  
                 ruleReportCriteria.getResponsiblePrincipalId(), ruleReportCriteria.isConsiderWorkgroupMembership(),
 929  
                 ruleReportCriteria.isIncludeDelegations(), ruleReportCriteria.isActiveIndicator(), extensionValues,
 930  
                 actionRequestCodes);
 931  0
         RuleDTO[] returnableRules = new RuleDTO[rulesFound.size()];
 932  0
         int i = 0;
 933  0
         for (Iterator iter = rulesFound.iterator(); iter.hasNext();) {
 934  0
             RuleBaseValues rule = (RuleBaseValues) iter.next();
 935  0
             returnableRules[i] = DTOConverter.convertRule(rule);
 936  0
             i++;
 937  0
         }
 938  0
         return returnableRules;
 939  
     }
 940  
 
 941  
     public DocumentSearchResultDTO performDocumentSearch(DocumentSearchCriteriaDTO criteriaVO) throws WorkflowException {
 942  0
         return performDocumentSearchWithPrincipal(null, criteriaVO);
 943  
     }
 944  
 
 945  
     public DocumentSearchResultDTO performDocumentSearchWithPrincipal(String principalId, DocumentSearchCriteriaDTO criteriaVO) throws WorkflowException {
 946  0
         DocSearchCriteriaDTO criteria = DTOConverter.convertDocumentSearchCriteriaDTO(criteriaVO);
 947  0
         criteria.setOverridingUserSession(true);
 948  0
         if (principalId != null) {
 949  0
                 KEWServiceLocator.getIdentityHelperService().validatePrincipalId(principalId);
 950  
         } else {
 951  
                 // if the principal is null then we need to use the system "kr" user for execution of the search
 952  0
                 principalId = KEWServiceLocator.getIdentityHelperService().getSystemPrincipal().getPrincipalId();
 953  
         }
 954  0
         DocumentSearchResultComponents components = KEWServiceLocator.getDocumentSearchService().getListRestrictedByCriteria(principalId, criteria);
 955  0
         DocumentSearchResultDTO resultVO = DTOConverter.convertDocumentSearchResultComponents(components);
 956  0
         resultVO.setOverThreshold(criteria.isOverThreshold());
 957  0
         resultVO.setSecurityFilteredRows(Integer.valueOf(criteria.getSecurityFilteredRows()));
 958  0
         return resultVO;
 959  
     }
 960  
 
 961  
     /**
 962  
      * @see org.kuali.rice.kew.service.WorkflowUtility#getDocumentInitiatorPrincipalId(java.lang.Long)
 963  
      */
 964  
     public String getDocumentInitiatorPrincipalId(String documentId)
 965  
                     throws WorkflowException {
 966  0
         if (documentId == null) {
 967  0
             LOG.error("null documentId passed in.");
 968  0
             throw new RuntimeException("null documentId passed in.");
 969  
         }
 970  
 
 971  0
         DocumentRouteHeaderValue header = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId, false);
 972  0
         if ( header == null) {
 973  0
                 return null;
 974  
         }
 975  0
             return header.getInitiatorWorkflowId();
 976  
     }
 977  
     /**
 978  
      * @see org.kuali.rice.kew.service.WorkflowUtility#getDocumentRoutedByPrincipalId(java.lang.Long)
 979  
      */
 980  
     public String getDocumentRoutedByPrincipalId(String documentId)
 981  
                     throws WorkflowException {
 982  0
         if (documentId == null) {
 983  0
             LOG.error("null documentId passed in.");
 984  0
             throw new RuntimeException("null documentId passed in.");
 985  
         }
 986  
 
 987  0
         DocumentRouteHeaderValue header = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId, false);
 988  0
         if ( header == null) {
 989  0
                 return null;
 990  
         }
 991  0
             return header.getRoutedByUserWorkflowId();
 992  
     }
 993  
 
 994  
     /**
 995  
          *
 996  
          * @see org.kuali.rice.kew.service.WorkflowUtility#getSearchableAttributeDateTimeValuesByKey(java.lang.Long, java.lang.String)
 997  
          */
 998  
         public Timestamp[] getSearchableAttributeDateTimeValuesByKey(
 999  
                         String documentId, String key) {
 1000  0
                 List<Timestamp> results = KEWServiceLocator.getRouteHeaderService().getSearchableAttributeDateTimeValuesByKey(documentId, key);
 1001  0
                 if (ObjectUtils.isNull(results)) {
 1002  0
                         return null;
 1003  
                 }
 1004  0
                 return results.toArray(new Timestamp[]{});
 1005  
         }
 1006  
 
 1007  
         /**
 1008  
          *
 1009  
          * @see org.kuali.rice.kew.service.WorkflowUtility#getSearchableAttributeFloatValuesByKey(java.lang.Long, java.lang.String)
 1010  
          */
 1011  
         public BigDecimal[] getSearchableAttributeFloatValuesByKey(String documentId, String key) {
 1012  0
                 List<BigDecimal> results = KEWServiceLocator.getRouteHeaderService().getSearchableAttributeFloatValuesByKey(documentId, key);
 1013  0
                 if (ObjectUtils.isNull(results)) {
 1014  0
                         return null;
 1015  
                 }
 1016  0
                 return results.toArray(new BigDecimal[]{});
 1017  
         }
 1018  
 
 1019  
         /**
 1020  
          *
 1021  
          * @see org.kuali.rice.kew.service.WorkflowUtility#getSearchableAttributeLongValuesByKey(java.lang.Long, java.lang.String)
 1022  
          */
 1023  
         public Long[] getSearchableAttributeLongValuesByKey(String documentId, String key) {
 1024  0
                 List<Long> results = KEWServiceLocator.getRouteHeaderService().getSearchableAttributeLongValuesByKey(documentId, key);
 1025  0
                 if (ObjectUtils.isNull(results)) {
 1026  0
                         return null;
 1027  
                 }
 1028  0
                 return results.toArray(new Long[]{});
 1029  
         }
 1030  
 
 1031  
         /**
 1032  
          *
 1033  
          * @see org.kuali.rice.kew.service.WorkflowUtility#getSearchableAttributeStringValuesByKey(java.lang.Long, java.lang.String)
 1034  
          */
 1035  
         public String[] getSearchableAttributeStringValuesByKey(String documentId, String key) {
 1036  0
                 List<String> results = KEWServiceLocator.getRouteHeaderService().getSearchableAttributeStringValuesByKey(documentId, key);
 1037  0
                 if (ObjectUtils.isNull(results)) {
 1038  0
                         return null;
 1039  
                 }
 1040  0
                 return results.toArray(new String[]{});
 1041  
         }
 1042  
 
 1043  
     public String getFutureRequestsKey(String principalId) {
 1044  0
         return KEWConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_KEY + "," + principalId + "," + new Date().toString() + ", " + Math.random();
 1045  
     }
 1046  
 
 1047  
     public String getReceiveFutureRequestsValue() {
 1048  0
         return KEWConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_VALUE;
 1049  
     }
 1050  
 
 1051  
     public String getDoNotReceiveFutureRequestsValue() {
 1052  0
         return KEWConstants.DONT_RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_VALUE;
 1053  
     }
 1054  
 
 1055  
     public String getClearFutureRequestsValue() {
 1056  0
         return KEWConstants.CLEAR_FUTURE_REQUESTS_BRANCH_STATE_VALUE;
 1057  
     }
 1058  
         
 1059  
         public DocumentDetailDTO getDocumentDetailFromAppId(
 1060  
                         String documentTypeName, String appId) throws WorkflowException {
 1061  0
         if (documentTypeName == null) {
 1062  0
             LOG.error("null documentTypeName passed in.");
 1063  0
             throw new RuntimeException("null documentTypeName passed in");
 1064  
         }
 1065  0
         if (appId == null) {
 1066  0
             LOG.error("null appId passed in.");
 1067  0
             throw new RuntimeException("null appId passed in");
 1068  
         }
 1069  
         
 1070  0
         Collection documentIds = KEWServiceLocator.getRouteHeaderService().findByDocTypeAndAppId(documentTypeName, appId);
 1071  
         
 1072  0
         if(documentIds==null||documentIds.isEmpty()){
 1073  0
             LOG.error("No RouteHeader Ids found for criteria");
 1074  0
                     throw new WorkflowException("No RouteHeader Ids found for criteria");
 1075  
         }
 1076  0
         if(documentIds.size()>1){
 1077  0
             LOG.error("More than one RouteHeader Id found for criteria");
 1078  0
                     throw new WorkflowException("More than one RouteHeader Id found for criteria");
 1079  
                 }
 1080  
 
 1081  0
         return getDocumentDetail((String)documentIds.iterator().next());
 1082  
         }
 1083  
         
 1084  
         public String getAppDocId(String documentId) {
 1085  0
                   return KEWServiceLocator.getRouteHeaderService().getAppDocId(documentId);
 1086  
          }
 1087  
     
 1088  
     public DocumentStatusTransitionDTO[] getDocumentStatusTransitionHistory(String documentId) throws WorkflowException {
 1089  0
         if (documentId == null) {
 1090  0
             LOG.error("null documentId passed in.");
 1091  0
             throw new RuntimeException("null documentId passed in");
 1092  
         }
 1093  0
         if ( LOG.isDebugEnabled() ) {
 1094  0
             LOG.debug("Fetching document status transition history [id="+documentId+"]");
 1095  
         }
 1096  0
         DocumentRouteHeaderValue document = loadDocument(documentId);
 1097  
         
 1098  0
         UserSession userSession = GlobalVariables.getUserSession();
 1099  0
         String principalId = null;
 1100  0
         if (userSession != null) { // get the principalId if we can
 1101  0
                 principalId = userSession.getPrincipalId();
 1102  
         }
 1103  0
         List<DocumentStatusTransition> list = document.getAppDocStatusHistory();
 1104  
 
 1105  0
         DocumentStatusTransitionDTO[] transitionHistory = new DocumentStatusTransitionDTO[list.size()];        
 1106  0
         int i = 0;
 1107  0
         for (Object element : list) {
 1108  0
                 DocumentStatusTransition transition = (DocumentStatusTransition) element;
 1109  0
             transitionHistory[i] = DTOConverter.convertDocumentStatusTransition(transition);
 1110  0
             i++;
 1111  0
         }
 1112  0
         return transitionHistory;
 1113  
     }
 1114  
 
 1115  
         //for document link
 1116  
 
 1117  
         public void deleteDocumentLink(DocumentLinkDTO docLink) throws WorkflowException {
 1118  0
                 KEWServiceLocator.getDocumentLinkService().deleteDocumentLink(initDocLink(docLink));
 1119  0
         }
 1120  
 
 1121  
         /**
 1122  
          * This overridden method ...
 1123  
          * 
 1124  
          * @see org.kuali.rice.kew.routeheader.service.WorkflowDocumentService#addDocumentLink(org.kuali.rice.kew.documentlink.DocumentLink)
 1125  
          */
 1126  
         public void addDocumentLink(DocumentLinkDTO docLinkVO) throws WorkflowException {
 1127  0
                 KEWServiceLocator.getDocumentLinkService().saveDocumentLink(initDocLink(docLinkVO));
 1128  0
         }
 1129  
 
 1130  
         /**
 1131  
          * This overridden method ...
 1132  
          * 
 1133  
          * @see org.kuali.rice.kew.routeheader.service.WorkflowDocumentService#getgetLinkedDocumentsByDocId(java.lang.Long)
 1134  
          */
 1135  
         public List<DocumentLinkDTO> getLinkedDocumentsByDocId(String documentId) throws WorkflowException {
 1136  0
                 return DTOConverter.convertDocumentLinkToArrayList(KEWServiceLocator.getDocumentLinkService().getLinkedDocumentsByDocId(documentId));
 1137  
         }
 1138  
 
 1139  
         /**
 1140  
          * This overridden method ...
 1141  
          * 
 1142  
          * @see org.kuali.rice.kew.routeheader.service.WorkflowDocumentService#getDocumentLink(org.kuali.rice.kew.documentlink.DocumentLink)
 1143  
          */
 1144  
         public DocumentLinkDTO getLinkedDocument(DocumentLinkDTO docLinkVO) throws WorkflowException{
 1145  0
                 return DTOConverter.convertDocumentLink(KEWServiceLocator.getDocumentLinkService().getLinkedDocument(initDocLink(docLinkVO)));
 1146  
         }
 1147  
 
 1148  
         /**
 1149  
          * This overridden method ...
 1150  
          * 
 1151  
          * @see org.kuali.rice.kew.routeheader.service.WorkflowDocumentService#deleteDocumentLinkByDocId(java.lang.Long)
 1152  
          */
 1153  
         public void deleteDocumentLinksByDocId(String documentId) throws WorkflowException{
 1154  0
                 KEWServiceLocator.getDocumentLinkService().deleteDocumentLinksByDocId(documentId);
 1155  0
         }
 1156  
 
 1157  
         private DocumentLink initDocLink(DocumentLinkDTO docLinkVO){
 1158  0
                 DocumentLink docLink = new DocumentLink();
 1159  0
                 docLink.setDocLinkId(docLinkVO.getLinbkId());
 1160  0
                 docLink.setOrgnDocId(docLinkVO.getOrgnDocId());
 1161  0
                 docLink.setDestDocId(docLinkVO.getDestDocId());
 1162  
 
 1163  0
                 return docLink;
 1164  
         }
 1165  
 }