/**
   * @see
   *     org.kuali.rice.krad.service.DocumentService#disapproveDocument(org.kuali.rice.krad.document.Document,
   *     java.lang.String)
   */
  @Override
  public Document disapproveDocument(Document document, String annotation) throws Exception {
    checkForNulls(document);

    Note note = createNoteFromDocument(document, annotation);
    // if note type is BO, override and link disapprove notes to Doc Header
    if (document.getNoteType().equals(NoteType.BUSINESS_OBJECT)) {
      note.setNoteTypeCode(NoteType.DOCUMENT_HEADER.getCode());
      note.setRemoteObjectIdentifier(document.getDocumentHeader().getObjectId());
    }
    document.addNote(note);

    // SAVE THE NOTE
    // Note: This save logic is replicated here and in KualiDocumentAction, when to save (based on
    // doc state) should be moved
    //      into a doc service method
    getNoteService().save(note);

    prepareWorkflowDocument(document);
    getWorkflowDocumentService()
        .disapprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());
    removeAdHocPersonsAndWorkgroups(document);
    return document;
  }
  /**
   * @see
   *     org.kuali.rice.krad.service.DocumentService#cancelDocument(org.kuali.rice.krad.document.Document,
   *     java.lang.String)
   */
  @Override
  public Document cancelDocument(Document document, String annotation) throws WorkflowException {
    checkForNulls(document);
    // if (!getDocumentActionFlags(document).getCanCancel()) {
    //    throw buildAuthorizationException("cancel", document);
    // }
    if (document instanceof MaintenanceDocument) {
      MaintenanceDocument maintDoc = ((MaintenanceDocument) document);
      if (maintDoc.getOldMaintainableObject() != null
          && (maintDoc.getOldMaintainableObject().getDataObject() instanceof BusinessObject)) {
        ((BusinessObject) maintDoc.getOldMaintainableObject().getDataObject()).refresh();
      }

      if (maintDoc.getNewMaintainableObject().getDataObject() instanceof BusinessObject) {
        ((BusinessObject) maintDoc.getNewMaintainableObject().getDataObject()).refresh();
      }
    }
    prepareWorkflowDocument(document);
    getWorkflowDocumentService()
        .cancel(document.getDocumentHeader().getWorkflowDocument(), annotation);
    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());

    removeAdHocPersonsAndWorkgroups(document);
    return document;
  }
  @Override
  public Document saveDocument(
      Document document, Class<? extends KualiDocumentEvent> kualiDocumentEventClass)
      throws WorkflowException, ValidationException {
    checkForNulls(document);
    if (kualiDocumentEventClass == null) {
      throw new IllegalArgumentException("invalid (null) kualiDocumentEventClass");
    }
    // if event is not an instance of a SaveDocumentEvent or a SaveOnlyDocumentEvent
    if (!SaveEvent.class.isAssignableFrom(kualiDocumentEventClass)) {
      throw new ConfigurationException(
          "The KualiDocumentEvent class '"
              + kualiDocumentEventClass.getName()
              + "' does not implement the class '"
              + SaveEvent.class.getName()
              + "'");
    }
    //        if (!getDocumentActionFlags(document).getCanSave()) {
    //            throw buildAuthorizationException("save", document);
    //        }
    document.prepareForSave();
    Document savedDocument =
        validateAndPersistDocumentAndSaveAdHocRoutingRecipients(
            document, generateKualiDocumentEvent(document, kualiDocumentEventClass));
    prepareWorkflowDocument(savedDocument);
    getWorkflowDocumentService()
        .save(savedDocument.getDocumentHeader().getWorkflowDocument(), null);

    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), savedDocument.getDocumentHeader().getWorkflowDocument());

    return savedDocument;
  }
 /**
  * @see
  *     org.kuali.rice.krad.service.DocumentService#superUserCancelDocument(org.kuali.rice.krad.document.Document,
  *     java.lang.String)
  */
 @Override
 public Document superUserDisapproveDocumentWithoutSaving(Document document, String annotation)
     throws WorkflowException {
   prepareWorkflowDocument(document);
   getWorkflowDocumentService()
       .superUserDisapprove(document.getDocumentHeader().getWorkflowDocument(), annotation);
   UserSessionUtils.addWorkflowDocument(
       GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());
   removeAdHocPersonsAndWorkgroups(document);
   return document;
 }
 /**
  * @see
  *     org.kuali.rice.krad.service.DocumentService#clearDocumentFyi(org.kuali.rice.krad.document.Document,
  *     java.util.List)
  */
 @Override
 public Document clearDocumentFyi(Document document, List<AdHocRouteRecipient> adHocRecipients)
     throws WorkflowException {
   checkForNulls(document);
   // populate document content so searchable attributes will be indexed properly
   document.populateDocumentForRouting();
   getWorkflowDocumentService()
       .clearFyi(document.getDocumentHeader().getWorkflowDocument(), adHocRecipients);
   UserSessionUtils.addWorkflowDocument(
       GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());
   removeAdHocPersonsAndWorkgroups(document);
   return document;
 }
  /**
   * @see
   *     org.kuali.rice.krad.service.DocumentService#sendAdHocRequests(org.kuali.rice.krad.document.Document,
   *     String, java.util.List)
   */
  @Override
  public void sendAdHocRequests(
      Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients)
      throws WorkflowException {
    prepareWorkflowDocument(document);
    getWorkflowDocumentService()
        .sendWorkflowNotification(
            document.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());

    removeAdHocPersonsAndWorkgroups(document);
  }
 /**
  * @see
  *     org.kuali.rice.krad.service.DocumentService#acknowledgeDocument(org.kuali.rice.krad.document.Document,
  *     java.lang.String, java.util.List)
  */
 @Override
 public Document acknowledgeDocument(
     Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients)
     throws WorkflowException {
   checkForNulls(document);
   // if (!getDocumentActionFlags(document).getCanAcknowledge()) {
   //    throw buildAuthorizationException("acknowledge", document);
   // }
   prepareWorkflowDocument(document);
   getWorkflowDocumentService()
       .acknowledge(
           document.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
   UserSessionUtils.addWorkflowDocument(
       GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());
   removeAdHocPersonsAndWorkgroups(document);
   return document;
 }
 /**
  * @see
  *     org.kuali.rice.krad.service.DocumentService#superUserCancelDocument(org.kuali.rice.krad.document.Document,
  *     java.lang.String)
  */
 @Override
 public Document superUserCancelDocument(Document document, String annotation)
     throws WorkflowException {
   Document savedDocument = getLegacyDataAdapter().saveDocument(document);
   savedDocument.processAfterRetrieve();
   // Need to preserve the workflow document header, which just got left behind
   savedDocument
       .getDocumentHeader()
       .setWorkflowDocument(document.getDocumentHeader().getWorkflowDocument());
   prepareWorkflowDocument(savedDocument);
   getWorkflowDocumentService()
       .superUserCancel(savedDocument.getDocumentHeader().getWorkflowDocument(), annotation);
   UserSessionUtils.addWorkflowDocument(
       GlobalVariables.getUserSession(), savedDocument.getDocumentHeader().getWorkflowDocument());
   removeAdHocPersonsAndWorkgroups(savedDocument);
   return savedDocument;
 }
 /**
  * @see
  *     org.kuali.rice.krad.service.DocumentService#routeDocument(org.kuali.rice.krad.document.Document,
  *     java.lang.String, java.util.List)
  */
 @Override
 public Document routeDocument(
     Document document, String annotation, List<AdHocRouteRecipient> adHocRecipients)
     throws ValidationException, WorkflowException {
   checkForNulls(document);
   // if (!getDocumentActionFlags(document).getCanRoute()) {
   //    throw buildAuthorizationException("route", document);
   // }
   document.prepareForSave();
   Document savedDocument = validateAndPersistDocument(document, new RouteDocumentEvent(document));
   prepareWorkflowDocument(savedDocument);
   getWorkflowDocumentService()
       .route(
           savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);
   UserSessionUtils.addWorkflowDocument(
       GlobalVariables.getUserSession(), savedDocument.getDocumentHeader().getWorkflowDocument());
   removeAdHocPersonsAndWorkgroups(savedDocument);
   return savedDocument;
 }
  /**
   * @see
   *     org.kuali.rice.krad.service.DocumentService#completeDocument(org.kuali.rice.krad.document.Document,
   *     java.lang.String, java.util.List)
   */
  @Override
  public Document completeDocument(Document document, String annotation, List adHocRecipients)
      throws WorkflowException {
    checkForNulls(document);

    document.prepareForSave();
    Document savedDocument =
        validateAndPersistDocument(document, new CompleteDocumentEvent(document));

    prepareWorkflowDocument(savedDocument);
    getWorkflowDocumentService()
        .complete(
            savedDocument.getDocumentHeader().getWorkflowDocument(), annotation, adHocRecipients);

    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), savedDocument.getDocumentHeader().getWorkflowDocument());

    removeAdHocPersonsAndWorkgroups(savedDocument);

    return savedDocument;
  }
  /**
   * This is temporary until workflow 2.0 and reads from a table to get documents whose status has
   * changed to A (approved - no outstanding approval actions requested)
   *
   * @param documentHeaderId
   * @return Document
   * @throws WorkflowException
   */
  @Override
  public Document getByDocumentHeaderId(String documentHeaderId) throws WorkflowException {
    if (documentHeaderId == null) {
      throw new IllegalArgumentException("invalid (null) documentHeaderId");
    }
    boolean internalUserSession = false;
    try {
      // KFSMI-2543 - allowed method to run without a user session so it can be used
      // by workflow processes
      if (GlobalVariables.getUserSession() == null) {
        internalUserSession = true;
        GlobalVariables.setUserSession(new UserSession(KRADConstants.SYSTEM_USER));
        GlobalVariables.clear();
      }

      WorkflowDocument workflowDocument = null;

      if (LOG.isDebugEnabled()) {
        LOG.debug("Retrieving doc id: " + documentHeaderId + " from workflow service.");
      }
      workflowDocument =
          getWorkflowDocumentService()
              .loadWorkflowDocument(documentHeaderId, GlobalVariables.getUserSession().getPerson());
      UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);

      Class<? extends Document> documentClass =
          getDocumentClassByTypeName(workflowDocument.getDocumentTypeName());

      // retrieve the Document
      Document document =
          getLegacyDataAdapter().findByDocumentHeaderId(documentClass, documentHeaderId);
      return postProcessDocument(documentHeaderId, workflowDocument, document);
    } finally {
      // if a user session was established for this call, clear it out
      if (internalUserSession) {
        GlobalVariables.clear();
        GlobalVariables.setUserSession(null);
      }
    }
  }
  @Override
  public Document recallDocument(Document document, String annotation, boolean cancel)
      throws WorkflowException {
    checkForNulls(document);
    WorkflowDocument workflowDocument =
        KRADServiceLocatorWeb.getDocumentService()
            .getByDocumentHeaderId(document.getDocumentNumber())
            .getDocumentHeader()
            .getWorkflowDocument();

    if (!workflowDocument.isFinal() && !workflowDocument.isProcessed()) {
      Note note = createNoteFromDocument(document, annotation);
      document.addNote(note);
      getNoteService().save(note);
    }

    prepareWorkflowDocument(document);
    getWorkflowDocumentService()
        .recall(document.getDocumentHeader().getWorkflowDocument(), annotation, cancel);
    UserSessionUtils.addWorkflowDocument(
        GlobalVariables.getUserSession(), document.getDocumentHeader().getWorkflowDocument());
    removeAdHocPersonsAndWorkgroups(document);
    return document;
  }
  /**
   * Creates a new document by document type name. The principal name passed in will be used as the
   * document initiator. If the initiatorPrincipalNm is null or blank, the current user will be
   * used.
   *
   * @see org.kuali.rice.krad.service.DocumentService#getNewDocument(String, String)
   */
  @Override
  public Document getNewDocument(String documentTypeName, String initiatorPrincipalNm)
      throws WorkflowException {

    // argument validation
    String watchName = "DocumentServiceImpl.getNewDocument";
    StopWatch watch = new StopWatch();
    watch.start();
    if (LOG.isDebugEnabled()) {
      LOG.debug(watchName + ": started");
    }
    if (StringUtils.isBlank(documentTypeName)) {
      throw new IllegalArgumentException("invalid (blank) documentTypeName");
    }
    if (GlobalVariables.getUserSession() == null) {
      throw new IllegalStateException(
          "GlobalVariables must be populated with a valid UserSession before a new document can be created");
    }

    // get the class for this docTypeName
    Class<? extends Document> documentClass = getDocumentClassByTypeName(documentTypeName);

    // get the initiator
    Person initiator = null;
    if (StringUtils.isBlank(initiatorPrincipalNm)) {
      initiator = GlobalVariables.getUserSession().getPerson();
    } else {
      initiator =
          KimApiServiceLocator.getPersonService().getPersonByPrincipalName(initiatorPrincipalNm);
      if (initiator == null) {
        initiator = GlobalVariables.getUserSession().getPerson();
      }
    }

    // get the authorization
    DocumentAuthorizer documentAuthorizer =
        getDocumentDictionaryService().getDocumentAuthorizer(documentTypeName);
    DocumentPresentationController documentPresentationController =
        getDocumentDictionaryService().getDocumentPresentationController(documentTypeName);
    // make sure this person is authorized to initiate
    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "calling canInitiate from getNewDocument("
              + documentTypeName
              + ","
              + initiatorPrincipalNm
              + ")");
    }
    if (!documentPresentationController.canInitiate(documentTypeName)
        || !documentAuthorizer.canInitiate(documentTypeName, initiator)) {
      throw new DocumentAuthorizationException(
          initiator.getPrincipalName(), "initiate", documentTypeName);
    }

    // initiate new workflow entry, get the workflow doc
    WorkflowDocument workflowDocument =
        getWorkflowDocumentService().createWorkflowDocument(documentTypeName, initiator);
    UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);

    // create a new document header object
    DocumentHeader documentHeader = new DocumentHeader();
    documentHeader.setWorkflowDocument(workflowDocument);
    documentHeader.setDocumentNumber(workflowDocument.getDocumentId());

    // build Document of specified type
    Document document = null;
    try {
      // all maintenance documents have same class
      if (MaintenanceDocumentBase.class.isAssignableFrom(documentClass)) {
        Class<?>[] defaultConstructor = new Class[] {String.class};
        Constructor<? extends Document> cons = documentClass.getConstructor(defaultConstructor);
        if (cons == null) {
          throw new ConfigurationException(
              "Could not find constructor with document type name parameter needed for Maintenance Document Base class");
        }
        document = cons.newInstance(documentTypeName);
      } else {
        // non-maintenance document
        document = documentClass.newInstance();
      }
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Error instantiating Document", e);
    } catch (InstantiationException e) {
      throw new RuntimeException("Error instantiating Document", e);
    } catch (SecurityException e) {
      throw new RuntimeException("Error instantiating Maintenance Document", e);
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(
          "Error instantiating Maintenance Document: No constructor with String parameter found",
          e);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException("Error instantiating Maintenance Document", e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException("Error instantiating Maintenance Document", e);
    }

    document.setDocumentHeader(documentHeader);
    document.setDocumentNumber(documentHeader.getDocumentNumber());

    watch.stop();
    if (LOG.isDebugEnabled()) {
      LOG.debug(watchName + ": " + watch.toString());
    }

    return document;
  }