/**
   * Relink the content data from a new node to an existing node to preserve the version history.
   *
   * @param tempNodeRef temp nodeRef
   * @param nodeToMoveRef NodeRef
   * @param newParentNodeRef NodeRef
   * @param newName new name
   */
  public void relinkNode(
      NodeRef tempNodeRef, NodeRef nodeToMoveRef, NodeRef newParentNodeRef, String newName)
      throws FileNotFoundException, FileExistsException {
    // Get the properties for the old and new nodes
    org.alfresco.service.cmr.model.FileInfo tempFileInfo =
        fileFolderService.getFileInfo(tempNodeRef);
    org.alfresco.service.cmr.model.FileInfo fileToMoveInfo =
        fileFolderService.getFileInfo(nodeToMoveRef);

    // Save the current name of the old node
    String tempName = tempFileInfo.getName();

    try {
      // Rename operation will add or remove the sys:temporary aspect appropriately

      // rename temp file to the new name
      fileFolderService.rename(tempNodeRef, newName);

      // rename new file to old name
      fileFolderService.rename(nodeToMoveRef, tempName);
    } catch (org.alfresco.service.cmr.model.FileNotFoundException e) {
      throw new FileNotFoundException(e.getMessage());
    } catch (org.alfresco.service.cmr.model.FileExistsException e) {
      throw new FileExistsException(e.getMessage());
    }

    if (!tempFileInfo.isFolder() && !fileToMoveInfo.isFolder()) {
      // swap the content between the two
      ContentData oldContentData = tempFileInfo.getContentData();
      if (oldContentData == null) {
        String mimetype = mimetypeService.guessMimetype(tempName);
        oldContentData = ContentData.setMimetype(null, mimetype);
      }

      ContentData newContentData = fileToMoveInfo.getContentData();

      // Reset the mime type
      // TODO Pass the content along when guessing the mime type, so we're more accurate
      String mimetype = mimetypeService.guessMimetype(newName);
      newContentData = ContentData.setMimetype(newContentData, mimetype);

      nodeService.setProperty(tempNodeRef, ContentModel.PROP_CONTENT, newContentData);
      nodeService.setProperty(nodeToMoveRef, ContentModel.PROP_CONTENT, oldContentData);
    }
  }
  @Override
  public boolean isFolder(String site, String path) {
    boolean toRet = false;
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    String rootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(rootPath, path);

    if (nodeRef != null) {
      FileInfo fileInfo = persistenceManagerService.getFileInfo(nodeRef);
      toRet = fileInfo.isFolder();
    }
    return toRet;
  }
  /**
   * get document from wcm content
   *
   * @param path
   * @return document
   * @throws ServiceException
   */
  public InputStream getContent(String path) {
    InputStream retStream = null;
    PersistenceManagerService persistenceManagerService =
        _servicesManager.getService(PersistenceManagerService.class);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(path);

    if (nodeRef != null) {
      FileInfo fileInfo = persistenceManagerService.getFileInfo(nodeRef);
      if (fileInfo.isFolder()) {
        logger.info(MSG_CONTENT_FOR_FOLDER_REQUESTED, path);
      } else {
        ContentReader reader = persistenceManagerService.getReader(nodeRef);
        retStream = reader.getContentInputStream();
      }
    } else {
      logger.info(MSG_NODE_REF_IS_NULL_FOR_PATH, path);
    }

    return retStream;
  }
  /**
   * Helper method to extract file info from a specific node.
   *
   * <p>This method goes direct to the repo for all information and no data is cached here.
   *
   * @param nodeRef the node
   * @param readOnly, should the file be shown as "read only", regardless of its permissions?
   * @param lockedFilesAsOffline should a locked file be marked as offline
   * @return Returns the file information pertinent to the node
   * @throws FileNotFoundException if the path refers to a non-existent file
   */
  private ContentFileInfo getFileInformationImpl(
      NodeRef nodeRef, boolean readOnly, boolean lockedFilesAsOffline)
      throws FileNotFoundException {
    // get the file info
    org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);

    // retrieve required properties and create new JLAN file info
    ContentFileInfo fileInfo = new ContentFileInfo(nodeRef);

    // Set the file id from the node's DBID
    long id =
        DefaultTypeConverter.INSTANCE.convert(
            Long.class, nodeService.getProperty(nodeRef, ContentModel.PROP_NODE_DBID));
    fileInfo.setFileId((int) (id & 0xFFFFFFFFL));

    // unset all attribute flags
    int fileAttributes = 0;
    fileInfo.setFileAttributes(fileAttributes);

    if (fileFolderInfo.isFolder()) {
      // add directory attribute
      fileAttributes |= FileAttribute.Directory;
      fileInfo.setFileAttributes(fileAttributes);
      fileInfo.setFileType(FileType.Directory);
    } else {
      Map<QName, Serializable> nodeProperties = fileFolderInfo.getProperties();

      // Get the file size from the content

      ContentData contentData = (ContentData) nodeProperties.get(ContentModel.PROP_CONTENT);
      long size = 0L;
      if (contentData != null) {
        size = contentData.getSize();
      }
      fileInfo.setSize(size);

      // Set the allocation size by rounding up the size to a 512 byte block boundary

      if (size > 0) {
        fileInfo.setAllocationSize((size + 512L) & 0xFFFFFFFFFFFFFE00L);
      }

      // Check whether the file is locked

      if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE)) {
        LockType lockType = lockService.getLockType(nodeRef);

        int attr = fileInfo.getFileAttributes();

        if (lockType != null) {
          switch (lockType) {
            case NODE_LOCK:
              if ((attr & FileAttribute.ReadOnly) == 0) attr += FileAttribute.ReadOnly;
              break;
            case WRITE_LOCK:
              LockStatus lockStatus = lockService.getLockStatus(nodeRef);
              if (lockStatus == LockStatus.LOCK_OWNER) {
              } else {
                if ((attr & FileAttribute.ReadOnly) == 0) {
                  attr += FileAttribute.ReadOnly;
                }

                if (lockedFilesAsOffline) {
                  attr += FileAttribute.NTOffline;
                }
              }
              break;
            case READ_ONLY_LOCK:
              if ((attr & FileAttribute.ReadOnly) == 0) {
                attr += FileAttribute.ReadOnly;
              }

              if (lockedFilesAsOffline) {
                attr += FileAttribute.NTOffline;
              }
              break;
          }

          fileInfo.setFileAttributes(attr);
        }
      }

      // Check if it is a link node

      if (fileFolderInfo.isLink()) {
        fileInfo.setLinkNodeRef(fileFolderInfo.getLinkNodeRef());
      }
    }

    // created
    Date createdDate = fileFolderInfo.getCreatedDate();
    if (createdDate != null) {
      long created = DefaultTypeConverter.INSTANCE.longValue(createdDate);
      fileInfo.setCreationDateTime(created);
    }
    // modified
    Date modifiedDate = fileFolderInfo.getModifiedDate();
    if (modifiedDate != null) {
      long modified = DefaultTypeConverter.INSTANCE.longValue(modifiedDate);
      fileInfo.setModifyDateTime(modified);
      fileInfo.setAccessDateTime(modified);
      fileInfo.setChangeDateTime(modified);
    }
    // name
    String name = fileFolderInfo.getName();
    if (name != null) {
      fileInfo.setFileName(name);

      // Check for file names that should be hidden
      if (hiddenAspect.getVisibility(Client.cifs, fileInfo.getNodeRef())
          == Visibility.HiddenAttribute) {
        // Add the hidden file attribute
        int attr = fileInfo.getFileAttributes();
        if ((attr & FileAttribute.Hidden) == 0) {
          attr += FileAttribute.Hidden;
          fileInfo.setFileAttributes(attr);
        }
      }
    }

    // Read/write access

    if (!fileFolderInfo.isFolder() || isReadOnlyFlagOnFolders) {
      boolean deniedPermission =
          permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED;
      if (readOnly || deniedPermission) {
        int attr = fileInfo.getFileAttributes();
        if ((attr & FileAttribute.ReadOnly) == 0) {
          attr += FileAttribute.ReadOnly;
          fileInfo.setFileAttributes(attr);
        }
      }
    }

    // Set the normal file attribute if no other attributes are set

    if (fileInfo.getFileAttributes() == 0) fileInfo.setFileAttributes(FileAttribute.NTNormal);

    // Debug

    if (logger.isDebugEnabled()) {
      logger.debug("Fetched file info: \n" + "   info: " + fileInfo);
    }

    // Return the file information

    return fileInfo;
  }
  @Override
  public void copyToEnvironment(String site, String environment, String path)
      throws DeploymentException {
    ServicesConfig servicesConfig = getServicesManager().getService(ServicesConfig.class);
    PersistenceManagerService persistenceManagerService =
        getServicesManager().getService(PersistenceManagerService.class);
    String siteRepoRootPath = SITE_REPO_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);

    String envRepoPath = SITE_ENVIRONMENT_ROOT_PATTERN.replaceAll(SITE_REPLACEMENT_PATTERN, site);
    envRepoPath = envRepoPath.replaceAll(ENVIRONMENT_REPLACEMENT_PATTERN, environment);

    NodeRef envRepoRoot = persistenceManagerService.getNodeRef(envRepoPath);

    NodeRef envNode = persistenceManagerService.getNodeRef(envRepoRoot, path);
    NodeRef nodeRef = persistenceManagerService.getNodeRef(siteRepoRootPath, path);
    if (nodeRef != null) {
      if (envNode == null) {
        envNode = createLiveRepositoryCopy(envRepoRoot, path, nodeRef);
      } else {
        FileInfo envNodeInfo = persistenceManagerService.getFileInfo(envNode);
        if (envNodeInfo.isFolder()) {
          Map<QName, Serializable> copyNodeProps = persistenceManagerService.getProperties(nodeRef);
          copyNodeProps.put(ContentModel.PROP_NAME, envNodeInfo.getName());
          persistenceManagerService.setProperties(envNode, copyNodeProps);
        } else {
          persistenceManagerService.copy(nodeRef, envNode);
        }
      }
      Serializable sendEmailValue =
          persistenceManagerService.getProperty(
              nodeRef, CStudioContentModel.PROP_WEB_WF_SEND_EMAIL);
      boolean sendEmail = (sendEmailValue != null) && (Boolean) sendEmailValue;

      if (sendEmail) {
        Serializable submittedByValue =
            persistenceManagerService.getProperty(
                nodeRef, CStudioContentModel.PROP_WEB_WF_SUBMITTED_BY);
        String submittedBy = "";
        if (submittedByValue != null) {
          submittedBy = (String) submittedByValue;
        } else {
          logger.error("did not send approval notification as submitted by property is null");
          return;
        }
        // DmPathTO path = new DmPathTO(nodePath);
        String approver =
            (String)
                persistenceManagerService.getProperty(
                    nodeRef, CStudioContentModel.PROP_WEB_APPROVED_BY);
        NotificationService notificationService =
            getServicesManager().getService(NotificationService.class);
        notificationService.sendApprovalNotification(site, submittedBy, path, approver);
        /*
         * Remove this sendmail property as we are done sending email
         */
        persistenceManagerService.removeProperty(
            nodeRef, CStudioContentModel.PROP_WEB_WF_SEND_EMAIL);
      }

      Map<QName, Serializable> nodeProps = persistenceManagerService.getProperties(envNode);
      for (QName propName : DmConstants.SUBMITTED_PROPERTIES) {
        nodeProps.remove(propName);
      }
      persistenceManagerService.setProperties(envNode, nodeProps);

      nodeProps = persistenceManagerService.getProperties(nodeRef);
      for (QName propName : DmConstants.SUBMITTED_PROPERTIES) {
        nodeProps.remove(propName);
      }
      persistenceManagerService.setProperties(nodeRef, nodeProps);
    }
  }