Coverage Report - org.kuali.rice.kns.workflow.service.impl.WorkflowDocumentServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
WorkflowDocumentServiceImpl
0%
0/154
0%
0/84
3.417
 
 1  
 /*
 2  
  * Copyright 2005-2007 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  
 package org.kuali.rice.kns.workflow.service.impl;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.exception.RiceRuntimeException;
 20  
 import org.kuali.rice.kew.dto.NetworkIdDTO;
 21  
 import org.kuali.rice.kew.dto.RouteNodeInstanceDTO;
 22  
 import org.kuali.rice.kew.dto.UserIdDTO;
 23  
 import org.kuali.rice.kew.exception.DocumentTypeNotFoundException;
 24  
 import org.kuali.rice.kew.exception.InvalidActionTakenException;
 25  
 import org.kuali.rice.kew.exception.WorkflowException;
 26  
 import org.kuali.rice.kew.service.WorkflowInfo;
 27  
 import org.kuali.rice.kew.util.KEWConstants;
 28  
 import org.kuali.rice.kim.bo.Group;
 29  
 import org.kuali.rice.kim.bo.Person;
 30  
 import org.kuali.rice.kim.bo.entity.KimPrincipal;
 31  
 import org.kuali.rice.kim.service.KIMServiceLocator;
 32  
 import org.kuali.rice.kns.bo.AdHocRouteRecipient;
 33  
 import org.kuali.rice.kns.exception.UnknownDocumentIdException;
 34  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 35  
 import org.kuali.rice.kns.util.GlobalVariables;
 36  
 import org.kuali.rice.kns.util.RiceKeyConstants;
 37  
 import org.kuali.rice.kns.util.Timer;
 38  
 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
 39  
 import org.kuali.rice.kns.workflow.service.KualiWorkflowInfo;
 40  
 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
 41  
 import org.springframework.transaction.annotation.Transactional;
 42  
 
 43  
 import java.text.MessageFormat;
 44  
 import java.util.ArrayList;
 45  
 import java.util.Iterator;
 46  
 import java.util.List;
 47  
 
 48  
 
 49  
 /**
 50  
  * This class is the implementation of the WorkflowDocumentService, which makes use of Workflow.
 51  
  */
 52  
 @Transactional
 53  0
 public class WorkflowDocumentServiceImpl implements WorkflowDocumentService {
 54  0
     private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(WorkflowDocumentServiceImpl.class);
 55  
 
 56  
     private KualiWorkflowInfo workflowInfoService;
 57  
 
 58  
     public boolean workflowDocumentExists(String documentHeaderId) {
 59  0
         boolean exists = false;
 60  
 
 61  0
         if (StringUtils.isBlank(documentHeaderId)) {
 62  0
             throw new IllegalArgumentException("invalid (blank) documentHeaderId");
 63  
         }
 64  
 
 65  0
         Long routeHeaderId = null;
 66  
         try {
 67  0
             routeHeaderId = new Long(documentHeaderId);
 68  
         }
 69  0
         catch (NumberFormatException e) {
 70  0
             throw new IllegalArgumentException("cannot convert '" + documentHeaderId + "' into a Long");
 71  0
         }
 72  
 
 73  0
         exists = workflowInfoService.routeHeaderExists(routeHeaderId);
 74  
 
 75  0
         return exists;
 76  
     }
 77  
 
 78  
     /**
 79  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#createWorkflowDocument(java.lang.String,
 80  
      *      org.kuali.rice.kew.user.WorkflowUser)
 81  
      */
 82  
     public KualiWorkflowDocument createWorkflowDocument(String documentTypeId, Person person) throws WorkflowException {
 83  0
         Timer t0 = new Timer("createWorkflowDocument");
 84  
 
 85  0
         if (StringUtils.isBlank(documentTypeId)) {
 86  0
             throw new IllegalArgumentException("invalid (blank) documentTypeId");
 87  
         }
 88  0
         if (person == null) {
 89  0
             throw new IllegalArgumentException("invalid (null) person");
 90  
         }
 91  
 
 92  0
         if ((null == person) || StringUtils.isBlank(person.getPrincipalName())) {
 93  0
             throw new IllegalArgumentException("invalid (empty) authenticationUserId");
 94  
         }
 95  
 
 96  0
         if (LOG.isDebugEnabled()) {
 97  0
             LOG.debug("creating workflowDoc(" + documentTypeId + "," + person.getPrincipalName() + ")");
 98  
         }
 99  
 
 100  0
         KualiWorkflowDocument document = new KualiWorkflowDocumentImpl(getUserIdVO(person), documentTypeId);
 101  
 
 102  
         // workflow doesn't complain about invalid docTypes until the first call to getRouteHeaderId, but the rest of our code
 103  
         // assumes that you get the exception immediately upon trying to create a document of that invalid type
 104  
         //
 105  
         // and it throws the generic WorkflowException, apparently, instead of the more specific DocumentTypeNotFoundException,
 106  
         // so as long as I'm here I'll do that conversion as well
 107  
         try {
 108  0
             document.getRouteHeaderId();
 109  
         }
 110  0
         catch (WorkflowException e) {
 111  0
             if (e.getMessage().contains("Could not locate the given document type name")) {
 112  0
                 throw new DocumentTypeNotFoundException("unknown document type '" + documentTypeId + "'");
 113  
             }
 114  
             else {
 115  0
                 throw e;
 116  
             }
 117  0
         }
 118  
 
 119  0
         t0.log();
 120  
 
 121  0
         return document;
 122  
     }
 123  
 
 124  
     /**
 125  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#createWorkflowDocument(java.lang.Long,
 126  
      *      org.kuali.rice.kew.user.WorkflowUser)
 127  
      */
 128  
     public KualiWorkflowDocument createWorkflowDocument(Long documentHeaderId, Person user) throws WorkflowException {
 129  0
         if (documentHeaderId == null) {
 130  0
             throw new IllegalArgumentException("invalid (null) documentHeaderId");
 131  
         }
 132  0
         if (user == null) {
 133  0
             throw new IllegalArgumentException("invalid (null) workflowUser");
 134  
         }
 135  0
         else if (StringUtils.isEmpty(user.getPrincipalName())) {
 136  0
             throw new IllegalArgumentException("invalid (empty) workflowUser");
 137  
         }
 138  
 
 139  0
         if (LOG.isDebugEnabled()) {
 140  0
             LOG.debug("retrieving document(" + documentHeaderId + "," + user.getPrincipalName() + ")");
 141  
         }
 142  
 
 143  0
         KualiWorkflowDocument document = new KualiWorkflowDocumentImpl(getUserIdVO(user), documentHeaderId);
 144  0
         if (document.getRouteHeader() == null) {
 145  0
             throw new UnknownDocumentIdException("unable to locate document with documentHeaderId '" + documentHeaderId + "'");
 146  
         }
 147  0
         return document;
 148  
     }
 149  
 
 150  
     /**
 151  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#acknowledge(org.kuali.rice.kew.rule.FlexDoc)
 152  
      */
 153  
     public void acknowledge(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients) throws WorkflowException {
 154  0
         if (LOG.isDebugEnabled()) {
 155  0
             LOG.debug("acknowleding document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 156  
         }
 157  
 
 158  0
         handleAdHocRouteRequests(workflowDocument, annotation, filterAdHocRecipients(adHocRecipients, new String[] { KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KEWConstants.ACTION_REQUEST_FYI_REQ }));
 159  0
         workflowDocument.acknowledge(annotation);
 160  0
     }
 161  
 
 162  
     /**
 163  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#approve(org.kuali.rice.kew.rule.FlexDoc)
 164  
      */
 165  
     public void approve(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients) throws WorkflowException {
 166  0
         if (LOG.isDebugEnabled()) {
 167  0
             LOG.debug("approving document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 168  
         }
 169  
 
 170  0
         handleAdHocRouteRequests(workflowDocument, annotation, filterAdHocRecipients(adHocRecipients, new String[] { KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KEWConstants.ACTION_REQUEST_FYI_REQ, KEWConstants.ACTION_REQUEST_APPROVE_REQ }));
 171  0
         workflowDocument.approve(annotation);
 172  0
     }
 173  
 
 174  
 
 175  
     /**
 176  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#superUserApprove(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument,
 177  
      *      java.lang.String)
 178  
      */
 179  
     public void superUserApprove(KualiWorkflowDocument workflowDocument, String annotation) throws WorkflowException {
 180  0
             if ( LOG.isInfoEnabled() ) {
 181  0
                     LOG.info("super user approve document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 182  
             }
 183  0
         workflowDocument.superUserApprove(annotation);
 184  0
     }
 185  
 
 186  
     /**
 187  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#superUserCancel(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument,
 188  
      *      java.lang.String)
 189  
      */
 190  
     public void superUserCancel(KualiWorkflowDocument workflowDocument, String annotation) throws WorkflowException {
 191  0
         LOG.info("super user cancel document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 192  0
         workflowDocument.superUserCancel(annotation);
 193  0
     }
 194  
 
 195  
     /**
 196  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#superUserDisapprove(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument,
 197  
      *      java.lang.String)
 198  
      */
 199  
     public void superUserDisapprove(KualiWorkflowDocument workflowDocument, String annotation) throws WorkflowException {
 200  0
             if ( LOG.isInfoEnabled() ) {
 201  0
                     LOG.info("super user disapprove document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 202  
             }
 203  0
         workflowDocument.superUserDisapprove(annotation);
 204  0
     }
 205  
 
 206  
     /**
 207  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#blanketApprove(org.kuali.rice.kew.rule.FlexDoc)
 208  
      */
 209  
     public void blanketApprove(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients) throws WorkflowException {
 210  0
         if (LOG.isDebugEnabled()) {
 211  0
             LOG.debug("blanket approving document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 212  
         }
 213  
 
 214  0
         handleAdHocRouteRequests(workflowDocument, annotation, filterAdHocRecipients(adHocRecipients, new String[] { KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KEWConstants.ACTION_REQUEST_FYI_REQ }));
 215  0
         workflowDocument.blanketApprove(annotation);
 216  0
     }
 217  
 
 218  
     /**
 219  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#cancel(org.kuali.rice.kew.rule.FlexDoc)
 220  
      */
 221  
     public void cancel(KualiWorkflowDocument workflowDocument, String annotation) throws WorkflowException {
 222  0
         if (LOG.isDebugEnabled()) {
 223  0
             LOG.debug("canceling document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 224  
         }
 225  
 
 226  0
         workflowDocument.cancel(annotation);
 227  0
     }
 228  
 
 229  
     /**
 230  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#clearFyi(org.kuali.rice.kew.rule.FlexDoc)
 231  
      */
 232  
     public void clearFyi(KualiWorkflowDocument workflowDocument, List adHocRecipients) throws WorkflowException {
 233  0
         if (LOG.isDebugEnabled()) {
 234  0
             LOG.debug("clearing FYI for document(" + workflowDocument.getRouteHeaderId() + ")");
 235  
         }
 236  
 
 237  0
         handleAdHocRouteRequests(workflowDocument, "", filterAdHocRecipients(adHocRecipients, new String[] { KEWConstants.ACTION_REQUEST_FYI_REQ }));
 238  0
         workflowDocument.fyi();
 239  0
     }
 240  
 
 241  
     public void sendWorkflowNotification(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients) throws WorkflowException {
 242  0
             sendWorkflowNotification(workflowDocument, annotation, adHocRecipients, null);
 243  0
     }
 244  
     
 245  
     /**
 246  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#sendWorkflowNotification(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument, java.lang.String, java.util.List)
 247  
      */
 248  
     public void sendWorkflowNotification(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients, String notificationLabel) throws WorkflowException {
 249  0
         if (LOG.isDebugEnabled()) {
 250  0
             LOG.debug("sending FYI for document(" + workflowDocument.getRouteHeaderId() + ")");
 251  
         }
 252  
 
 253  0
         handleAdHocRouteRequests(workflowDocument, annotation, adHocRecipients, notificationLabel);
 254  0
     }
 255  
 
 256  
     /**
 257  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#disapprove(org.kuali.rice.kew.rule.FlexDoc)
 258  
      */
 259  
     public void disapprove(KualiWorkflowDocument workflowDocument, String annotation) throws WorkflowException {
 260  0
         if (LOG.isDebugEnabled()) {
 261  0
             LOG.debug("disapproving document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 262  
         }
 263  
 
 264  0
         workflowDocument.disapprove(annotation);
 265  0
     }
 266  
 
 267  
     /**
 268  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#route(org.kuali.rice.kew.rule.FlexDoc)
 269  
      */
 270  
     public void route(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients) throws WorkflowException {
 271  0
         if (LOG.isDebugEnabled()) {
 272  0
             LOG.debug("routing document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 273  
         }
 274  
 
 275  0
         handleAdHocRouteRequests(workflowDocument, annotation, filterAdHocRecipients(adHocRecipients, new String[] { KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KEWConstants.ACTION_REQUEST_FYI_REQ, KEWConstants.ACTION_REQUEST_APPROVE_REQ }));
 276  0
         workflowDocument.routeDocument(annotation);
 277  0
     }
 278  
 
 279  
     /**
 280  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#save(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument, java.lang.String)
 281  
      */
 282  
     public void save(KualiWorkflowDocument workflowDocument, String annotation) throws WorkflowException {
 283  0
         if (workflowDocument.isStandardSaveAllowed()) {
 284  0
         if (LOG.isDebugEnabled()) {
 285  0
             LOG.debug("saving document(" + workflowDocument.getRouteHeaderId() + ",'" + annotation + "')");
 286  
         }
 287  
 
 288  0
         workflowDocument.saveDocument(annotation);
 289  
     }
 290  
         else {
 291  0
             this.saveRoutingData(workflowDocument);
 292  
         }
 293  0
     }
 294  
 
 295  
     /**
 296  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#saveRoutingData(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument)
 297  
      */
 298  
     public void saveRoutingData(KualiWorkflowDocument workflowDocument) throws WorkflowException {
 299  0
         if (LOG.isDebugEnabled()) {
 300  0
             LOG.debug("saving document(" + workflowDocument.getRouteHeaderId() + ")");
 301  
         }
 302  
 
 303  0
         workflowDocument.saveRoutingData();
 304  0
     }
 305  
 
 306  
     /**
 307  
      * @see org.kuali.rice.kns.workflow.service.WorkflowDocumentService#getCurrentRouteLevelName(org.kuali.rice.kns.workflow.service.KualiWorkflowDocument)
 308  
      */
 309  
     public String getCurrentRouteLevelName(KualiWorkflowDocument workflowDocument) throws WorkflowException {
 310  0
         if (LOG.isDebugEnabled()) {
 311  0
             LOG.debug("getting current route level name for document(" + workflowDocument.getRouteHeaderId());
 312  
         }
 313  
 //        return KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getRouteHeaderId()).getCurrentRouteLevelName();
 314  0
         KualiWorkflowDocument freshCopyWorkflowDoc = createWorkflowDocument(workflowDocument.getRouteHeaderId(), GlobalVariables.getUserSession().getPerson());
 315  0
         return freshCopyWorkflowDoc.getCurrentRouteNodeNames();
 316  
     }
 317  
 
 318  
     private void handleAdHocRouteRequests(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients) throws WorkflowException {
 319  0
             handleAdHocRouteRequests(workflowDocument, annotation, adHocRecipients, null);
 320  0
     }
 321  
     
 322  
     /**
 323  
      * Convenience method for generating ad hoc requests for a given document
 324  
      *
 325  
      * @param flexDoc
 326  
      * @param annotation
 327  
      * @param adHocRecipients
 328  
      * @throws InvalidActionTakenException
 329  
      * @throws InvalidRouteTypeException
 330  
      * @throws InvalidActionRequestException
 331  
      */
 332  
     private void handleAdHocRouteRequests(KualiWorkflowDocument workflowDocument, String annotation, List adHocRecipients, String notificationLabel) throws WorkflowException {
 333  
 
 334  0
         if (adHocRecipients != null && adHocRecipients.size() > 0) {
 335  0
             String currentNode = null;
 336  0
             String[] currentNodes = workflowDocument.getNodeNames();
 337  0
             if (currentNodes.length == 0) {
 338  0
                 WorkflowInfo workflowInfo = new WorkflowInfo();
 339  0
                 RouteNodeInstanceDTO[] nodes = workflowInfo.getTerminalNodeInstances(workflowDocument.getRouteHeaderId());
 340  0
                 currentNodes = new String[nodes.length];
 341  0
                 for (int nodeIndex = 0; nodeIndex < nodes.length; nodeIndex++) {
 342  0
                     currentNodes[nodeIndex] = nodes[nodeIndex].getName();
 343  
                 }
 344  
             }
 345  
             // for now just pick a node and go with it...
 346  0
             for (int i = 0; i < currentNodes.length; i++) {
 347  0
                 currentNode = currentNodes[i];
 348  
             }
 349  
 
 350  0
             for (Iterator iter = adHocRecipients.iterator(); iter.hasNext();) {
 351  0
                 AdHocRouteRecipient recipient = (AdHocRouteRecipient) iter.next();
 352  0
                 if (StringUtils.isNotEmpty(recipient.getId())) {
 353  0
                         if ( StringUtils.isBlank( annotation ) ) {
 354  
                                 try {
 355  0
                                         String message = KNSServiceLocator.getKualiConfigurationService().getPropertyString(RiceKeyConstants.MESSAGE_ADHOC_ANNOTATION);                                
 356  0
                                         annotation = MessageFormat.format(message, GlobalVariables.getUserSession().getPrincipalName() );
 357  0
                                 } catch ( Exception ex ) {
 358  0
                                         LOG.warn("Unable to set annotation", ex );
 359  0
                                 }
 360  
                         }
 361  0
                     if (AdHocRouteRecipient.PERSON_TYPE.equals(recipient.getType())) {
 362  
                         // TODO make the 1 a constant
 363  0
                             KimPrincipal principal = KIMServiceLocator.getIdentityManagementService().getPrincipalByPrincipalName(recipient.getId());
 364  0
                                 if (principal == null) {
 365  0
                                         throw new RiceRuntimeException("Could not locate principal with name '" + recipient.getId() + "'");
 366  
                                 }
 367  0
                         workflowDocument.adHocRouteDocumentToPrincipal(recipient.getActionRequested(), currentNode, annotation, principal.getPrincipalId(), "", true, notificationLabel);
 368  0
                     }
 369  
                     else {
 370  0
                             Group group = KIMServiceLocator.getIdentityManagementService().getGroup(recipient.getId());
 371  0
                                 if (group == null) {
 372  0
                                         throw new RiceRuntimeException("Could not locate group with id '" + recipient.getId() + "'");
 373  
                                 }
 374  0
                             workflowDocument.adHocRouteDocumentToGroup(recipient.getActionRequested(), currentNode, annotation, group.getGroupId() , "", true, notificationLabel);
 375  
                     }
 376  
                 }
 377  0
             }
 378  
         }
 379  0
     }
 380  
 
 381  
     /**
 382  
      * Convenience method to filter out any ad hoc recipients that should not be allowed given the action requested of the user that
 383  
      * is taking action on the document
 384  
      *
 385  
      * @param adHocRecipients
 386  
      */
 387  
     private List filterAdHocRecipients(List adHocRecipients, String[] validTypes) {
 388  
         // now filter out any but ack or fyi from the ad hoc list
 389  0
         List realAdHocRecipients = new ArrayList();
 390  0
         if (adHocRecipients != null) {
 391  0
             for (Iterator iter = adHocRecipients.iterator(); iter.hasNext();) {
 392  0
                 AdHocRouteRecipient proposedRecipient = (AdHocRouteRecipient) iter.next();
 393  0
                 if (StringUtils.isNotBlank(proposedRecipient.getActionRequested())) {
 394  0
                     for (int i = 0; i < validTypes.length; i++) {
 395  0
                         if (validTypes[i].equals(proposedRecipient.getActionRequested())) {
 396  0
                             realAdHocRecipients.add(proposedRecipient);
 397  
                         }
 398  
                     }
 399  
                 }
 400  0
             }
 401  
         }
 402  0
         return realAdHocRecipients;
 403  
     }
 404  
 
 405  
     private UserIdDTO getUserIdVO(Person user) {
 406  0
         return new NetworkIdDTO(user.getPrincipalName());
 407  
     }
 408  
 
 409  
 
 410  
     public void setWorkflowInfoService(KualiWorkflowInfo workflowInfoService) {
 411  0
         this.workflowInfoService = workflowInfoService;
 412  0
     }
 413  
 
 414  
     public KualiWorkflowInfo getWorkflowInfoService() {
 415  0
         return workflowInfoService;
 416  
     }
 417  
 }