protected String saveContent(String objectId, String changeToken) {
    Holder<String> objectIdHolder = new Holder<String>(objectId);
    Holder<String> changeTokenHolder = new Holder<String>(changeToken);

    if (contentStream != null) {
      getBinding()
          .getObjectService()
          .setContentStream(
              getRepositoryId(),
              objectIdHolder,
              contentOverwrite,
              changeTokenHolder,
              contentStream,
              null);
    } else if (deleteContent) {
      getBinding()
          .getObjectService()
          .deleteContentStream(getRepositoryId(), objectIdHolder, changeTokenHolder, null);
    }

    if (objectIdHolder.getValue() != null) {
      return objectIdHolder.getValue();
    }

    return objectId;
  }
  @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();
    }
  }
  private Content checkExceptionBeforeUpdateProperties(
      CallContext callContext,
      String repositoryId,
      Holder<String> objectId,
      Properties properties,
      Holder<String> changeToken) {
    // //////////////////
    // General Exception
    // //////////////////
    exceptionService.invalidArgumentRequiredCollection("properties", properties.getPropertyList());
    Content content = contentService.getContent(repositoryId, objectId.getValue());
    exceptionService.objectNotFound(DomainType.OBJECT, content, objectId.getValue());
    if (content.isDocument()) {
      Document d = (Document) content;
      exceptionService.versioning(d);
      exceptionService.constraintUpdateWhenCheckedOut(repositoryId, callContext.getUsername(), d);
      TypeDefinition typeDef = typeManager.getTypeDefinition(repositoryId, d);
      exceptionService.constraintImmutable(repositoryId, d, typeDef);
    }
    exceptionService.permissionDenied(
        callContext, repositoryId, PermissionMapping.CAN_UPDATE_PROPERTIES_OBJECT, content);
    exceptionService.updateConflict(content, changeToken);

    TypeDefinition tdf = typeManager.getTypeDefinition(repositoryId, content);
    exceptionService.constraintPropertyValue(repositoryId, tdf, properties, objectId.getValue());

    return content;
  }
  @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();
    }
  }
  @Test
  public void testCheckInWithContent() {
    String verId = createDocument(PROP_NAME, fRootFolderId, VersioningState.MAJOR);

    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId, verId, "*", false, IncludeRelationships.NONE, null, false, false, null);
    String docId = getVersionSeriesId(verId, version.getProperties().getProperties());
    assertTrue(null != docId && docId.length() > 0);

    assertFalse(isCheckedOut(version.getProperties().getProperties()));

    Holder<Boolean> contentCopied = new Holder<Boolean>();
    Holder<String> idHolder = new Holder<String>(verId); // or should this
    // be version
    // series?
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    String pwcId = idHolder.getValue();

    ContentStream altContent = fCreator.createAlternateContent();
    Properties newProps =
        fCreator.getUpdatePropertyList(VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW);
    idHolder = new Holder<String>(pwcId);
    //        assertTrue(isCheckedOut(docId));
    assertTrue(isCheckedOut(pwcId));

    // Test check-in and pass content and properties
    String checkinComment = "Checkin with content and properties.";
    fVerSvc.checkIn(
        fRepositoryId,
        idHolder,
        true,
        newProps,
        altContent,
        checkinComment,
        null,
        null,
        null,
        null);
    // Neither the version nor the version series should be checked out any
    // longer:
    assertFalse(isCheckedOut(idHolder.getValue()));
    //        assertFalse(isCheckedOut(docId));
    ContentStream retrievedContent =
        fObjSvc.getContentStream(
            fRepositoryId,
            idHolder.getValue(),
            null,
            BigInteger.valueOf(-1) /* offset */,
            BigInteger.valueOf(-1) /* length */,
            null);

    // New content and property should be set
    assertTrue(fCreator.verifyContent(fCreator.createAlternateContent(), retrievedContent));
    assertTrue(
        fCreator.verifyProperty(
            idHolder.getValue(), VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW));
  }
 @Override
 public void invalidArgumentChangeEventNotAvailable(
     String repositoryId, Holder<String> changeLogToken) {
   if (changeLogToken != null && changeLogToken.getValue() != null) {
     Change change = contentService.getChangeEvent(repositoryId, changeLogToken.getValue());
     if (change == null)
       invalidArgument("changeLogToken:" + changeLogToken.getValue() + " does not exist");
   }
 }
  @Test
  public void testCancelCheckout() {
    String verId = createDocument(PROP_NAME, fRootFolderId, VersioningState.MAJOR);
    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId, verId, "*", false, IncludeRelationships.NONE, null, false, false, null);
    String idOfLastVersion = version.getId();
    String docId = getVersionSeriesId(verId, version.getProperties().getProperties());
    assertTrue(null != docId && docId.length() > 0);
    assertFalse(isCheckedOut(version.getProperties().getProperties()));
    Holder<Boolean> contentCopied = new Holder<Boolean>();
    Holder<String> idHolder = new Holder<String>(verId); // or should this
    // be version
    // series?
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    String pwcId = idHolder.getValue();

    // Set a new content and modify property
    Properties props = fObjSvc.getProperties(fRepositoryId, pwcId, "*", null);
    String changeToken =
        (String) props.getProperties().get(PropertyIds.CHANGE_TOKEN).getFirstValue();
    ContentStream altContent = fCreator.createAlternateContent();
    idHolder = new Holder<String>(pwcId);
    Holder<String> tokenHolder = new Holder<String>(changeToken);
    fObjSvc.setContentStream(fRepositoryId, idHolder, true, tokenHolder, altContent, null);
    fCreator.updateProperty(
        idHolder.getValue(), VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW);

    // cancel checkout
    fVerSvc.cancelCheckOut(fRepositoryId, pwcId, null);
    try {
      // Verify that pwc no longer exists
      fObjSvc.getObject(
          fRepositoryId, pwcId, "*", false, IncludeRelationships.NONE, null, false, false, null);
      fail("Getting pwc after cancel checkout should fail.");
    } catch (CmisObjectNotFoundException e1) {
    } catch (Exception e2) {
      fail(
          "Expected a CmisObjectNotFoundException after cancel checkin, but got a "
              + e2.getClass().getName());
    }

    // verify that the old content and properties are still valid
    assertTrue(
        fCreator.verifyProperty(
            idOfLastVersion, VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE));
    ContentStream retrievedContent =
        fObjSvc.getContentStream(
            fRepositoryId,
            idOfLastVersion,
            null,
            BigInteger.valueOf(-1) /* offset */,
            BigInteger.valueOf(-1) /* length */,
            null);
    assertTrue(fCreator.verifyContent(retrievedContent, fCreator.createContent()));
  }
 @Override
 public void updateConflict(Content content, Holder<String> changeToken) {
   if ((changeToken == null || changeToken.getValue() == null)) {
     throw new CmisUpdateConflictException(
         "Change token is required to update", HTTP_STATUS_CODE_409);
   } else if (!changeToken.getValue().equals(content.getChangeToken())) {
     throw new CmisUpdateConflictException(
         "Cannot update because the changeToken conflicts", HTTP_STATUS_CODE_409);
   }
 }
  public ObjectId checkIn(boolean major, String checkinComment) {
    Holder<String> objectIdHolder = new Holder<String>(getId());

    // convert properties
    Properties checkinProperties = prepareProperties();

    // prepare policies
    List<String> checkinPolicies = null;
    if ((addPolicies != null) && (!addPolicies.isEmpty())) {
      checkinPolicies = new ArrayList<String>(addPolicies);
    }

    // prepare ACLs
    List<AceChangeHolder> checkinAddAces = new ArrayList<AceChangeHolder>();
    List<AceChangeHolder> checkinRemoveAces = new ArrayList<AceChangeHolder>();
    for (AclPropagation ap : AclPropagation.values()) {
      if (addAces.containsKey(ap)) {
        checkinAddAces.addAll(addAces.get(ap));
      }
      if (removeAces.containsKey(ap)) {
        checkinAddAces.addAll(removeAces.get(ap));
      }
    }
    if (addAces.containsKey(null)) {
      checkinAddAces.addAll(addAces.get(null));
    }
    if (removeAces.containsKey(null)) {
      checkinAddAces.addAll(removeAces.get(null));
    }

    // check in
    getBinding()
        .getVersioningService()
        .checkIn(
            getRepositoryId(),
            objectIdHolder,
            major,
            checkinProperties,
            contentStream,
            checkinComment,
            checkinPolicies,
            prepareAcl(checkinAddAces),
            prepareAcl(checkinRemoveAces),
            null);

    if (objectIdHolder.getValue() != null) {
      return getSession().createObjectId(objectIdHolder.getValue());
    }

    return getObjectId();
  }
  @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 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();
    }
  }
  @Test
  public void testGetPropertiesOfLatestVersion() {
    VersioningState versioningState = VersioningState.MAJOR;
    String verId = createDocument(PROP_NAME, fRootFolderId, versioningState);
    getDocument(verId);

    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId, verId, "*", false, IncludeRelationships.NONE, null, false, false, null);
    String docId = getVersionSeriesId(verId, version.getProperties().getProperties());
    assertTrue(null != docId && docId.length() > 0);

    Holder<Boolean> contentCopied = new Holder<Boolean>();
    Holder<String> idHolder = new Holder<String>(verId); // or should this
    // be version
    // series?
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    String pwcId = idHolder.getValue();

    ContentStream altContent = fCreator.createAlternateContent();
    Properties newProps =
        fCreator.getUpdatePropertyList(VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW);
    idHolder = new Holder<String>(pwcId);
    //        assertTrue(isCheckedOut(docId));
    assertTrue(isCheckedOut(pwcId));

    // Test check-in and pass content and properties
    String checkinComment = "Checkin with content and properties.";
    fVerSvc.checkIn(
        fRepositoryId,
        idHolder,
        true,
        newProps,
        altContent,
        checkinComment,
        null,
        null,
        null,
        null);

    Properties latest =
        fVerSvc.getPropertiesOfLatestVersion(fRepositoryId, docId, docId, true, "*", null);
    assertNotNull(latest);

    checkVersionProperties(verId, versioningState, latest.getProperties(), checkinComment);
  }
  @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();
    }
  }
 @Override
 public void invalidArgumentRequiredHolderString(String argumentName, Holder<String> argument) {
   if (argument == null || isEmptyString(argument.getValue())) {
     invalidArgumentRequired(argumentName);
   }
 }
  @Test
  public void testCheckOutAndOtherUser() {
    String verId = createDocument(PROP_NAME, fRootFolderId, VersioningState.MAJOR);
    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId, verId, "*", false, IncludeRelationships.NONE, null, false, false, null);
    String docId = getVersionSeriesId(verId, version.getProperties().getProperties());
    assertTrue(null != docId && docId.length() > 0);
    assertFalse(isCheckedOut(version.getProperties().getProperties()));
    Holder<Boolean> contentCopied = new Holder<Boolean>();
    Holder<String> idHolder = new Holder<String>(verId); // or should this
    // be version
    // series?
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    String pwcId = idHolder.getValue();

    // Test that a checkin as another user is not possible
    setRuntimeContext(TEST_USER_2);
    try {
      fVerSvc.checkIn(
          fRepositoryId, idHolder, true, null, null, "My Comment", null, null, null, null);
      fail("Checking in a document as another user should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }

    // Test that a cancel checkout as another user is not possible
    try {
      fVerSvc.cancelCheckOut(fRepositoryId, pwcId, null);
      fail("Checking in a document as another user should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }

    // Test that an updateProperties as another user is not possible
    try {
      fCreator.updateProperty(pwcId, VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW);
      fail("updateProperty in a document as another user should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }

    ContentStream altContent = fCreator.createAlternateContent();
    Holder<String> pwcHolder = new Holder<String>(pwcId);
    try {
      fObjSvc.setContentStream(fRepositoryId, pwcHolder, true, null, altContent, null);
      fail("setContentStream in a document as another user should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }

    setRuntimeContext(TEST_USER);
    // Test that a check-in as same user is possible
    fVerSvc.checkIn(
        fRepositoryId,
        pwcHolder,
        true,
        null,
        null,
        "testCheckOutAndOtherUser",
        null,
        null,
        null,
        null);

    // Because nothing was changed we should have a new version with
    // identical content
    ContentStream retrievedContent =
        fObjSvc.getContentStream(
            fRepositoryId,
            pwcHolder.getValue(),
            null,
            BigInteger.valueOf(-1) /* offset */,
            BigInteger.valueOf(-1) /* length */,
            null);
    assertTrue(fCreator.verifyContent(retrievedContent, fCreator.createContent()));
    assertTrue(
        fCreator.verifyProperty(
            idHolder.getValue(), VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE));
  }
  @Test
  public void testCheckOutBasic() {
    String verId = createDocument(PROP_NAME, fRootFolderId, VersioningState.MAJOR);

    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId, verId, "*", false, IncludeRelationships.NONE, null, false, false, null);
    String docId = getVersionSeriesId(verId, version.getProperties().getProperties());
    assertTrue(null != docId && docId.length() > 0);

    assertFalse(isCheckedOut(version.getProperties().getProperties()));

    Holder<Boolean> contentCopied = new Holder<Boolean>();
    Holder<String> idHolder = new Holder<String>(verId); // or should this
    // be version
    // series?
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    String pwcId = idHolder.getValue();
    // test that object is checked out and that all properties are set
    // correctly
    Properties props = fObjSvc.getProperties(fRepositoryId, pwcId, "*", null);
    String changeToken =
        (String) props.getProperties().get(PropertyIds.CHANGE_TOKEN).getFirstValue();
    checkVersionProperties(pwcId, VersioningState.CHECKEDOUT, props.getProperties(), null);

    // Test that a second checkout is not possible
    try {
      fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
      fail("Checking out a document that is already checked-out should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }
    // version and version series should be checked out now
    //        assertTrue(isCheckedOut(docId));
    assertTrue(isCheckedOut(pwcId));

    // Set a new content and modify property
    ContentStream altContent = fCreator.createAlternateContent();
    idHolder = new Holder<String>(pwcId);
    Holder<String> tokenHolder = new Holder<String>(changeToken);
    fObjSvc.setContentStream(fRepositoryId, idHolder, true, tokenHolder, altContent, null);
    fCreator.updateProperty(
        idHolder.getValue(), VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW);

    // Test that a check-in as same user is possible
    String checkinComment = "Checkin without content and properties.";
    fVerSvc.checkIn(
        fRepositoryId, idHolder, true, null, null, checkinComment, null, null, null, null);
    // Neither the version nor the version series should be checked out any
    // longer:
    assertFalse(isCheckedOut(idHolder.getValue()));
    //        assertFalse(isCheckedOut(docId));
    ContentStream retrievedContent =
        fObjSvc.getContentStream(
            fRepositoryId,
            idHolder.getValue(),
            null,
            BigInteger.valueOf(-1) /* offset */,
            BigInteger.valueOf(-1) /* length */,
            null);
    assertTrue(fCreator.verifyContent(fCreator.createAlternateContent(), retrievedContent));
    assertTrue(
        fCreator.verifyProperty(
            idHolder.getValue(), VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW));

    List<ObjectData> allVersions =
        fVerSvc.getAllVersions(fRepositoryId, docId, docId, "*", false, null);
    assertEquals(2, allVersions.size());
  }
  @Test
  public void testGetLatestVersion() {
    VersioningState versioningState = VersioningState.MINOR;
    String verId = createDocument(PROP_NAME, fRootFolderId, versioningState);
    getDocument(verId);

    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId, verId, "*", false, IncludeRelationships.NONE, null, false, false, null);
    String docId = getVersionSeriesId(verId, version.getProperties().getProperties());
    assertTrue(null != docId && docId.length() > 0);

    Holder<Boolean> contentCopied = new Holder<Boolean>();
    Holder<String> idHolder = new Holder<String>(verId); // or should this
    // be version
    // series?
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    String pwcId = idHolder.getValue();

    ContentStream altContent = fCreator.createAlternateContent();
    Properties newProps =
        fCreator.getUpdatePropertyList(VersionTestTypeSystemCreator.PROPERTY_ID, PROP_VALUE_NEW);
    idHolder = new Holder<String>(pwcId);
    //        assertTrue(isCheckedOut(docId));
    assertTrue(isCheckedOut(pwcId));

    // Test check-in and pass content and properties
    String checkinComment = "Checkin with content and properties.";
    fVerSvc.checkIn(
        fRepositoryId,
        idHolder,
        true,
        newProps,
        altContent,
        checkinComment,
        null,
        null,
        null,
        null);

    // get latest major version
    versioningState = VersioningState.MAJOR;
    boolean isMajor = true;
    ObjectData objData =
        fVerSvc.getObjectOfLatestVersion(
            fRepositoryId,
            docId,
            docId,
            isMajor,
            "*",
            false,
            IncludeRelationships.NONE,
            null,
            false,
            false,
            null);
    checkVersionProperties(
        verId, versioningState, objData.getProperties().getProperties(), checkinComment);
    ContentStream retrievedContent =
        fObjSvc.getContentStream(
            fRepositoryId,
            objData.getId(),
            null,
            BigInteger.valueOf(-1) /* offset */,
            BigInteger.valueOf(-1) /* length */,
            null);
    assertTrue(fCreator.verifyContent(retrievedContent, fCreator.createAlternateContent()));

    // get latest non-major version, must be the same as before
    versioningState = VersioningState.MAJOR;
    isMajor = false;
    objData =
        fVerSvc.getObjectOfLatestVersion(
            fRepositoryId,
            docId,
            docId,
            isMajor,
            "*",
            false,
            IncludeRelationships.NONE,
            null,
            false,
            false,
            null);
    checkVersionProperties(
        verId, versioningState, objData.getProperties().getProperties(), checkinComment);
    retrievedContent =
        fObjSvc.getContentStream(
            fRepositoryId,
            objData.getId(),
            null,
            BigInteger.valueOf(-1) /* offset */,
            BigInteger.valueOf(-1) /* length */,
            null);
    assertTrue(fCreator.verifyContent(retrievedContent, fCreator.createAlternateContent()));
  }
  private String createVersionSeriesWithThreeVersions() {
    String verIdV1 = createDocument(PROP_NAME, fRootFolderId, VersioningState.MAJOR);
    getDocument(verIdV1);

    ObjectData version =
        fObjSvc.getObject(
            fRepositoryId,
            verIdV1,
            "*",
            false,
            IncludeRelationships.NONE,
            null,
            false,
            false,
            null);
    String verSeriesId = getVersionSeriesId(verIdV1, version.getProperties().getProperties());

    // create second version with different content
    Holder<String> idHolder = new Holder<String>(verIdV1);
    Holder<Boolean> contentCopied = new Holder<Boolean>(false);
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);

    ContentStream content2 = createContent('a');
    Properties newProps =
        fCreator.getUpdatePropertyList(
            VersionTestTypeSystemCreator.PROPERTY_ID, "PropertyFromVersion2");
    idHolder = new Holder<String>(verIdV1);
    // Test check-in and pass content and properties
    String checkinComment = "Checkin from Unit Test-2.";
    fVerSvc.checkIn(
        fRepositoryId, idHolder, true, newProps, content2, checkinComment, null, null, null, null);
    String verIdV2 = idHolder.getValue();

    // create third version with different content
    contentCopied = new Holder<Boolean>(false);
    fVerSvc.checkOut(fRepositoryId, idHolder, null, contentCopied);
    ContentStream content3 = super.createContent('a');
    newProps =
        fCreator.getUpdatePropertyList(
            VersionTestTypeSystemCreator.PROPERTY_ID, "PropertyFromVersion3");
    // Test check-in and pass content and properties
    checkinComment = "Checkin from Unit Test-3.";
    fVerSvc.checkIn(
        fRepositoryId, idHolder, true, newProps, content3, checkinComment, null, null, null, null);
    /* String verIdV3 = */ idHolder.getValue();

    // Try to update version2 which should fail (on a versioned document
    // only a document that
    // is checked out can be modified.
    try {
      fCreator.updateProperty(
          verIdV2, VersionTestTypeSystemCreator.PROPERTY_ID, "ChangeWithoutCheckout");
      fail("updateProperty for an older version should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }
    // try to set content on an older version
    ContentStream content4 = super.createContent('x');
    idHolder = new Holder<String>(verIdV2);
    try {
      fObjSvc.setContentStream(fRepositoryId, idHolder, true, null, content4, null);
      fail("setContentStream for an older version should fail.");
    } catch (Exception e) {
      assertTrue(e instanceof CmisUpdateConflictException);
    }

    return verSeriesId;
  }
    public void serve(
        CallContext context,
        CmisService service,
        String repositoryId,
        HttpServletRequest request,
        HttpServletResponse response)
        throws Exception {
      assert context != null;
      assert service != null;
      assert repositoryId != null;
      assert request != null;
      assert response != null;

      // get parameters
      String changeLogToken = getStringParameter(request, Constants.PARAM_CHANGE_LOG_TOKEN);
      Boolean includeProperties = getBooleanParameter(request, Constants.PARAM_PROPERTIES);
      String filter = getStringParameter(request, Constants.PARAM_FILTER);
      Boolean includePolicyIds = getBooleanParameter(request, Constants.PARAM_POLICY_IDS);
      Boolean includeAcl = getBooleanParameter(request, Constants.PARAM_ACL);
      BigInteger maxItems = getBigIntegerParameter(request, Constants.PARAM_MAX_ITEMS);

      // execute
      if (stopBeforeService(service)) {
        return;
      }

      Holder<String> changeLogTokenHolder = new Holder<String>(changeLogToken);
      ObjectList changes =
          service.getContentChanges(
              repositoryId,
              changeLogTokenHolder,
              includeProperties,
              filter,
              includePolicyIds,
              includeAcl,
              maxItems,
              null);

      if (stopAfterService(service)) {
        return;
      }

      if (changes == null) {
        throw new CmisRuntimeException("Changes are null!");
      }

      // set headers
      response.setStatus(HttpServletResponse.SC_OK);
      response.setContentType(Constants.MEDIATYPE_FEED);

      // write XML
      AtomFeed feed = new AtomFeed();
      feed.startDocument(response.getOutputStream(), getNamespaces(service));
      feed.startFeed(true);

      // write basic Atom feed elements
      GregorianCalendar now = new GregorianCalendar();
      feed.writeFeedElements(
          "contentChanges", null, "", "Content Change", now, null, changes.getNumItems());

      // write links
      UrlBuilder baseUrl = compileBaseUrl(request, repositoryId);

      feed.writeServiceLink(baseUrl.toString(), repositoryId);

      UrlBuilder selfLink = compileUrlBuilder(baseUrl, RESOURCE_CHANGES, null);
      selfLink.addParameter(Constants.PARAM_CHANGE_LOG_TOKEN, changeLogToken);
      selfLink.addParameter(Constants.PARAM_PROPERTIES, includeProperties);
      selfLink.addParameter(Constants.PARAM_FILTER, filter);
      selfLink.addParameter(Constants.PARAM_POLICY_IDS, includePolicyIds);
      selfLink.addParameter(Constants.PARAM_ACL, includeAcl);
      selfLink.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
      feed.writeSelfLink(selfLink.toString(), null);

      if (changeLogTokenHolder.getValue() != null) {
        if (Boolean.TRUE.equals(changes.hasMoreItems())) {
          UrlBuilder nextLink = compileUrlBuilder(baseUrl, RESOURCE_CHANGES, null);
          nextLink.addParameter(Constants.PARAM_CHANGE_LOG_TOKEN, changeLogTokenHolder.getValue());
          nextLink.addParameter(Constants.PARAM_PROPERTIES, includeProperties);
          nextLink.addParameter(Constants.PARAM_FILTER, filter);
          nextLink.addParameter(Constants.PARAM_POLICY_IDS, includePolicyIds);
          nextLink.addParameter(Constants.PARAM_ACL, includeAcl);
          nextLink.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
          feed.writeNextLink(nextLink.toString());
        }

        // The CMIS spec says that the AtomPub binding doesn't provide
        // the change log token. We are doing it anyway.
        XMLStreamWriter writer = feed.getWriter();
        writer.writeStartElement(
            XMLConstants.PREFIX_APACHE_CHEMISTY,
            "changeLogToken",
            XMLConstants.NAMESPACE_APACHE_CHEMISTRY);
        writer.writeNamespace(
            XMLConstants.PREFIX_APACHE_CHEMISTY, XMLConstants.NAMESPACE_APACHE_CHEMISTRY);
        writer.writeCharacters(changeLogTokenHolder.getValue());
        writer.writeEndElement();
      }

      // write entries
      if (changes.getObjects() != null) {
        AtomEntry entry = new AtomEntry(feed.getWriter());
        for (ObjectData object : changes.getObjects()) {
          if (object == null) {
            continue;
          }
          writeContentChangesObjectEntry(
              service,
              entry,
              object,
              null,
              repositoryId,
              null,
              null,
              baseUrl,
              false,
              context.getCmisVersion());
        }
      }

      // write extensions
      feed.writeExtensions(changes);

      // we are done
      feed.endFeed();
      feed.endDocument();
    }