Coverage Report - org.kuali.rice.kew.impl.document.WorkflowDocumentImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
WorkflowDocumentImpl
0%
0/290
0%
0/62
1.316
WorkflowDocumentImpl$ModifiableDocument
0%
0/31
0%
0/2
1.316
WorkflowDocumentImpl$ModifiableDocumentContent
0%
0/46
0%
0/2
1.316
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  *
 4  
  *
 5  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  * http://www.opensource.org/licenses/ecl2.php
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.kuali.rice.kew.impl.document;
 18  
 
 19  
 import java.io.Serializable;
 20  
 import java.util.Arrays;
 21  
 import java.util.Collections;
 22  
 import java.util.Date;
 23  
 import java.util.HashSet;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Set;
 27  
 
 28  
 import org.apache.commons.lang.StringUtils;
 29  
 import org.joda.time.DateTime;
 30  
 import org.kuali.rice.kew.api.KewApiConstants;
 31  
 import org.kuali.rice.kew.api.KewApiServiceLocator;
 32  
 import org.kuali.rice.kew.api.action.ActionRequest;
 33  
 import org.kuali.rice.kew.api.action.ActionRequestType;
 34  
 import org.kuali.rice.kew.api.action.ActionTaken;
 35  
 import org.kuali.rice.kew.api.action.ActionType;
 36  
 import org.kuali.rice.kew.api.action.AdHocRevoke;
 37  
 import org.kuali.rice.kew.api.action.AdHocToGroup;
 38  
 import org.kuali.rice.kew.api.action.AdHocToPrincipal;
 39  
 import org.kuali.rice.kew.api.action.DocumentActionParameters;
 40  
 import org.kuali.rice.kew.api.action.DocumentActionResult;
 41  
 import org.kuali.rice.kew.api.action.MovePoint;
 42  
 import org.kuali.rice.kew.api.action.RequestedActions;
 43  
 import org.kuali.rice.kew.api.action.ReturnPoint;
 44  
 import org.kuali.rice.kew.api.action.ValidActions;
 45  
 import org.kuali.rice.kew.api.action.WorkflowDocumentActionsService;
 46  
 import org.kuali.rice.kew.api.document.Document;
 47  
 import org.kuali.rice.kew.api.document.DocumentContent;
 48  
 import org.kuali.rice.kew.api.document.DocumentContentUpdate;
 49  
 import org.kuali.rice.kew.api.document.DocumentDetail;
 50  
 import org.kuali.rice.kew.api.document.DocumentStatus;
 51  
 import org.kuali.rice.kew.api.document.DocumentUpdate;
 52  
 import org.kuali.rice.kew.api.document.RouteNodeInstance;
 53  
 import org.kuali.rice.kew.api.document.WorkflowAttributeDefinition;
 54  
 import org.kuali.rice.kew.api.document.WorkflowAttributeValidationError;
 55  
 import org.kuali.rice.kew.api.document.WorkflowDocumentService;
 56  
 
 57  
 /**
 58  
  * TODO ..
 59  
  * 
 60  
  * TODO - it is intended that operations against document data on this are only "flushed" when an
 61  
  * action is performed...
 62  
  * 
 63  
  * <p>
 64  
  * This class is *not* thread safe.
 65  
  * 
 66  
  */
 67  0
 public class WorkflowDocumentImpl implements Serializable, WorkflowDocumentPrototype {
 68  
 
 69  
     private static final long serialVersionUID = -3672966990721719088L;
 70  
 
 71  
     private String principalId;
 72  
     private ModifiableDocument modifiableDocument;
 73  
     private ModifiableDocumentContent modifiableDocumentContent;
 74  
     private ValidActions validActions;
 75  
     private RequestedActions requestedActions;
 76  
 
 77  0
     private boolean documentDeleted = false;
 78  
 
 79  
     private transient WorkflowDocumentActionsService workflowDocumentActionsService;
 80  
     private transient WorkflowDocumentService workflowDocumentService;
 81  
 
 82  
     public void init(String principalId, Document document) {
 83  0
         if (StringUtils.isBlank("principalId")) {
 84  0
             throw new IllegalArgumentException("principalId was null or blank");
 85  
         }
 86  0
         if (document == null) {
 87  0
             throw new IllegalArgumentException("document was null");
 88  
         }
 89  0
         this.principalId = principalId;
 90  0
         this.modifiableDocument = new ModifiableDocument(document);
 91  0
         this.modifiableDocumentContent = null;
 92  0
         this.validActions = null;
 93  0
         this.requestedActions = null;
 94  0
     }
 95  
 
 96  
     public WorkflowDocumentActionsService getWorkflowDocumentActionsService() {
 97  0
         if (workflowDocumentActionsService == null) {
 98  0
             workflowDocumentActionsService = KewApiServiceLocator.getWorkflowDocumentActionsService();
 99  
         }
 100  0
         return workflowDocumentActionsService;
 101  
     }
 102  
 
 103  
     public void setWorkflowDocumentActionsService(WorkflowDocumentActionsService workflowDocumentActionsService) {
 104  0
         this.workflowDocumentActionsService = workflowDocumentActionsService;
 105  0
     }
 106  
 
 107  
     public WorkflowDocumentService getWorkflowDocumentService() {
 108  0
         if (workflowDocumentService == null) {
 109  0
             workflowDocumentService = KewApiServiceLocator.getWorkflowDocumentService();
 110  
         }
 111  0
         return workflowDocumentService;
 112  
     }
 113  
 
 114  
     public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
 115  0
         this.workflowDocumentService = workflowDocumentService;
 116  0
     }
 117  
 
 118  
     protected ModifiableDocument getModifiableDocument() {
 119  0
         return modifiableDocument;
 120  
     }
 121  
 
 122  
     protected ModifiableDocumentContent getModifiableDocumentContent() {
 123  0
         if (this.modifiableDocumentContent == null) {
 124  0
             DocumentContent documentContent = getWorkflowDocumentService().getDocumentContent(getDocumentId());
 125  0
             if (documentContent == null) {
 126  0
                 throw new IllegalStateException("Failed to load document content for documentId: " + getDocumentId());
 127  
             }
 128  0
             this.modifiableDocumentContent = new ModifiableDocumentContent(documentContent);
 129  
         }
 130  0
         return this.modifiableDocumentContent;
 131  
     }
 132  
 
 133  
     @Override
 134  
     public String getDocumentId() {
 135  0
         if (documentDeleted) {
 136  0
             throw new IllegalStateException("Document has been deleted.");
 137  
         }
 138  0
         return getModifiableDocument().getDocumentId();
 139  
     }
 140  
 
 141  
     @Override
 142  
     public Document getDocument() {
 143  0
         return getModifiableDocument().getDocument();
 144  
     }
 145  
 
 146  
     @Override
 147  
     public DocumentContent getDocumentContent() {
 148  0
         return getModifiableDocumentContent().getDocumentContent();
 149  
     }
 150  
 
 151  
     @Override
 152  
     public String getApplicationContent() {
 153  0
         return getDocumentContent().getApplicationContent();
 154  
     }
 155  
 
 156  
     @Override
 157  
     public void setApplicationContent(String applicationContent) {
 158  0
         getModifiableDocumentContent().setApplicationContent(applicationContent);
 159  0
     }
 160  
     
 161  
     @Override
 162  
     public void setAttributeContent(String attributeContent) {
 163  0
         getModifiableDocumentContent().setAttributeContent(attributeContent);
 164  0
     }
 165  
 
 166  
     @Override
 167  
     public void clearAttributeContent() {
 168  0
         getModifiableDocumentContent().setAttributeContent("");
 169  0
     }
 170  
 
 171  
     @Override
 172  
     public String getAttributeContent() {
 173  0
         return getDocumentContent().getAttributeContent();
 174  
     }
 175  
 
 176  
     @Override
 177  
     public void addAttributeDefinition(WorkflowAttributeDefinition attributeDefinition) {
 178  0
         getModifiableDocumentContent().addAttributeDefinition(attributeDefinition);
 179  0
     }
 180  
 
 181  
     @Override
 182  
     public void removeAttributeDefinition(WorkflowAttributeDefinition attributeDefinition) {
 183  0
         getModifiableDocumentContent().removeAttributeDefinition(attributeDefinition);
 184  0
     }
 185  
 
 186  
     @Override
 187  
     public void clearAttributeDefinitions() {
 188  0
         getAttributeDefinitions().clear();
 189  0
     }
 190  
 
 191  
     @Override
 192  
     public List<WorkflowAttributeDefinition> getAttributeDefinitions() {
 193  0
         return getModifiableDocumentContent().getAttributeDefinitions();
 194  
     }
 195  
 
 196  
     @Override
 197  
     public void setSearchableContent(String searchableContent) {
 198  0
         getModifiableDocumentContent().setSearchableContent(searchableContent);
 199  0
     }
 200  
     
 201  
     @Override
 202  
     public void addSearchableDefinition(WorkflowAttributeDefinition searchableDefinition) {
 203  0
         getModifiableDocumentContent().addSearchableDefinition(searchableDefinition);
 204  0
     }
 205  
 
 206  
     @Override
 207  
     public void removeSearchableDefinition(WorkflowAttributeDefinition searchableDefinition) {
 208  0
         getModifiableDocumentContent().removeSearchableDefinition(searchableDefinition);
 209  0
     }
 210  
 
 211  
     @Override
 212  
     public void clearSearchableDefinitions() {
 213  0
         getSearchableDefinitions().clear();
 214  0
     }
 215  
 
 216  
     @Override
 217  
     public void clearSearchableContent() {
 218  0
         getModifiableDocumentContent().setSearchableContent("");
 219  0
     }
 220  
 
 221  
     @Override
 222  
     public List<WorkflowAttributeDefinition> getSearchableDefinitions() {
 223  0
         return getModifiableDocumentContent().getSearchableDefinitions();
 224  
     }
 225  
 
 226  
     @Override
 227  
     public List<WorkflowAttributeValidationError> validateAttributeDefinition(
 228  
             WorkflowAttributeDefinition attributeDefinition) {
 229  0
         return getWorkflowDocumentActionsService().validateWorkflowAttributeDefinition(attributeDefinition);
 230  
     }
 231  
 
 232  
     @Override
 233  
     public List<ActionRequest> getRootActionRequests() {
 234  0
         return getWorkflowDocumentService().getRootActionRequests(getDocumentId());
 235  
     }
 236  
 
 237  
     @Override
 238  
     public List<ActionTaken> getActionsTaken() {
 239  0
         return getWorkflowDocumentService().getActionsTaken(getDocumentId());
 240  
     }
 241  
 
 242  
     @Override
 243  
     public void setApplicationDocumentId(String applicationDocumentId) {
 244  0
         getModifiableDocument().setApplicationDocumentId(applicationDocumentId);
 245  0
     }
 246  
 
 247  
     @Override
 248  
     public String getApplicationDocumentId() {
 249  0
         return getModifiableDocument().getApplicationDocumentId();
 250  
     }
 251  
 
 252  
     @Override
 253  
     public DateTime getDateCreated() {
 254  0
         return getModifiableDocument().getDateCreated();
 255  
     }
 256  
 
 257  
     @Override
 258  
     public String getTitle() {
 259  0
         return getModifiableDocument().getTitle();
 260  
     }
 261  
 
 262  
     @Override
 263  
     public ValidActions getValidActions() {
 264  0
         if (validActions == null) {
 265  0
             validActions = getWorkflowDocumentActionsService().determineValidActions(getDocumentId(), getPrincipalId());
 266  
         }
 267  0
         return validActions;
 268  
     }
 269  
 
 270  
     @Override
 271  
     public RequestedActions getRequestedActions() {
 272  0
         if (requestedActions == null) {
 273  0
             requestedActions = getWorkflowDocumentActionsService().determineRequestedActions(getDocumentId(),
 274  
                     getPrincipalId());
 275  
         }
 276  0
         return requestedActions;
 277  
     }
 278  
 
 279  
     protected DocumentUpdate getDocumentUpdateIfDirty() {
 280  0
         if (getModifiableDocument().isDirty()) {
 281  0
             return getModifiableDocument().build();
 282  
         }
 283  0
         return null;
 284  
     }
 285  
 
 286  
     protected DocumentContentUpdate getDocumentContentUpdateIfDirty() {
 287  0
         if (getModifiableDocumentContent().isDirty()) {
 288  0
             return getModifiableDocumentContent().build();
 289  
         }
 290  0
         return null;
 291  
     }
 292  
 
 293  
     protected void resetStateAfterAction(DocumentActionResult response) {
 294  0
         this.modifiableDocument = new ModifiableDocument(response.getDocument());
 295  0
         this.validActions = null;
 296  0
         if (response.getValidActions() != null) {
 297  0
             this.validActions = response.getValidActions();
 298  
         }
 299  0
         this.requestedActions = null;
 300  0
         if (response.getRequestedActions() != null) {
 301  0
             this.requestedActions = response.getRequestedActions();
 302  
         }
 303  
         // regardless of whether modifiable document content is dirty, we null it out so it will be re-fetched next time it's needed
 304  0
         this.modifiableDocumentContent = null;
 305  0
     }
 306  
 
 307  
     @Override
 308  
     public void saveDocument(String annotation) {
 309  0
         DocumentActionResult result = getWorkflowDocumentActionsService().save(
 310  
                 constructDocumentActionParameters(annotation));
 311  0
         resetStateAfterAction(result);
 312  0
     }
 313  
 
 314  
     @Override
 315  
     public void route(String annotation) {
 316  0
         DocumentActionResult result = getWorkflowDocumentActionsService().route(
 317  
                 constructDocumentActionParameters(annotation));
 318  0
         resetStateAfterAction(result);
 319  0
     }
 320  
 
 321  
     @Override
 322  
     public void disapprove(String annotation) {
 323  0
         DocumentActionResult result = getWorkflowDocumentActionsService().disapprove(
 324  
                 constructDocumentActionParameters(annotation));
 325  0
         resetStateAfterAction(result);
 326  0
     }
 327  
 
 328  
     @Override
 329  
     public void approve(String annotation) {
 330  0
         DocumentActionResult result = getWorkflowDocumentActionsService().approve(
 331  
                 constructDocumentActionParameters(annotation));
 332  0
         resetStateAfterAction(result);
 333  0
     }
 334  
 
 335  
     @Override
 336  
     public void cancel(String annotation) {
 337  0
         DocumentActionResult result = getWorkflowDocumentActionsService().cancel(
 338  
                 constructDocumentActionParameters(annotation));
 339  0
         resetStateAfterAction(result);
 340  0
     }
 341  
 
 342  
     @Override
 343  
     public void blanketApprove(String annotation) {
 344  0
         DocumentActionResult result = getWorkflowDocumentActionsService().blanketApprove(
 345  
                 constructDocumentActionParameters(annotation));
 346  0
         resetStateAfterAction(result);
 347  0
     }
 348  
 
 349  
     @Override
 350  
     public void blanketApprove(String annotation, String... nodeNames) {
 351  0
         if (nodeNames == null) {
 352  0
             throw new IllegalArgumentException("nodeNames was null");
 353  
         }
 354  0
         Set<String> nodeNamesSet = new HashSet<String>(Arrays.asList(nodeNames));
 355  0
         DocumentActionResult result = getWorkflowDocumentActionsService().blanketApproveToNodes(
 356  
                 constructDocumentActionParameters(annotation), nodeNamesSet);
 357  0
         resetStateAfterAction(result);
 358  0
     }
 359  
 
 360  
     @Override
 361  
     public void saveDocumentData() {
 362  0
         DocumentActionResult result = getWorkflowDocumentActionsService().saveDocumentData(
 363  
                 constructDocumentActionParameters(null));
 364  0
         resetStateAfterAction(result);
 365  0
     }
 366  
 
 367  
     @Override
 368  
     public void setApplicationDocumentStatus(String applicationDocumentStatus) {
 369  0
         getModifiableDocument().setApplicationDocumentStatus(applicationDocumentStatus);
 370  0
     }
 371  
 
 372  
     @Override
 373  
     public void acknowledge(String annotation) {
 374  0
         DocumentActionResult result = getWorkflowDocumentActionsService().acknowledge(
 375  
                 constructDocumentActionParameters(annotation));
 376  0
         resetStateAfterAction(result);
 377  0
     }
 378  
 
 379  
     @Override
 380  
     public void fyi(String annotation) {
 381  0
         DocumentActionResult result = getWorkflowDocumentActionsService().clearFyi(
 382  
                 constructDocumentActionParameters(annotation));
 383  0
         resetStateAfterAction(result);
 384  0
     }
 385  
 
 386  
     @Override
 387  
     public void fyi() {
 388  0
         fyi("");
 389  0
     }
 390  
 
 391  
     /**
 392  
      * TODO - be sure to mention that once this document is deleted, this api effectively becomes
 393  
      * "dead" when you try to execute any document operation
 394  
      */
 395  
     @Override
 396  
     public void delete() {
 397  0
         getWorkflowDocumentActionsService().delete(getDocumentId(), principalId);
 398  0
         documentDeleted = true;
 399  0
     }
 400  
 
 401  
     @Override
 402  
     public void refresh() {
 403  0
         Document document = getWorkflowDocumentService().getDocument(getDocumentId());
 404  0
         this.modifiableDocument = new ModifiableDocument(document);
 405  0
         this.validActions = null;
 406  0
         this.requestedActions = null;
 407  0
         this.modifiableDocumentContent = null;
 408  0
     }
 409  
 
 410  
     @Override
 411  
     public void adHocToPrincipal(ActionRequestType actionRequested, String annotation, String targetPrincipalId,
 412  
             String responsibilityDescription, boolean forceAction) {
 413  0
         adHocToPrincipal(actionRequested, null, annotation, targetPrincipalId, responsibilityDescription, forceAction);
 414  0
     }
 415  
 
 416  
     @Override
 417  
     public void adHocToPrincipal(ActionRequestType actionRequested, String nodeName, String annotation,
 418  
             String targetPrincipalId, String responsibilityDescription, boolean forceAction) {
 419  0
         adHocToPrincipal(actionRequested, nodeName, annotation, targetPrincipalId, responsibilityDescription,
 420  
                 forceAction, null);
 421  0
     }
 422  
 
 423  
     @Override
 424  
     public void adHocToPrincipal(ActionRequestType actionRequested, String nodeName, String annotation,
 425  
             String targetPrincipalId, String responsibilityDescription, boolean forceAction, String requestLabel) {
 426  0
         AdHocToPrincipal.Builder builder = AdHocToPrincipal.Builder
 427  
                 .create(actionRequested, nodeName, targetPrincipalId);
 428  0
         builder.setResponsibilityDescription(responsibilityDescription);
 429  0
         builder.setForceAction(forceAction);
 430  0
         builder.setRequestLabel(requestLabel);
 431  0
         DocumentActionResult result = getWorkflowDocumentActionsService().adHocToPrincipal(
 432  
                 constructDocumentActionParameters(annotation), builder.build());
 433  0
         resetStateAfterAction(result);
 434  0
     }
 435  
 
 436  
     @Override
 437  
     public void adHocToGroup(ActionRequestType actionRequested, String annotation, String targetGroupId,
 438  
             String responsibilityDescription, boolean forceAction) {
 439  0
         adHocToGroup(actionRequested, null, annotation, targetGroupId, responsibilityDescription, forceAction);
 440  0
     }
 441  
 
 442  
     @Override
 443  
     public void adHocToGroup(ActionRequestType actionRequested, String nodeName, String annotation,
 444  
             String targetGroupId, String responsibilityDescription, boolean forceAction) {
 445  0
         adHocToGroup(actionRequested, nodeName, annotation, targetGroupId, responsibilityDescription, forceAction, null);
 446  0
     }
 447  
 
 448  
     @Override
 449  
     public void adHocToGroup(ActionRequestType actionRequested, String nodeName, String annotation,
 450  
             String targetGroupId, String responsibilityDescription, boolean forceAction, String requestLabel) {
 451  0
         AdHocToGroup.Builder builder = AdHocToGroup.Builder.create(actionRequested, nodeName, targetGroupId);
 452  0
         builder.setResponsibilityDescription(responsibilityDescription);
 453  0
         builder.setForceAction(forceAction);
 454  0
         builder.setRequestLabel(requestLabel);
 455  0
         DocumentActionResult result = getWorkflowDocumentActionsService().adHocToGroup(
 456  
                 constructDocumentActionParameters(annotation), builder.build());
 457  0
         resetStateAfterAction(result);
 458  0
     }
 459  
 
 460  
     @Override
 461  
     public void revokeAdHocRequestById(String actionRequestId, String annotation) {
 462  0
         if (StringUtils.isBlank(actionRequestId)) {
 463  0
             throw new IllegalArgumentException("actionRequestId was null or blank");
 464  
         }
 465  0
         DocumentActionResult result = getWorkflowDocumentActionsService().revokeAdHocRequestById(
 466  
                 constructDocumentActionParameters(annotation), actionRequestId);
 467  0
         resetStateAfterAction(result);
 468  0
     }
 469  
 
 470  
     @Override
 471  
     public void revokeAdHocRequests(AdHocRevoke revoke, String annotation) {
 472  0
         if (revoke == null) {
 473  0
             throw new IllegalArgumentException("revokeFromPrincipal was null");
 474  
         }
 475  0
         DocumentActionResult result = getWorkflowDocumentActionsService().revokeAdHocRequests(
 476  
                 constructDocumentActionParameters(annotation), revoke);
 477  0
         resetStateAfterAction(result);
 478  0
     }
 479  
 
 480  
     @Override
 481  
     public void revokeAllAdHocRequests(String annotation) {
 482  0
         DocumentActionResult result = getWorkflowDocumentActionsService().revokeAllAdHocRequests(
 483  
                 constructDocumentActionParameters(annotation));
 484  0
         resetStateAfterAction(result);
 485  0
     }
 486  
 
 487  
     @Override
 488  
     public void setTitle(String title) {
 489  0
         getModifiableDocument().setTitle(title);
 490  0
     }
 491  
 
 492  
     @Override
 493  
     public String getDocumentTypeName() {
 494  0
         return getDocument().getDocumentTypeName();
 495  
     }
 496  
 
 497  
     @Override
 498  
     public boolean isCompletionRequested() {
 499  0
         return getRequestedActions().isCompleteRequested();
 500  
     }
 501  
 
 502  
     @Override
 503  
     public boolean isApprovalRequested() {
 504  0
         return getRequestedActions().isApproveRequested();
 505  
     }
 506  
 
 507  
     @Override
 508  
     public boolean isAcknowledgeRequested() {
 509  0
         return getRequestedActions().isAcknowledgeRequested();
 510  
     }
 511  
 
 512  
     @Override
 513  
     public boolean isFYIRequested() {
 514  0
         return getRequestedActions().isFyiRequested();
 515  
     }
 516  
 
 517  
     @Override
 518  
     public boolean isBlanketApproveCapable() {
 519  0
         return isValidAction(ActionType.BLANKET_APPROVE)
 520  
                 && (isCompletionRequested() || isApprovalRequested() || isInitiated());
 521  
     }
 522  
 
 523  
     @Override
 524  
     public boolean isRouteCapable() {
 525  0
         return isValidAction(ActionType.ROUTE);
 526  
     }
 527  
 
 528  
     @Override
 529  
     public boolean isValidAction(ActionType actionType) {
 530  0
         if (actionType == null) {
 531  0
             throw new IllegalArgumentException("actionType was null");
 532  
         }
 533  0
         return getValidActions().getValidActions().contains(actionType);
 534  
     }
 535  
 
 536  
     @Override
 537  
     public void superUserBlanketApprove(String annotation) {
 538  0
         DocumentActionResult result = getWorkflowDocumentActionsService().superUserBlanketApprove(
 539  
                 constructDocumentActionParameters(annotation), true);
 540  0
         resetStateAfterAction(result);
 541  0
     }
 542  
 
 543  
     @Override
 544  
     public void superUserNodeApprove(String nodeName, String annotation) {
 545  0
         DocumentActionResult result = getWorkflowDocumentActionsService().superUserNodeApprove(
 546  
                 constructDocumentActionParameters(annotation), true, nodeName);
 547  0
         resetStateAfterAction(result);
 548  0
     }
 549  
 
 550  
     @Override
 551  
     public void superUserTakeRequestedAction(String actionRequestId, String annotation) {
 552  0
         DocumentActionResult result = getWorkflowDocumentActionsService().superUserTakeRequestedAction(
 553  
                 constructDocumentActionParameters(annotation), true, actionRequestId);
 554  0
         resetStateAfterAction(result);
 555  0
     }
 556  
 
 557  
     @Override
 558  
     public void superUserDisapprove(String annotation) {
 559  0
         DocumentActionResult result = getWorkflowDocumentActionsService().superUserDisapprove(
 560  
                 constructDocumentActionParameters(annotation), true);
 561  0
         resetStateAfterAction(result);
 562  0
     }
 563  
 
 564  
     @Override
 565  
     public void superUserCancel(String annotation) {
 566  0
         DocumentActionResult result = getWorkflowDocumentActionsService().superUserCancel(
 567  
                 constructDocumentActionParameters(annotation), true);
 568  0
         resetStateAfterAction(result);
 569  0
     }
 570  
 
 571  
     @Override
 572  
     public void superUserReturnToPreviousNode(ReturnPoint returnPoint, String annotation) {
 573  0
         DocumentActionResult result = getWorkflowDocumentActionsService().superUserReturnToPreviousNode(
 574  
                 constructDocumentActionParameters(annotation), true, returnPoint);
 575  0
         resetStateAfterAction(result);
 576  0
     }
 577  
 
 578  
     @Override
 579  
     public void complete(String annotation) {
 580  0
         DocumentActionResult result = getWorkflowDocumentActionsService().complete(
 581  
                 constructDocumentActionParameters(annotation));
 582  0
         resetStateAfterAction(result);
 583  0
     }
 584  
 
 585  
     @Override
 586  
     public void logAnnotation(String annotation) {
 587  0
         getWorkflowDocumentActionsService().logAnnotation(getDocumentId(), principalId, annotation);
 588  0
     }
 589  
 
 590  
     @Override
 591  
     public DocumentStatus getStatus() {
 592  0
         return getDocument().getStatus();
 593  
     }
 594  
 
 595  
     @Override
 596  
     public boolean checkStatus(DocumentStatus status) {
 597  0
         if (status == null) {
 598  0
             throw new IllegalArgumentException("status was null");
 599  
         }
 600  0
         return status == getStatus();
 601  
     }
 602  
 
 603  
     /**
 604  
      * Indicates if the document is in the initiated state or not.
 605  
      * 
 606  
      * @return true if in the specified state
 607  
      */
 608  
     @Override
 609  
     public boolean isInitiated() {
 610  0
         return checkStatus(DocumentStatus.INITIATED);
 611  
     }
 612  
 
 613  
     /**
 614  
      * Indicates if the document is in the saved state or not.
 615  
      * 
 616  
      * @return true if in the specified state
 617  
      */
 618  
     @Override
 619  
     public boolean isSaved() {
 620  0
         return checkStatus(DocumentStatus.SAVED);
 621  
     }
 622  
 
 623  
     /**
 624  
      * Indicates if the document is in the enroute state or not.
 625  
      * 
 626  
      * @return true if in the specified state
 627  
      */
 628  
     @Override
 629  
     public boolean isEnroute() {
 630  0
         return checkStatus(DocumentStatus.ENROUTE);
 631  
     }
 632  
 
 633  
     /**
 634  
      * Indicates if the document is in the exception state or not.
 635  
      * 
 636  
      * @return true if in the specified state
 637  
      */
 638  
     @Override
 639  
     public boolean isException() {
 640  0
         return checkStatus(DocumentStatus.EXCEPTION);
 641  
     }
 642  
 
 643  
     /**
 644  
      * Indicates if the document is in the canceled state or not.
 645  
      * 
 646  
      * @return true if in the specified state
 647  
      */
 648  
     @Override
 649  
     public boolean isCanceled() {
 650  0
         return checkStatus(DocumentStatus.CANCELED);
 651  
     }
 652  
 
 653  
     /**
 654  
      * Indicates if the document is in the disapproved state or not.
 655  
      * 
 656  
      * @return true if in the specified state
 657  
      */
 658  
     @Override
 659  
     public boolean isDisapproved() {
 660  0
         return checkStatus(DocumentStatus.DISAPPROVED);
 661  
     }
 662  
 
 663  
     /**
 664  
      * Indicates if the document is in the Processed or Finalized state.
 665  
      * 
 666  
      * @return true if in the specified state
 667  
      */
 668  
     @Override
 669  
     public boolean isApproved() {
 670  0
         return isProcessed() || isFinal();
 671  
     }
 672  
 
 673  
     /**
 674  
      * Indicates if the document is in the processed state or not.
 675  
      * 
 676  
      * @return true if in the specified state
 677  
      */
 678  
     @Override
 679  
     public boolean isProcessed() {
 680  0
         return checkStatus(DocumentStatus.PROCESSED);
 681  
     }
 682  
 
 683  
     /**
 684  
      * Indicates if the document is in the final state or not.
 685  
      * 
 686  
      * @return true if in the specified state
 687  
      */
 688  
     @Override
 689  
     public boolean isFinal() {
 690  0
         return checkStatus(DocumentStatus.FINAL);
 691  
     }
 692  
 
 693  
     /**
 694  
      * Returns the principalId with which this WorkflowDocument was constructed
 695  
      * 
 696  
      * @return the principalId with which this WorkflowDocument was constructed
 697  
      */
 698  
     @Override
 699  
     public String getPrincipalId() {
 700  0
         return principalId;
 701  
     }
 702  
 
 703  
     @Override
 704  
     public void switchPrincipal(String principalId) {
 705  0
         if (StringUtils.isBlank(this.principalId)) {
 706  0
             throw new IllegalArgumentException("principalId was null or blank");
 707  
         }
 708  0
         this.principalId = principalId;
 709  0
         this.validActions = null;
 710  0
         this.requestedActions = null;
 711  0
     }
 712  
 
 713  
     @Override
 714  
     public void takeGroupAuthority(String annotation, String groupId) {
 715  0
         DocumentActionResult result = getWorkflowDocumentActionsService().takeGroupAuthority(
 716  
                 constructDocumentActionParameters(annotation), groupId);
 717  0
         resetStateAfterAction(result);
 718  0
     }
 719  
 
 720  
     @Override
 721  
     public void releaseGroupAuthority(String annotation, String groupId) {
 722  0
         DocumentActionResult result = getWorkflowDocumentActionsService().releaseGroupAuthority(
 723  
                 constructDocumentActionParameters(annotation), groupId);
 724  0
         resetStateAfterAction(result);
 725  0
     }
 726  
 
 727  
     @Override
 728  
     public Set<String> getNodeNames() {
 729  0
         List<RouteNodeInstance> activeNodeInstances = getActiveRouteNodeInstances();
 730  0
         Set<String> nodeNames = new HashSet<String>(activeNodeInstances.size());
 731  0
         for (RouteNodeInstance routeNodeInstance : activeNodeInstances) {
 732  0
             nodeNames.add(routeNodeInstance.getName());
 733  
         }
 734  0
         return Collections.unmodifiableSet(nodeNames);
 735  
     }
 736  
 
 737  
     @Override
 738  
     public void returnToPreviousNode(String nodeName, String annotation) {
 739  0
         if (StringUtils.isBlank(nodeName)) {
 740  0
             throw new IllegalArgumentException("nodeName was null or blank");
 741  
         }
 742  0
         returnToPreviousNode(ReturnPoint.create(nodeName), annotation);
 743  0
     }
 744  
 
 745  
     @Override
 746  
     public void returnToPreviousNode(ReturnPoint returnPoint, String annotation) {
 747  0
         if (returnPoint == null) {
 748  0
             throw new IllegalArgumentException("returnPoint was null");
 749  
         }
 750  0
         DocumentActionResult result = getWorkflowDocumentActionsService().returnToPreviousNode(
 751  
                 constructDocumentActionParameters(annotation), returnPoint);
 752  0
         resetStateAfterAction(result);
 753  0
     }
 754  
 
 755  
     @Override
 756  
     public void move(MovePoint movePoint, String annotation) {
 757  0
         if (movePoint == null) {
 758  0
             throw new IllegalArgumentException("movePoint was null");
 759  
         }
 760  0
         DocumentActionResult result = getWorkflowDocumentActionsService().move(
 761  
                 constructDocumentActionParameters(annotation), movePoint);
 762  0
         resetStateAfterAction(result);
 763  0
     }
 764  
 
 765  
     @Override
 766  
     public List<RouteNodeInstance> getActiveRouteNodeInstances() {
 767  0
         return getWorkflowDocumentService().getActiveRouteNodeInstances(getDocumentId());
 768  
     }
 769  
 
 770  
     @Override
 771  
     public List<RouteNodeInstance> getRouteNodeInstances() {
 772  0
         return getWorkflowDocumentService().getRouteNodeInstances(getDocumentId());
 773  
     }
 774  
 
 775  
     @Override
 776  
     public List<String> getPreviousNodeNames() {
 777  0
         return getWorkflowDocumentService().getPreviousRouteNodeNames(getDocumentId());
 778  
     }
 779  
 
 780  
     @Override
 781  
     public DocumentDetail getDocumentDetail() {
 782  0
         return getWorkflowDocumentService().getDocumentDetail(getDocumentId());
 783  
     }
 784  
 
 785  
     @Override
 786  
     public void updateDocumentContent(DocumentContentUpdate documentContentUpdate) {
 787  0
         if (documentContentUpdate == null) {
 788  0
             throw new IllegalArgumentException("documentContentUpdate was null.");
 789  
         }
 790  0
         getModifiableDocumentContent().setDocumentContentUpdate(documentContentUpdate);
 791  0
     }
 792  
 
 793  
     @Override
 794  
     public void placeInExceptionRouting(String annotation) {
 795  0
         DocumentActionResult result = getWorkflowDocumentActionsService().placeInExceptionRouting(
 796  
                 constructDocumentActionParameters(annotation));
 797  0
         resetStateAfterAction(result);
 798  0
     }
 799  
 
 800  
     @Override
 801  
     public void setVariable(String name, String value) {
 802  0
         getModifiableDocument().setVariable(name, value);
 803  0
     }
 804  
 
 805  
     @Override
 806  
     public String getVariableValue(String name) {
 807  0
         return getModifiableDocument().getVariableValue(name);
 808  
     }
 809  
 
 810  
     @Override
 811  
     public void setReceiveFutureRequests() {
 812  0
         setVariable(getFutureRequestsKey(principalId), getReceiveFutureRequestsValue());
 813  0
     }
 814  
 
 815  
     @Override
 816  
     public void setDoNotReceiveFutureRequests() {
 817  0
         this.setVariable(getFutureRequestsKey(principalId), getDoNotReceiveFutureRequestsValue());
 818  0
     }
 819  
 
 820  
     @Override
 821  
     public void setClearFutureRequests() {
 822  0
         this.setVariable(getFutureRequestsKey(principalId), getClearFutureRequestsValue());
 823  0
     }
 824  
 
 825  
     protected String getFutureRequestsKey(String principalId) {
 826  0
         return KewApiConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_KEY + "," + principalId + ","
 827  
                 + new Date().toString() + ", " + Math.random();
 828  
     }
 829  
 
 830  
     @Override
 831  
     public String getReceiveFutureRequestsValue() {
 832  0
         return KewApiConstants.RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_VALUE;
 833  
     }
 834  
 
 835  
     @Override
 836  
     public String getDoNotReceiveFutureRequestsValue() {
 837  0
         return KewApiConstants.DONT_RECEIVE_FUTURE_REQUESTS_BRANCH_STATE_VALUE;
 838  
     }
 839  
 
 840  
     @Override
 841  
     public String getClearFutureRequestsValue() {
 842  0
         return KewApiConstants.CLEAR_FUTURE_REQUESTS_BRANCH_STATE_VALUE;
 843  
     }
 844  
 
 845  
     protected DocumentActionParameters constructDocumentActionParameters(String annotation) {
 846  0
         DocumentActionParameters.Builder builder = DocumentActionParameters.Builder.create(getDocumentId(),
 847  
                 getPrincipalId());
 848  0
         builder.setAnnotation(annotation);
 849  0
         builder.setDocumentUpdate(getDocumentUpdateIfDirty());
 850  0
         builder.setDocumentContentUpdate(getDocumentContentUpdateIfDirty());
 851  0
         return builder.build();
 852  
     }
 853  
     
 854  
     @Override
 855  
     public DateTime getDateLastModified() {
 856  0
         return getDocument().getDateLastModified();
 857  
     }
 858  
 
 859  
     @Override
 860  
     public DateTime getDateApproved() {
 861  0
         return getDocument().getDateApproved();
 862  
     }
 863  
 
 864  
     @Override
 865  
     public DateTime getDateFinalized() {
 866  0
         return getDocument().getDateFinalized();
 867  
     }
 868  
 
 869  
     @Override
 870  
     public String getInitiatorPrincipalId() {
 871  0
         return getDocument().getInitiatorPrincipalId();
 872  
     }
 873  
 
 874  
     @Override
 875  
     public String getRoutedByPrincipalId() {
 876  0
         return getDocument().getRoutedByPrincipalId();
 877  
     }
 878  
 
 879  
     @Override
 880  
     public String getDocumentTypeId() {
 881  0
         return getDocument().getDocumentTypeId();
 882  
     }
 883  
 
 884  
     @Override
 885  
     public String getDocumentHandlerUrl() {
 886  0
         return getDocument().getDocumentHandlerUrl();
 887  
     }
 888  
 
 889  
     @Override
 890  
     public String getApplicationDocumentStatus() {
 891  0
         return getDocument().getApplicationDocumentStatus();
 892  
     }
 893  
 
 894  
     @Override
 895  
     public DateTime getApplicationDocumentStatusDate() {
 896  0
         return getDocument().getApplicationDocumentStatusDate();
 897  
     }
 898  
 
 899  
     @Override
 900  
     public Map<String, String> getVariables() {
 901  0
         return getDocument().getVariables();
 902  
     }
 903  
 
 904  
     protected static class ModifiableDocumentContent implements Serializable {
 905  
 
 906  
         private static final long serialVersionUID = -4458431160327214042L;
 907  
 
 908  
         private boolean dirty;
 909  
         private DocumentContent originalDocumentContent;
 910  
         private DocumentContentUpdate.Builder builder;
 911  
 
 912  0
         protected ModifiableDocumentContent(DocumentContent documentContent) {
 913  0
             this.dirty = false;
 914  0
             this.originalDocumentContent = documentContent;
 915  0
             this.builder = DocumentContentUpdate.Builder.create(documentContent);
 916  0
         }
 917  
 
 918  
         protected DocumentContent getDocumentContent() {
 919  0
             if (!dirty) {
 920  0
                 return originalDocumentContent;
 921  
             }
 922  0
             DocumentContent.Builder documentContentBuilder = DocumentContent.Builder.create(originalDocumentContent);
 923  0
             documentContentBuilder.setApplicationContent(builder.getApplicationContent());
 924  0
             documentContentBuilder.setAttributeContent(builder.getApplicationContent());
 925  0
             documentContentBuilder.setSearchableContent(builder.getSearchableContent());
 926  0
             return documentContentBuilder.build();
 927  
         }
 928  
 
 929  
         protected DocumentContentUpdate build() {
 930  0
             return builder.build();
 931  
         }
 932  
 
 933  
         protected void setDocumentContentUpdate(DocumentContentUpdate update) {
 934  0
             this.builder = DocumentContentUpdate.Builder.create(update);
 935  0
             this.dirty = true;
 936  0
         }
 937  
 
 938  
         protected void addAttributeDefinition(WorkflowAttributeDefinition definition) {
 939  0
             builder.getAttributeDefinitions().add(definition);
 940  0
             dirty = true;
 941  0
         }
 942  
 
 943  
         protected void removeAttributeDefinition(WorkflowAttributeDefinition definition) {
 944  0
             builder.getAttributeDefinitions().remove(definition);
 945  0
             dirty = true;
 946  0
         }
 947  
 
 948  
         protected List<WorkflowAttributeDefinition> getAttributeDefinitions() {
 949  0
             return builder.getAttributeDefinitions();
 950  
         }
 951  
 
 952  
         protected void addSearchableDefinition(WorkflowAttributeDefinition definition) {
 953  0
             builder.getSearchableDefinitions().add(definition);
 954  0
             dirty = true;
 955  0
         }
 956  
 
 957  
         protected void removeSearchableDefinition(WorkflowAttributeDefinition definition) {
 958  0
             builder.getSearchableDefinitions().remove(definition);
 959  0
             dirty = true;
 960  0
         }
 961  
 
 962  
         protected List<WorkflowAttributeDefinition> getSearchableDefinitions() {
 963  0
             return builder.getAttributeDefinitions();
 964  
         }
 965  
 
 966  
         protected void setApplicationContent(String applicationContent) {
 967  0
             builder.setApplicationContent(applicationContent);
 968  0
             dirty = true;
 969  0
         }
 970  
 
 971  
         protected void setAttributeContent(String attributeContent) {
 972  0
             builder.setAttributeContent(attributeContent);
 973  0
             dirty = true;
 974  0
         }
 975  
 
 976  
         public void setAttributeDefinitions(List<WorkflowAttributeDefinition> attributeDefinitions) {
 977  0
             builder.setAttributeDefinitions(attributeDefinitions);
 978  0
             dirty = true;
 979  0
         }
 980  
 
 981  
         public void setSearchableContent(String searchableContent) {
 982  0
             builder.setSearchableContent(searchableContent);
 983  0
             dirty = true;
 984  0
         }
 985  
 
 986  
         public void setSearchableDefinitions(List<WorkflowAttributeDefinition> searchableDefinitions) {
 987  0
             builder.setSearchableDefinitions(searchableDefinitions);
 988  0
             dirty = true;
 989  0
         }
 990  
 
 991  
         boolean isDirty() {
 992  0
             return dirty;
 993  
         }
 994  
 
 995  
     }
 996  
 
 997  0
     protected static class ModifiableDocument implements Serializable {
 998  
 
 999  
         private static final long serialVersionUID = -3234793238863410378L;
 1000  
 
 1001  
         private boolean dirty;
 1002  
         private Document originalDocument;
 1003  
         private DocumentUpdate.Builder builder;
 1004  
 
 1005  0
         protected ModifiableDocument(Document document) {
 1006  0
             this.dirty = false;
 1007  0
             this.originalDocument = document;
 1008  0
             this.builder = DocumentUpdate.Builder.create(document);
 1009  0
         }
 1010  
 
 1011  
         protected Document getDocument() {
 1012  0
             if (!dirty) {
 1013  0
                 return originalDocument;
 1014  
             }
 1015  0
             Document.Builder documentBuilder = Document.Builder.create(originalDocument);
 1016  0
             documentBuilder.setApplicationDocumentId(builder.getApplicationDocumentId());
 1017  0
             documentBuilder.setTitle(builder.getTitle());
 1018  0
             return documentBuilder.build();
 1019  
         }
 1020  
 
 1021  
         protected DocumentUpdate build() {
 1022  0
             return builder.build();
 1023  
         }
 1024  
 
 1025  
         /**
 1026  
          * Immutable value which is accessed frequently, provide direct access to it.
 1027  
          */
 1028  
         protected String getDocumentId() {
 1029  0
             return originalDocument.getDocumentId();
 1030  
         }
 1031  
 
 1032  
         /**
 1033  
          * Immutable value which is accessed frequently, provide direct access to it.
 1034  
          */
 1035  
         protected DateTime getDateCreated() {
 1036  0
             return originalDocument.getDateCreated();
 1037  
         }
 1038  
 
 1039  
         protected String getApplicationDocumentId() {
 1040  0
             return builder.getApplicationDocumentId();
 1041  
         }
 1042  
 
 1043  
         protected void setApplicationDocumentId(String applicationDocumentId) {
 1044  0
             builder.setApplicationDocumentId(applicationDocumentId);
 1045  0
             dirty = true;
 1046  0
         }
 1047  
 
 1048  
         protected String getTitle() {
 1049  0
             return builder.getTitle();
 1050  
         }
 1051  
 
 1052  
         protected void setTitle(String title) {
 1053  0
             builder.setTitle(title);
 1054  0
             dirty = true;
 1055  0
         }
 1056  
 
 1057  
         protected String getApplicationDocumentStatus() {
 1058  0
             return builder.getApplicationDocumentStatus();
 1059  
         }
 1060  
 
 1061  
         protected void setApplicationDocumentStatus(String applicationDocumentStatus) {
 1062  0
             builder.setApplicationDocumentStatus(applicationDocumentStatus);
 1063  0
             dirty = true;
 1064  0
         }
 1065  
 
 1066  
         protected void setVariable(String name, String value) {
 1067  0
             builder.setVariable(name, value);
 1068  0
             dirty = true;
 1069  0
         }
 1070  
 
 1071  
         protected String getVariableValue(String name) {
 1072  0
             return builder.getVariableValue(name);
 1073  
         }
 1074  
 
 1075  
         boolean isDirty() {
 1076  0
             return dirty;
 1077  
         }
 1078  
 
 1079  
     }
 1080  
 
 1081  
 }