@Override
  public void updateProperties(
      CallContext callContext,
      String repositoryId,
      Holder<String> objectId,
      Properties properties,
      Holder<String> changeToken) {

    exceptionService.invalidArgumentRequiredHolderString("objectId", objectId);

    Lock lock = threadLockService.getWriteLock(repositoryId, objectId.getValue());
    try {
      lock.lock();

      // //////////////////
      // Exception
      // //////////////////
      Content content =
          checkExceptionBeforeUpdateProperties(
              callContext, repositoryId, objectId, properties, changeToken);

      // //////////////////
      // Body of the method
      // //////////////////
      contentService.updateProperties(callContext, repositoryId, properties, content);

      nemakiCachePool.get(repositoryId).removeCmisCache(objectId.getValue());
    } finally {
      lock.unlock();
    }
  }
  @Override
  public void deleteContentStream(
      CallContext callContext,
      String repositoryId,
      Holder<String> objectId,
      Holder<String> changeToken,
      ExtensionsData extension) {

    exceptionService.invalidArgumentRequiredHolderString("objectId", objectId);

    Lock lock = threadLockService.getWriteLock(repositoryId, objectId.getValue());
    try {
      lock.lock();

      // //////////////////
      // Exception
      // //////////////////
      Document document = contentService.getDocument(repositoryId, objectId.getValue());
      exceptionService.objectNotFound(DomainType.OBJECT, document, document.getId());
      exceptionService.constraintContentStreamRequired(repositoryId, document);

      // //////////////////
      // Body of the method
      // //////////////////
      contentService.deleteContentStream(callContext, repositoryId, objectId);

      nemakiCachePool.get(repositoryId).removeCmisCache(objectId.getValue());

    } finally {
      lock.unlock();
    }
  }
  @Override
  public void setContentStream(
      CallContext callContext,
      String repositoryId,
      Holder<String> objectId,
      boolean overwriteFlag,
      ContentStream contentStream,
      Holder<String> changeToken) {

    exceptionService.invalidArgumentRequiredHolderString("objectId", objectId);

    Lock lock = threadLockService.getWriteLock(repositoryId, objectId.getValue());
    try {
      lock.lock();
      // //////////////////
      // General Exception
      // //////////////////

      exceptionService.invalidArgumentRequired("contentStream", contentStream);
      Document doc = (Document) contentService.getContent(repositoryId, objectId.getValue());
      exceptionService.objectNotFound(DomainType.OBJECT, doc, objectId.getValue());
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_SET_CONTENT_DOCUMENT, doc);
      DocumentTypeDefinition td =
          (DocumentTypeDefinition) typeManager.getTypeDefinition(repositoryId, doc.getObjectType());
      exceptionService.constraintImmutable(repositoryId, doc, td);

      // //////////////////
      // Specific Exception
      // //////////////////
      exceptionService.contentAlreadyExists(doc, overwriteFlag);
      exceptionService.streamNotSupported(td, contentStream);
      exceptionService.updateConflict(doc, changeToken);
      exceptionService.versioning(doc);
      Folder parent = contentService.getParent(repositoryId, objectId.getValue());
      exceptionService.objectNotFoundParentFolder(repositoryId, objectId.getValue(), parent);

      // //////////////////
      // Body of the method
      // //////////////////
      String oldId = objectId.getValue();

      // TODO Externalize versioningState
      if (doc.isPrivateWorkingCopy()) {
        Document result = contentService.replacePwc(callContext, repositoryId, doc, contentStream);
        objectId.setValue(result.getId());
      } else {
        Document result =
            contentService.createDocumentWithNewStream(
                callContext, repositoryId, doc, contentStream);
        objectId.setValue(result.getId());
      }

      nemakiCachePool.get(repositoryId).removeCmisCache(oldId);
    } finally {
      lock.unlock();
    }
  }
  @Override
  public String createRelationship(
      CallContext callContext,
      String repositoryId,
      Properties properties,
      List<String> policies,
      Acl addAces,
      Acl removeAces,
      ExtensionsData extension) {
    String objectTypeId = DataUtil.getIdProperty(properties, PropertyIds.OBJECT_TYPE_ID);
    RelationshipTypeDefinition td =
        (RelationshipTypeDefinition) typeManager.getTypeDefinition(repositoryId, objectTypeId);
    // //////////////////
    // Exception
    // //////////////////
    exceptionService.invalidArgumentRequiredCollection("properties", properties.getPropertyList());
    String sourceId = DataUtil.getIdProperty(properties, PropertyIds.SOURCE_ID);
    if (sourceId != null) {
      Content source = contentService.getContent(repositoryId, sourceId);
      if (source == null) exceptionService.constraintAllowedSourceTypes(td, source);
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_CREATE_RELATIONSHIP_SOURCE, source);
    }
    String targetId = DataUtil.getIdProperty(properties, PropertyIds.TARGET_ID);
    if (targetId != null) {
      Content target = contentService.getContent(repositoryId, targetId);
      if (target == null) exceptionService.constraintAllowedTargetTypes(td, target);
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_CREATE_RELATIONSHIP_TARGET, target);
    }

    exceptionService.constraintBaseTypeId(repositoryId, properties, BaseTypeId.CMIS_RELATIONSHIP);
    exceptionService.constraintPropertyValue(
        repositoryId, td, properties, DataUtil.getIdProperty(properties, PropertyIds.OBJECT_ID));
    exceptionService.constraintCotrollablePolicies(td, policies, properties);
    exceptionService.constraintCotrollableAcl(td, addAces, removeAces, properties);
    exceptionService.constraintPermissionDefined(repositoryId, addAces, null);
    exceptionService.constraintPermissionDefined(repositoryId, removeAces, null);
    exceptionService.nameConstraintViolation(properties, null);

    // //////////////////
    // Body of the method
    // //////////////////
    Relationship relationship =
        contentService.createRelationship(
            callContext, repositoryId, properties, policies, addAces, removeAces, extension);
    nemakiCachePool.get(repositoryId).removeCmisCache(relationship.getSourceId());
    nemakiCachePool.get(repositoryId).removeCmisCache(relationship.getTargetId());

    return relationship.getId();
  }
  @Override
  public void appendContentStream(
      CallContext callContext,
      String repositoryId,
      Holder<String> objectId,
      Holder<String> changeToken,
      ContentStream contentStream,
      boolean isLastChunk,
      ExtensionsData extension) {

    exceptionService.invalidArgumentRequiredHolderString("objectId", objectId);

    Lock lock = threadLockService.getWriteLock(repositoryId, objectId.getValue());
    try {
      lock.lock();

      // //////////////////
      // General Exception
      // //////////////////

      exceptionService.invalidArgumentRequired("contentStream", contentStream);
      Document doc = (Document) contentService.getContent(repositoryId, objectId.getValue());
      exceptionService.objectNotFound(DomainType.OBJECT, doc, objectId.getValue());
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_SET_CONTENT_DOCUMENT, doc);
      DocumentTypeDefinition td =
          (DocumentTypeDefinition) typeManager.getTypeDefinition(repositoryId, doc.getObjectType());
      exceptionService.constraintImmutable(repositoryId, doc, td);

      // //////////////////
      // Specific Exception
      // //////////////////
      exceptionService.streamNotSupported(td, contentStream);
      exceptionService.updateConflict(doc, changeToken);
      exceptionService.versioning(doc);

      // //////////////////
      // Body of the method
      // //////////////////
      contentService.appendAttachment(
          callContext, repositoryId, objectId, changeToken, contentStream, isLastChunk, extension);

      nemakiCachePool.get(repositoryId).removeCmisCache(objectId.getValue());
    } finally {
      lock.unlock();
    }
  }
  @Override
  public void moveObject(
      CallContext callContext,
      String repositoryId,
      Holder<String> objectId,
      String sourceFolderId,
      String targetFolderId) {

    exceptionService.invalidArgumentRequiredHolderString("objectId", objectId);

    Lock lock = threadLockService.getWriteLock(repositoryId, objectId.getValue());
    try {
      lock.lock();
      // //////////////////
      // General Exception
      // //////////////////
      exceptionService.invalidArgumentRequiredString("sourceFolderId", sourceFolderId);
      exceptionService.invalidArgumentRequiredString("targetFolderId", targetFolderId);
      Content content = contentService.getContent(repositoryId, objectId.getValue());
      exceptionService.objectNotFound(DomainType.OBJECT, content, objectId.getValue());
      Folder source = contentService.getFolder(repositoryId, sourceFolderId);
      exceptionService.objectNotFound(DomainType.OBJECT, source, sourceFolderId);
      Folder target = contentService.getFolder(repositoryId, targetFolderId);
      exceptionService.objectNotFound(DomainType.OBJECT, target, targetFolderId);
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_MOVE_OBJECT, content);
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_MOVE_SOURCE, source);
      exceptionService.permissionDenied(
          callContext, repositoryId, PermissionMapping.CAN_MOVE_TARGET, target);

      // //////////////////
      // Body of the method
      // //////////////////
      contentService.move(callContext, repositoryId, content, target);

      nemakiCachePool.get(repositoryId).removeCmisCache(content.getId());
    } finally {
      lock.unlock();
    }
  }