content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  package org.apache.chemistry.opencmis.inmemory;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertTrue;
  import static org.junit.Assert.fail;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.PrintStream;
  import java.io.UnsupportedEncodingException;
  import java.math.BigInteger;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.chemistry.opencmis.commons.PropertyIds;
  import org.apache.chemistry.opencmis.commons.data.Acl;
  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
  import org.apache.chemistry.opencmis.commons.data.BulkUpdateObjectIdAndChangeToken;
  import org.apache.chemistry.opencmis.commons.data.ContentStream;
  import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
  import org.apache.chemistry.opencmis.commons.data.ObjectData;
  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
  import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
  import org.apache.chemistry.opencmis.commons.data.Properties;
  import org.apache.chemistry.opencmis.commons.data.PropertyData;
  import org.apache.chemistry.opencmis.commons.data.RenditionData;
  import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutableDocumentTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutableFolderTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutableItemTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutablePolicyTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutableRelationshipTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutableSecondaryTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.MutableTypeDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
  import org.apache.chemistry.opencmis.commons.enums.Action;
  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
  import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
  import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
  import org.apache.chemistry.opencmis.commons.enums.Updatability;
  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
  import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
  import org.apache.chemistry.opencmis.commons.impl.IOUtils;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.BulkUpdateObjectIdAndChangeTokenImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.spi.Holder;
  import org.apache.chemistry.opencmis.inmemory.content.ObjectGenerator;
  import org.apache.chemistry.opencmis.inmemory.storedobj.impl.ContentStreamDataImpl;
  import org.apache.chemistry.opencmis.inmemory.storedobj.impl.RenditionUtil;
  import org.apache.chemistry.opencmis.inmemory.types.DocumentTypeCreationHelper;
  import org.apache.chemistry.opencmis.inmemory.types.PropertyCreationHelper;
  import org.apache.chemistry.opencmis.server.support.TypeDefinitionFactory;
  import org.junit.After;
  import org.junit.Before;
  import org.junit.Test;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class ObjectServiceTest extends AbstractServiceTest {
  
      private static final Logger log = LoggerFactory.getLogger(ObjectServiceTest.class);
      public static final String TEST_FOLDER_TYPE_ID = "MyFolderType";
      public static final String TEST_DOCUMENT_TYPE_ID = "MyDocumentType";
      public static final String TEST_DOC_TYPE_WITH_DEFAULTS_ID = "DocumentTypeWithDefault";
      public static final String TEST_FOLDER_TYPE_WITH_DEFAULTS_ID = "FolderTypeWithDefault";
      public static final String TEST_FOLDER_STRING_PROP_ID = "MyFolderStringProp";
      public static final String TEST_DOCUMENT_STRING_PROP_ID = "MyDocumentStringProp";
      public static final String TEST_VERSION_DOCUMENT_TYPE_ID = "MyVersionedType";
      public static final String TEST_VER_PROPERTY_ID = "VerStringProp";
      public static final String TEST_CUSTOM_DOCUMENT_TYPE_ID = "MyCustomDocumentType";
      public static final String TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID = "MyCustomInheritedDocType";
      public static final String TEST_CUSTOM_NO_CONTENT_TYPE_ID = "NoContentType";
      public static final String TEST_CUSTOM_MUST_CONTENT_TYPE_ID = "MustHaveContentType";
      public static final String TEST_DOCUMENT_MY_STRING_PROP_ID = "MyCustomDocumentStringProp";
      public static final String TEST_DOCUMENT_MY_MULTI_STRING_PROP_ID = "MyCustomDocumentMultiStringProp";
      public static final String TEST_DOCUMENT_MY_INT_PROP_ID = "MyCustomDocumentIntProp";
      public static final String TEST_DOCUMENT_MY_INT_PROP_ID_MANDATORY_DEFAULT = "MyCustomDocumentIntPropMandatoryDefault";
      public static final String TEST_FOLDER_MY_MULTI_STRING_PROP_ID = "MyCustomDocumentMultiStringProp";
      public static final String TEST_FOLDER_MY_INT_PROP_ID = "MyCustomDocumentIntProp";
      public static final String TEST_FOLDER_MY_INT_PROP_ID_MANDATORY_DEFAULT = "MyCustomDocumentIntPropMandatoryDefault";
      public static final String TEST_DOCUMENT_MY_SUB_STRING_PROP_ID = "MyInheritedStringProp";
      public static final String TEST_DOCUMENT_MY_SUB_INT_PROP_ID = "MyInheritedIntProp";
      public static final String TEST_ITEM_TYPE_ID = "MyItemType";
      public static final String ITEM_STRING_PROP = "ItemStringProp";
      private static final String DOCUMENT_TYPE_ID = DocumentTypeCreationHelper.getCmisDocumentType().getId();
      private static final String DOCUMENT_ID = "Document_1";
      private static final String FOLDER_TYPE_ID = DocumentTypeCreationHelper.getCmisFolderType().getId();
      private static final String FOLDER_ID = "Folder_1";
      private static final String MY_CUSTOM_NAME = "My Custom Document";
      private static final int MAX_SIZE = 100;
      private static final String PNG = "image/png";
      private static final String JPEG = "image/jpeg";
      private static final String NEW_STRING_PROP_VAL = "My ugly string 1";
      private static final BigInteger NEW_INT_PROP_VAL = BigInteger.valueOf(815);
      public static final String TEST_SECONDARY_TYPE_ID = "MySecondaryType";
      public static final String SECONDARY_STRING_PROP = "SecondaryStringProp";
      public static final String SECONDARY_INTEGER_PROP = "SecondaryIntegerProp";
      public static final String REL_STRING_PROP = "CrossReferenceKind";
      public static final String TEST_RELATION_TYPE_ID = "CrossReferenceType";
      public static final String TEST_RESTRICTED_RELATION_TYPE_ID = "RestrictedRelationType";
      public static final String TEST_POLICY_TYPE_ID = "AuditPolicy";
      public static final String TEST_POLICY_PROPERTY_ID = "AuditSettings";
      private static final String ENCODING_UTF8 = "UTF-8";
  
      ObjectCreator fCreator;
  
      @Override
      @Before
      public void setUp() {
          super.setTypeCreatorClass(ObjectTestTypeSystemCreator.class.getName());
          super.setUp();
          fCreator = new ObjectCreator(fFactory, fObjSvc, fRepositoryId);
      }
  
      @Override
      @After
      public void tearDown() {
          super.tearDown();
      }
  
      @Override
      protected void addParameters(Map<String, String> parameters) {
          parameters.put(ConfigConstants.MAX_CONTENT_SIZE_KB, Integer.valueOf(MAX_SIZE).toString());
      }
  
      @Test
      public void testCreateDocument() {
          log.info("starting testCreateObject() ...");
          String id = createDocument(fRootFolderId, false);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
          log.info("... testCreateObject() finished.");
  
          // test create a document with a folder type, should fail:
          try {
              Properties props = createDocumentProperties("DocumentWithAFolderType", FOLDER_TYPE_ID);
              id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, null, VersioningState.NONE, null, null,
                      null, null);
              assertNotNull(id);
              fail("Creating  document with a folder type should fail.");
          } catch (Exception e) {
              log.info("Creating  document with a folder type failed as expected.");
          }
          // test create a document with an illegal name, should fail:
          try {
              Properties props = createDocumentProperties("abc (:*)", DOCUMENT_TYPE_ID);
              fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, null, VersioningState.NONE, null, null, null,
                      null);
              fail("Creating  document with an illegal name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
              log.info("Creating  document with an illegal name failed as expected.");
          }
      }
  
      @Test
      public void testCreateDocumentInvalidNames() {
          try {
              createDocumentNoCatch(null, fRootFolderId, DOCUMENT_TYPE_ID, VersioningState.NONE, false);
              fail("Document creation with null name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
          }
  
          try {
              createDocumentNoCatch("", fRootFolderId, DOCUMENT_TYPE_ID, VersioningState.NONE, false);
              fail("Document creation with empty name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
          }
  
          try {
              createDocumentNoCatch("/(%#$a������������", fRootFolderId, DOCUMENT_TYPE_ID, VersioningState.NONE, false);
              fail("Document creation with ilegal name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
          }
  
          try {
              createDocumentNoCatch("DuplicatedName", fRootFolderId, DOCUMENT_TYPE_ID, VersioningState.NONE, false);
              createDocumentNoCatch("DuplicatedName", fRootFolderId, DOCUMENT_TYPE_ID, VersioningState.NONE, false);
              fail("Document creation with existing name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisNameConstraintViolationException);
          }
      }
  
      @Test
      public void testCreateFolderInvalidNames() {
          try {
              createFolderNoCatch(null, fRootFolderId, FOLDER_TYPE_ID);
              fail("Folder creation with null name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
          }
  
          try {
              createFolderNoCatch("", fRootFolderId, FOLDER_TYPE_ID);
              fail("Folder creation with empty name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
          }
  
          try {
              createFolderNoCatch(
                      "/(%#$���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������",
                      fRootFolderId, FOLDER_TYPE_ID);
              fail("Folder creation with ilegal name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisInvalidArgumentException);
          }
  
          try {
              createFolderNoCatch("DuplicatedName", fRootFolderId, FOLDER_TYPE_ID);
              createFolderNoCatch("DuplicatedName", fRootFolderId, FOLDER_TYPE_ID);
              fail("Folder creation with existing name should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisNameConstraintViolationException || e instanceof IllegalArgumentException);
          }
      }
  
      @Test
      public void testGetObject() {
          log.info("starting testGetObject() ...");
          log.info("  creating object");
          String id = createDocument(fRootFolderId, false);
          if (id != null) {
              log.info("  createDocument succeeded with created id: " + id);
          }
  
          log.info("  getting object");
          retrieveDocument(id);
          log.info("... testGetObject() finished.");
      }
  
      @Test
      public void testGetObjectByPath() {
          log.info("starting testGetObjectByPath() ...");
          log.info("  creating object");
  
          // create a tree for testing paths
          String f1 = createFolder("folder1", fRootFolderId, FOLDER_TYPE_ID);
          String f2 = createFolder("folder2", fRootFolderId, FOLDER_TYPE_ID);
          String f3 = createFolder("folder3", fRootFolderId, FOLDER_TYPE_ID);
          String f11 = createFolder("folder1.1", f1, FOLDER_TYPE_ID);
          String f12 = createFolder("folder1.2", f1, FOLDER_TYPE_ID);
          String f13 = createFolder("folder1.3", f1, FOLDER_TYPE_ID);
          String f31 = createFolder("folder3.1", f3, FOLDER_TYPE_ID);
          String f32 = createFolder("folder3.2", f3, FOLDER_TYPE_ID);
          String f33 = createFolder("folder3.3", f3, FOLDER_TYPE_ID);
          String f121 = createFolder("folder1.2.1", f12, FOLDER_TYPE_ID);
          String f122 = createFolder("folder1.2.2", f12, FOLDER_TYPE_ID);
          String f123 = createFolder("folder1.2.3", f12, FOLDER_TYPE_ID);
          String f331 = createFolder("folder3.3.1", f33, FOLDER_TYPE_ID);
          String f332 = createFolder("folder3.3.2", f33, FOLDER_TYPE_ID);
          String f333 = createFolder("folder3.3.3", f33, FOLDER_TYPE_ID);
          String doc12 = createDocument("Document1.2.Doc", f12, false);
          String doc33 = createDocument("Document3.3.Doc", f33, false);
          String doc331 = createDocument("Document3.3.1.Doc", f331, false);
          String doc333 = createDocument("Document3.3.3.Doc", f333, false);
  
          log.info("  getting object by path");
          getByPath(f1, "/folder1");
          getByPath(f2, "/folder2");
          getByPath(f3, "/folder3");
          getByPath(f11, "/folder1/folder1.1");
          getByPath(f12, "/folder1/folder1.2");
          getByPath(f13, "/folder1/folder1.3");
          getByPath(f31, "/folder3/folder3.1");
          getByPath(f32, "/folder3/folder3.2");
          getByPath(f33, "/folder3/folder3.3");
          getByPath(f121, "/folder1/folder1.2/folder1.2.1");
          getByPath(f122, "/folder1/folder1.2/folder1.2.2");
          getByPath(f123, "/folder1/folder1.2/folder1.2.3");
          getByPath(f331, "/folder3/folder3.3/folder3.3.1");
          getByPath(f332, "/folder3/folder3.3/folder3.3.2");
          getByPath(f333, "/folder3/folder3.3/folder3.3.3");
          getByPath(doc12, "/folder1/folder1.2/Document1.2.Doc");
          getByPath(doc33, "/folder3/folder3.3/Document3.3.Doc");
          getByPath(doc331, "/folder3/folder3.3/folder3.3.1/Document3.3.1.Doc");
          getByPath(doc333, "/folder3/folder3.3/folder3.3.3/Document3.3.3.Doc");
  
          log.info("... testGetObjectByPath() finished.");
      }
  
      @Test
      public void testCreateDocumentWithContent() {
          log.info("starting testCreateDocumentWithContent() ...");
          String id = createDocument(fRootFolderId, true);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
  
          ContentStream sd = fObjSvc.getContentStream(fRepositoryId, id, null, BigInteger.valueOf(-1) /* offset */,
                  BigInteger.valueOf(-1) /* length */, null);
          verifyContentResult(sd);
  
          // delete content again
          Holder<String> idHolder = new Holder<String>(id);
          Properties props = fObjSvc.getProperties(fRepositoryId, id, PropertyIds.CHANGE_TOKEN, null);
          String changeToken = (String) props.getProperties().get(PropertyIds.CHANGE_TOKEN).getFirstValue();
          Holder<String> tokenHolder = new Holder<String>(changeToken);
          fObjSvc.deleteContentStream(fRepositoryId, idHolder, tokenHolder, null);
  
          try {
              props = fObjSvc.getProperties(fRepositoryId, id, PropertyIds.CHANGE_TOKEN, null);
              changeToken = (String) props.getProperties().get(PropertyIds.CHANGE_TOKEN).getFirstValue();
              tokenHolder = new Holder<String>(changeToken);
              sd = fObjSvc.getContentStream(fRepositoryId, id, null, BigInteger.valueOf(-1) /* offset */,
                      BigInteger.valueOf(-1) /* length */, null);
              fail("getContentStream with non existing content should raise a CmisConstraintException");
          } catch (Exception e) {
              assertTrue(e instanceof CmisConstraintException);
          }
  
          // create content again in a second call
          ContentStream contentStream = createContent();
          fObjSvc.setContentStream(fRepositoryId, idHolder, true, tokenHolder, contentStream, null);
          sd = fObjSvc.getContentStream(fRepositoryId, id, null, BigInteger.valueOf(-1) /* offset */,
                  BigInteger.valueOf(-1) /* length */, null);
          verifyContentResult(sd);
  
          // update content and do not set overwrite flag, expect failure
          try {
              props = fObjSvc.getProperties(fRepositoryId, id, PropertyIds.CHANGE_TOKEN, null);
              changeToken = (String) props.getProperties().get(PropertyIds.CHANGE_TOKEN).getFirstValue();
              tokenHolder = new Holder<String>(changeToken);
              fObjSvc.setContentStream(fRepositoryId, idHolder, false, tokenHolder, contentStream, null);
              fail("setContentStream with existing content and no overWriteFlag should fail");
          } catch (Exception e) {
              assertTrue(e instanceof CmisContentAlreadyExistsException);
          }
  
          // cleanup
          fObjSvc.deleteObject(fRepositoryId, id, true, null);
  
          log.info("... testCreateDocumentWithContent() finished.");
      }
  
      @Test
      public void testCreateDocumentWithContentNoFileNameNoMimeType() {
          log.info("starting testCreateDocumentWithContent() ...");
          ContentStreamDataImpl contentStream = null;
          List<String> policies = null;
          Acl addACEs = null;
          Acl removeACEs = null;
          ExtensionsData extension = null;
  
          Properties props = createDocumentProperties(DOCUMENT_ID, DOCUMENT_TYPE_ID);
  
          contentStream = (ContentStreamDataImpl) createContent();
          contentStream.setFileName(null);
          contentStream.setMimeType(null);
  
          String id = null;
          try {
              id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, contentStream, VersioningState.NONE,
                      policies, addACEs, removeACEs, extension);
              if (null == id) {
                  fail("createDocument failed.");
              }
  
              ContentStream sd = fObjSvc.getContentStream(fRepositoryId, id, null, BigInteger.valueOf(-1) /* offset */,
                      BigInteger.valueOf(-1) /* length */, null);
              assertNotNull(sd.getMimeType());
              assertNotNull(sd.getFileName());
          } catch (Exception e) {
              fail("createDocument() failed with exception: " + e);
          }
      }
  
      @Test
      public void testCreateDocumentFromSource() {
          log.info("starting testCreateDocumentFromSource() ...");
          // create a 1st document
          String id1 = createDocument(fRootFolderId, true);
          // create a second document with first as source
          String id2 = null;
          try {
              VersioningState versioningState = VersioningState.NONE;
              Properties props = createDocumentPropertiesForDocumentFromSource("Document From Source");
              id2 = fObjSvc.createDocumentFromSource(fRepositoryId, id1, props, fRootFolderId, versioningState, null,
                      null, null, null);
              if (null == id2) {
                  fail("createDocumentFromSource failed.");
              }
          } catch (Exception e) {
              fail("createDocumentFromSource() failed with exception: " + e);
          }
  
          // get content from second document and compare it with original one
          ContentStream sd = fObjSvc.getContentStream(fRepositoryId, id2, null, BigInteger.valueOf(-1) /* offset */,
                  BigInteger.valueOf(-1) /* length */, null);
          verifyContentResult(sd);
  
          // cleanup
          fObjSvc.deleteObject(fRepositoryId, id1, true, null);
          fObjSvc.deleteObject(fRepositoryId, id2, true, null);
  
          log.info("... testCreateDocumentFromSource() finished.");
      }
  
      @Test
      public void testCreatedDocumentInherited() {
          log.info("starting testCreatedDocumentInherited() ...");
          log.info("  creating object");
  
          String id = createDocumentInheritedProperties(fRootFolderId, false);
          if (id != null) {
              log.info("  createDocument succeeded with created id: " + id);
          }
  
          log.info("  getting object");
          try {
              ObjectData res = fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false,
                      false, null);
              assertNotNull(res);
  
              String returnedId = res.getId();
              assertEquals(id, returnedId);
              Map<String, PropertyData<?>> props = res.getProperties().getProperties();
              for (PropertyData<?> pd : props.values()) {
                  log.info("return property id: " + pd.getId() + ", value: " + pd.getValues());
              }
  
              PropertyData<?> pd = props.get(PropertyIds.NAME);
              assertNotNull(pd);
              assertEquals(MY_CUSTOM_NAME, pd.getFirstValue());
  
              pd = props.get(PropertyIds.OBJECT_TYPE_ID);
              assertEquals(TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID, pd.getFirstValue());
  
              pd = props.get(TEST_DOCUMENT_MY_STRING_PROP_ID);
              assertEquals("My pretty string", pd.getFirstValue());
  
              pd = props.get(TEST_DOCUMENT_MY_INT_PROP_ID);
              assertEquals(BigInteger.valueOf(4711), pd.getFirstValue());
  
              pd = props.get(TEST_DOCUMENT_MY_SUB_STRING_PROP_ID);
              assertEquals("another cool string", pd.getFirstValue());
  
              pd = props.get(TEST_DOCUMENT_MY_SUB_INT_PROP_ID);
              assertEquals(BigInteger.valueOf(4712), pd.getFirstValue());
          } catch (Exception e) {
              fail("getObject() failed with exception: " + e);
          }
          log.info("... testCreatedDocumentInherited() finished.");
      }
  
      @Test
      public void testBuildFolderAndDocuments() {
          // Create a hierarchy of folders and fill it with some documents
  
          ObjectGenerator gen = new ObjectGenerator(fFactory, fNavSvc, fObjSvc, fRepSvc, fRepositoryId,
                  ObjectGenerator.ContentKind.LOREM_IPSUM_TEXT);
          int levels = 2; // create a hierarchy with two levels
          int childrenPerLevel = 2; // create two folders on each level
  
          gen.setNumberOfDocumentsToCreatePerFolder(1); // create one document in
          // each folder
  
          // Set the type id for all created documents:
          gen.setDocumentTypeId(TEST_DOCUMENT_TYPE_ID);
  
          // Set the type id for all created folders:
          gen.setFolderTypeId(TEST_FOLDER_TYPE_ID);
  
          // set the properties the generator should fill with values for
          // documents:
          // Note: must be valid properties in type TEST_DOCUMENT_TYPE_ID
          List<String> propsToSet = new ArrayList<String>();
          propsToSet.add(TEST_DOCUMENT_STRING_PROP_ID);
          gen.setDocumentPropertiesToGenerate(propsToSet);
  
          // set the properties the generator should fill with values for folders:
          // Note: must be valid properties in type TEST_FOLDER_TYPE_ID
          propsToSet = new ArrayList<String>();
          propsToSet.add(TEST_FOLDER_STRING_PROP_ID);
          gen.setFolderPropertiesToGenerate(propsToSet);
  
          // Build the tree
          try {
              gen.createFolderHierachy(levels, childrenPerLevel, fRootFolderId);
              // Dump the tree
              gen.dumpFolder(fRootFolderId, "*");
          } catch (Exception e) {
              fail("Could not create folder hierarchy with documents. " + e);
          }
      }
  
      @Test
      public void testDeleteObject() {
          log.info("starting testDeleteObject() ...");
          log.info("Testing to delete a document");
          log.info("  creating object");
          String id = createDocument(fRootFolderId, false);
          if (id != null) {
              log.info("  createDocument succeeded with created id: " + id);
          }
  
          log.info("  getting object");
          retrieveDocument(id);
          log.info("  deleting object");
          try {
              fObjSvc.deleteObject(fRepositoryId, id, true, null);
          } catch (Exception e) {
              fail("deleteObject() for document failed with exception: " + e);
          }
  
          // check that it does not exist anymore
          try {
              fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false, false, null);
              fail("object should not longer exist after it was deleted.");
          } catch (CmisObjectNotFoundException e) {
              assertTrue(e instanceof CmisObjectNotFoundException);
          } catch (Exception e) {
              fail("getting deleted object should raise CMISObjectNotFoundException, but got " + e);
          }
  
          log.info("Testing to delete an empty folder");
          // create and delete an empty folder
          id = createFolder();
          try {
              fObjSvc.deleteObject(fRepositoryId, id, true, null);
          } catch (Exception e) {
              fail("deleteObject() for folder failed with exception: " + e);
          }
          // check that it does not exist anymore
          try {
              fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false, false, null);
              fail("object should not longer exist after it was deleted.");
          } catch (CmisObjectNotFoundException e) {
              assertTrue(e instanceof CmisObjectNotFoundException);
          } catch (Exception e) {
              fail("getting deleted object should raise CMISObjectNotFoundException, but got " + e);
          }
  
          // create a folder with a document and delete should fail
          // create and delete an empty folder
          log.info("Testing to delete a folder with a contained document");
          String folderId;
          folderId = createFolder();
          id = createDocument(folderId, false);
  
          try {
              fObjSvc.deleteObject(fRepositoryId, folderId, true, null);
              fail("deleteObject() for folder with a document should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisConstraintException);
          }
          // should succeed if we first delete document then folder
          try {
              fObjSvc.deleteObject(fRepositoryId, id, true, null);
              fObjSvc.deleteObject(fRepositoryId, folderId, true, null);
          } catch (Exception e) {
              fail("deleteObject() for document and folder failed with exception: " + e);
          }
          // check that it does not exist anymore
          try {
              fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false, false, null);
              fail("object should not longer exist after it was deleted.");
          } catch (CmisObjectNotFoundException e) {
              assertTrue(e instanceof CmisObjectNotFoundException);
          } catch (Exception e) {
              fail("getting deleted object should raise CMISObjectNotFoundException, but got " + e);
          }
          try {
              fObjSvc.getObject(fRepositoryId, folderId, "*", false, IncludeRelationships.NONE, null, false, false, null);
              fail("object should not longer exist after it was deleted.");
          } catch (CmisObjectNotFoundException e) {
              assertTrue(e instanceof CmisObjectNotFoundException);
          } catch (Exception e) {
              fail("getting deleted object should raise CMISObjectNotFoundException, but got " + e);
          }
          log.info("... testDeleteObject() finished.");
      }
  
      @Test
      public void testDeleteTree() {
          log.info("starting testDeleteTree() ...");
          ObjectGenerator gen = new ObjectGenerator(fFactory, fNavSvc, fObjSvc, fRepSvc, fRepositoryId,
                  ObjectGenerator.ContentKind.LOREM_IPSUM_TEXT);
          String rootFolderId = createFolder();
          // Set the type id for all created documents:
          gen.setDocumentTypeId(DocumentTypeCreationHelper.getCmisDocumentType().getId());
          // Set the type id for all created folders:
          gen.setFolderTypeId(DocumentTypeCreationHelper.getCmisFolderType().getId());
          gen.setNumberOfDocumentsToCreatePerFolder(2); // create two documents in
          // each folder
          gen.createFolderHierachy(1, 1, rootFolderId);
          try {
              fObjSvc.deleteTree(fRepositoryId, rootFolderId, null /* true */, UnfileObject.DELETE, true, null);
          } catch (Exception e) {
              fail("deleteTree failed unexpected. " + e);
          }
          log.info("Dumping folder, should only contain one empty folder under root");
          gen.dumpFolder(fRootFolderId, "*");
  
          // After that we should be not be able to get the root folder, because
          // it should be deleted
          try {
              fObjSvc.getObject(fRepositoryId, rootFolderId, "*", false, IncludeRelationships.NONE, null, false, false,
                      null);
              fail("object should not longer exist after it was deleted.");
          } catch (CmisObjectNotFoundException e) {
              assertTrue(e instanceof CmisObjectNotFoundException);
          } catch (Exception e) {
              fail("getting deleted object should raise CMISObjectNotFoundException, but got " + e);
          }
          log.info("... testDeleteTree() finished.");
      }
  
      @Test
      public void testMoveFolder() {
          log.info("starting testMoveFolder() ...");
          moveObjectTest(true);
          log.info("... testMoveFolder() finished.");
      }
  
      @Test
      public void testMoveDocument() {
          log.info("starting testMoveDocument() ...");
          moveObjectTest(false);
          log.info("... testMoveDocument() finished.");
      }
  
      @Test
      public void testUpdateProperties() {
          // TODO add test rename root folder and non root folder (must be a
          // folder)
          log.info("starting testUpdateProperties() ...");
          String oldChangeToken, newChangeToken;
          String id = createDocumentWithCustomType(MY_CUSTOM_NAME, fRootFolderId, false);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
  
          log.info("  getting object");
          try {
              ObjectData res = fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false,
                      false, null);
              assertNotNull(res);
              Map<String, PropertyData<?>> props = res.getProperties().getProperties();
  
              // check returned properties
              for (PropertyData<?> pd : props.values()) {
                  log.info("  return property id: " + pd.getId() + ", value: " + pd.getValues());
              }
  
              String returnedId = res.getId();
              assertEquals(id, returnedId);
              PropertyData<?> pd = props.get(PropertyIds.NAME);
              assertNotNull(pd);
              assertEquals(MY_CUSTOM_NAME, pd.getFirstValue());
              pd = props.get(PropertyIds.OBJECT_TYPE_ID);
              assertEquals(TEST_CUSTOM_DOCUMENT_TYPE_ID, pd.getFirstValue());
              pd = props.get(TEST_DOCUMENT_MY_STRING_PROP_ID);
              assertEquals("My pretty string", pd.getFirstValue());
              pd = props.get(TEST_DOCUMENT_MY_INT_PROP_ID);
              assertEquals(BigInteger.valueOf(4711), pd.getFirstValue());
  
              // update properties:
              log.info("updating property");
              List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
              // properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_NAME
              // , MY_CUSTOM_NAME));
              // properties.add(fFactory.createPropertyIdData(PropertyIds.
              // CMIS_OBJECT_TYPE_ID, TEST_CUSTOM_DOCUMENT_TYPE_ID));
              // Generate some property values for custom attributes
              properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID, NEW_STRING_PROP_VAL));
              properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, NEW_INT_PROP_VAL));
              Properties newProps = fFactory.createPropertiesData(properties);
  
              Holder<String> idHolder = new Holder<String>(id);
              Holder<String> changeTokenHolder = new Holder<String>();
              fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
              oldChangeToken = changeTokenHolder.getValue(); // store for later
              verifyUpdatedProperties(id, MY_CUSTOM_NAME);
  
              // Test delete properties
              log.info("deleting property");
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID, (String) null));
              newProps = fFactory.createPropertiesData(properties);
              Thread.sleep(100); // ensure new change token, timer resolution is
              // not good enough
              fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
              res = fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false, false, null);
              assertNotNull(res);
              props = res.getProperties().getProperties();
              for (PropertyData<?> pd2 : props.values()) {
                  log.info("  return property id: " + pd2.getId() + ", value: " + pd2.getValues());
              }
              pd = props.get(TEST_DOCUMENT_MY_STRING_PROP_ID);
              assertNull(pd.getFirstValue());
              // delete a required property and expect exception:
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, (BigInteger) null));
              newProps = fFactory.createPropertiesData(properties);
              idHolder = new Holder<String>(id);
              try {
                  fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
                  fail("Deleteing a required property should fail.");
              } catch (Exception e) {
                  assertTrue(e instanceof CmisConstraintException);
              }
  
              // Test violation of property definition constraints
              log.info("Test violation of property definition constraints");
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID,
                      "A very long String ABCDEFHIJKLMNOPQRSTUVWXYZ"));
              newProps = fFactory.createPropertiesData(properties);
              idHolder = new Holder<String>(id);
              try {
                  fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
                  fail("Exceeding max String lengt h should fail.");
              } catch (Exception e) {
                  assertTrue(e instanceof CmisConstraintException);
              }
              // Test stale token
              log.info("Test stale token");
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID, "ABC"));
              newProps = fFactory.createPropertiesData(properties);
              // set outdated token
              newChangeToken = changeTokenHolder.getValue();
              changeTokenHolder.setValue(oldChangeToken);
              assertFalse(oldChangeToken.equals(newChangeToken));
              try {
                  fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
                  fail("Update with an outdated changeToken should fail.");
              } catch (Exception e) {
                  assertTrue(e instanceof CmisUpdateConflictException);
              }
  
              // test a rename
              log.info("Test renaming");
              final String newName = "My Renamed Document"; // MY_CUSTOM_NAME
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, newName));
              newProps = fFactory.createPropertiesData(properties);
              changeTokenHolder.setValue(newChangeToken);
              fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
              id = idHolder.getValue(); // note that id is path and has changed!
              res = fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false, false, null);
              assertNotNull(res);
              props = res.getProperties().getProperties();
              pd = props.get(PropertyIds.NAME);
              assertNotNull(pd);
              assertEquals(newName, pd.getFirstValue());
  
              // test rename with a conflicting name
              createDocumentWithCustomType(MY_CUSTOM_NAME, fRootFolderId, false);
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, MY_CUSTOM_NAME));
              newProps = fFactory.createPropertiesData(properties);
              // now rename to old name
              try {
                  fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
                  fail("Update with a conflicting name should fail.");
              } catch (Exception e) {
                  assertTrue(e instanceof CmisNameConstraintViolationException);
              }
  
              // test an invalid name
              properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, "Invalid/Name"));
              newProps = fFactory.createPropertiesData(properties);
              try {
                  fObjSvc.updateProperties(fRepositoryId, idHolder, changeTokenHolder, newProps, null);
                  fail("Update with an invalid name should fail.");
              } catch (Exception e) {
                  assertTrue(e instanceof CmisInvalidArgumentException);
              }
  
          } catch (Exception e) {
              fail("getObject() failed with exception: " + e);
          }
          log.info("... testUpdateProperties() finished.");
      }
  
      @Test
      public void testAllowableActions() {
          log.info("starting testAllowableActions() ...");
          final boolean withContent = false;
          String id = createDocument(fRootFolderId, withContent);
  
          // get allowable actions via getObject
          ObjectData res = fObjSvc.getObject(fRepositoryId, id, "*", true, IncludeRelationships.NONE, null, false, false,
                  null);
          assertNotNull(res.getAllowableActions());
          Set<Action> actions = res.getAllowableActions().getAllowableActions();
          assertNotNull(actions);
          verifyAllowableActionsDocument(actions, false, withContent);
  
          // get allowable actions via getAllowableActions
          AllowableActions allowableActions = fObjSvc.getAllowableActions(fRepositoryId, id, null);
          assertNotNull(allowableActions);
          actions = allowableActions.getAllowableActions();
          assertNotNull(actions);
          verifyAllowableActionsDocument(actions, false, withContent);
  
          // cleanup
          fObjSvc.deleteObject(fRepositoryId, id, true, null);
          log.info("... testAllowableActions() finished.");
      }
  
      @SuppressWarnings("unchecked")
      @Test
      public void testDefaultPropertiesDocument() {
          log.info("starting testDefaultPropertiesDocument() ...");
          String id = createDocument("DefPropDoc", fRootFolderId, TEST_DOC_TYPE_WITH_DEFAULTS_ID, false);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
          ObjectData res = getDocumentObjectData(id);
          Map<String, PropertyData<?>> props = res.getProperties().getProperties();
          PropertyData<?> pd = props.get(TEST_DOCUMENT_MY_INT_PROP_ID);
          assertNotNull(pd);
          Object bi = pd.getFirstValue();
          assertNotNull(bi);
          assertEquals(BigInteger.valueOf(100), bi);
  
          pd = props.get(TEST_DOCUMENT_MY_MULTI_STRING_PROP_ID);
          assertNotNull(pd);
          List<String> valueList = (List<String>) pd.getValues();
          assertNotNull(valueList);
          assertTrue(valueList.contains("Apache"));
          assertTrue(valueList.contains("CMIS"));
  
          pd = props.get(TEST_DOCUMENT_MY_INT_PROP_ID_MANDATORY_DEFAULT);
          assertNotNull(pd);
          bi = pd.getFirstValue();
          assertNotNull(bi);
          assertEquals(BigInteger.valueOf(100), bi);
  
          log.info("... testDefaultPropertiesDocument() finished.");
      }
  
      @SuppressWarnings("unchecked")
      @Test
      public void testDefaultPropertiesFolder() {
          log.info("starting testDefaultPropertiesFolder() ...");
          String id = createFolder("DefPropFolder", fRootFolderId, TEST_FOLDER_TYPE_WITH_DEFAULTS_ID);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
          ObjectData res = getDocumentObjectData(id);
          Map<String, PropertyData<?>> props = res.getProperties().getProperties();
          PropertyData<?> pd = props.get(TEST_FOLDER_MY_INT_PROP_ID);
          assertNotNull(pd);
          Object bi = pd.getFirstValue();
          assertNotNull(bi);
          assertEquals(BigInteger.valueOf(100), bi);
  
          pd = props.get(TEST_FOLDER_MY_MULTI_STRING_PROP_ID);
          assertNotNull(pd);
          List<String> valueList = (List<String>) pd.getValues();
          assertNotNull(valueList);
          assertTrue(valueList.contains("Apache"));
          assertTrue(valueList.contains("CMIS"));
  
          pd = props.get(TEST_FOLDER_MY_INT_PROP_ID_MANDATORY_DEFAULT);
          assertNotNull(pd);
          bi = pd.getFirstValue();
          assertNotNull(bi);
          assertEquals(BigInteger.valueOf(100), bi);
  
          log.info("... testDefaultPropertiesFolder() finished.");
      }
  
      @Test
      public void testGetObjectNoObjectIdInFilter() {
          log.info("starting testGetObjectNoObjectIdInFilter() ...");
          log.info("  creating object");
          String id = createDocument(fRootFolderId, false);
          if (id != null) {
              log.info("  createDocument succeeded with created id: " + id);
          }
  
          log.info("  getting object");
          String filter = PropertyIds.NAME + "," + PropertyIds.CREATION_DATE + "," + PropertyIds.LAST_MODIFICATION_DATE;
          ObjectData res = fObjSvc.getObject(fRepositoryId, id, filter, false, IncludeRelationships.NONE, null, false,
                  false, null);
  
          String returnedId = res.getId();
          assertEquals(id, returnedId);
          log.info("... testGetObjectNoObjectIdInFilter() finished.");
      }
  
      @Test
      public void testSpecialChars() {
  
          log.info("starting testGetObjectByPath() with specal chars...");
          log.info("  creating object");
  
          createDocument("H������nschen", fRootFolderId, false);
          log.info("  getting object by path with special chars");
          try {
              ObjectData res = fObjSvc.getObjectByPath(fRepositoryId, "/H������nschen", "*", false,
                      IncludeRelationships.NONE, null, false, false, null);
              assertNotNull(res);
              assertNotNull(res.getId());
          } catch (Exception e) {
              fail("getObject() failed with exception: " + e);
          }
      }
  
      @Test
      public void testNoContentAllowed() {
          log.info("starting testNoContentAllowed() ...");
          String id = createDocument("NoContentAllowedDoc1", fRootFolderId, TEST_CUSTOM_NO_CONTENT_TYPE_ID, false);
          assertNotNull(id);
  
          try {
              id = createDocumentNoCatch("NoContentAllowedDoc2", fRootFolderId, TEST_CUSTOM_NO_CONTENT_TYPE_ID,
                      VersioningState.NONE, true);
              fail("Creating  document with content and type allows no content should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisConstraintException);
              log.info("Creating  document with content for no-content type failed as expected.");
          }
          log.info("... testNoContentAllowed finished.");
      }
  
      @Test
      public void testMustHaveContent() {
          log.info("starting testMustHaveContent() ...");
          String id = createDocument("MustHaveContentAllowedDoc1", fRootFolderId, TEST_CUSTOM_MUST_CONTENT_TYPE_ID, true);
          assertNotNull(id);
  
          try {
              id = createDocumentNoCatch("MustHaveContentAllowedDoc2", fRootFolderId, TEST_CUSTOM_MUST_CONTENT_TYPE_ID,
                      VersioningState.NONE, false);
              fail("Creating document without content and type requires content should fail.");
          } catch (Exception e) {
              assertTrue(e instanceof CmisConstraintException);
              log.info("Creating document with content for must-have-content type failed as expected.");
          }
          log.info("... testMustHaveContent finished.");
      }
  
      @Test
      public void testMaxContentSize() {
          log.info("starting testMaxContentSize() ...");
          try {
              createContent(MAX_SIZE + 1, MAX_SIZE, null);
              fail("createContent with exceeded content size should fail.");
          } catch (CmisInvalidArgumentException e) {
              log.debug("createDocument with exceeded failed as excpected.");
          } catch (Exception e1) {
              log.debug("createDocument with exceeded failed with wrong exception (expected CmisInvalidArgumentException, got "
                      + e1.getClass().getName() + ").");
          }
  
          try {
              ContentStream contentStream = createContent(MAX_SIZE + 1, MAX_SIZE, null);
              Properties props = createDocumentProperties("TestMaxContentSize", DOCUMENT_TYPE_ID);
              fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, contentStream, VersioningState.NONE, null,
                      null, null, null);
              fail("createDocument with exceeded content size should fail.");
          } catch (CmisInvalidArgumentException e) {
              log.debug("createDocument with exceeded failed as expected.");
          } catch (Exception e1) {
              log.debug("createDocument with exceeded failed with wrong exception (expected CmisInvalidArgumentException, got "
                      + e1.getClass().getName() + ").");
          }
      }
  
      @Test
      public void testRenditionImage() {
          // upload an image as JPEG picture
          log.info("starting testRendition() ...");
  
          try {
              InputStream imageStream = this.getClass().getResourceAsStream("/image.jpg");
              assertNotNull("Test setup failure no 'image.jpg' in test resources, getResourceAsStream failed",
                      imageStream);
              String id = createDocumentFromStream("TestJpegImage", fRootFolderId, DOCUMENT_TYPE_ID, imageStream, JPEG);
  
              assertNotNull(id);
              String renditionFilter = "*";
              List<RenditionData> renditions = fObjSvc
                      .getRenditions(fRepositoryId, id, renditionFilter, null, null, null);
              assertNotNull(renditions);
              assertEquals(1, renditions.size());
              RenditionData rd = renditions.get(0);
              assertEquals(JPEG, rd.getMimeType());
              assertEquals("cmis:thumbnail", rd.getKind());
              assertEquals(id, rd.getRenditionDocumentId());
              assertNotNull(rd.getBigHeight());
              assertNotNull(rd.getBigWidth());
              assertEquals(RenditionUtil.THUMBNAIL_SIZE, rd.getBigHeight().longValue());
              assertEquals(RenditionUtil.THUMBNAIL_SIZE, rd.getBigWidth().longValue());
              assertNotNull(rd.getStreamId());
              ContentStream renditionContent = fObjSvc.getContentStream(fRepositoryId, id, rd.getStreamId(), null, null,
                      null);
              assertEquals(rd.getMimeType(), renditionContent.getMimeType());
              readThumbnailStream(renditionContent.getStream());
          } catch (Exception e) {
              log.error("testRendition failed with exception ", e);
              fail("testRendition failed with exceetion " + e);
          }
          log.info("... testRendition finished.");
      }
  
      @Test
      public void testRenditionIcon() {
          // fake an office document
          log.info("starting testRendition() ...");
  
          try {
              ContentStream content = createContent(4, 0,
                      "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
              Properties props = createDocumentProperties("TestJOffice", DOCUMENT_TYPE_ID);
              String id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, content, VersioningState.NONE,
                      null, null, null, null);
  
              assertNotNull(id);
              String renditionFilter = "*";
              List<RenditionData> renditions = fObjSvc
                      .getRenditions(fRepositoryId, id, renditionFilter, null, null, null);
              assertNotNull(renditions);
              assertEquals(1, renditions.size());
              RenditionData rd = renditions.get(0);
              assertEquals(PNG, rd.getMimeType());
              assertEquals("cmis:thumbnail", rd.getKind());
              assertEquals(id, rd.getRenditionDocumentId());
              assertNotNull(rd.getBigHeight());
              assertNotNull(rd.getBigWidth());
              assertEquals(RenditionUtil.ICON_SIZE, rd.getBigHeight().longValue());
              assertEquals(RenditionUtil.ICON_SIZE, rd.getBigWidth().longValue());
              assertNotNull(rd.getStreamId());
              ContentStream renditionContent = fObjSvc.getContentStream(fRepositoryId, id, rd.getStreamId(), null, null,
                      null);
              assertEquals(rd.getMimeType(), renditionContent.getMimeType());
              readThumbnailStream(renditionContent.getStream());
          } catch (Exception e) {
              log.error("testRendition failed with exception ", e);
              fail("testRendition failed with exceetion " + e);
          }
          log.info("... testRendition finished.");
      }
  
      @Test
      public void testFolderRendition() {
          // upload an image as JPEG picture
          log.info("starting testFolderRendition() ...");
  
          try {
              InputStream imageStream = this.getClass().getResourceAsStream("/image.jpg");
              assertNotNull("Test setup failure no 'image.jpg' in test resources, getResourceAsStream failed",
                      imageStream);
              String id = createFolder();
  
              assertNotNull(id);
              String renditionFilter = "*";
              List<RenditionData> renditions = fObjSvc
                      .getRenditions(fRepositoryId, id, renditionFilter, null, null, null);
              assertNotNull(renditions);
              assertEquals(1, renditions.size());
              RenditionData rd = renditions.get(0);
              assertEquals(PNG, rd.getMimeType());
              assertEquals("cmis:thumbnail", rd.getKind());
              assertEquals(id, rd.getRenditionDocumentId());
              assertNotNull(rd.getBigHeight());
              assertNotNull(rd.getBigWidth());
              assertEquals(RenditionUtil.ICON_SIZE, rd.getBigHeight().longValue());
              assertEquals(RenditionUtil.ICON_SIZE, rd.getBigWidth().longValue());
              assertNotNull(rd.getStreamId());
              ContentStream renditionContent = fObjSvc.getContentStream(fRepositoryId, id, rd.getStreamId(), null, null,
                      null);
              assertEquals(rd.getMimeType(), renditionContent.getMimeType());
              readThumbnailStream(renditionContent.getStream());
          } catch (Exception e) {
              log.error("testFolderRendition failed with exception ", e);
              fail("testFolderRendition failed with exceetion " + e);
          }
          log.info("... testFolderRendition finished.");
  
      }
  
      @Test
      public void testAppendContent() {
          log.info("starting testAppendContent() ...");
          String id = createDocument(fRootFolderId, true);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
  
          // append content again in a second call
          Holder<String> idHolder = new Holder<String>(id);
  
          ContentStream contentStream = createContent();
          fObjSvc.appendContentStream(fRepositoryId, idHolder, null, contentStream, false, null);
          ContentStream sd = fObjSvc.getContentStream(fRepositoryId, id, null, null, null, null);
          verifyContentResult(sd, 64);
  
          // cleanup
          fObjSvc.deleteObject(fRepositoryId, id, true, null);
  
          log.info("... testAppendContent() finished.");
      }
  
      @Test
      public void testGetPartialContent() throws IOException, UnsupportedEncodingException {
          log.info("starting testGetPartialContent() ...");
          final String STREAM_NAME = "data.txt";
          final String MIME_TYPE = "text/plain";
          // append content again in a second call
  
          ContentStreamDataImpl content = new ContentStreamDataImpl(-1);
          content.setFileName(STREAM_NAME);
          content.setMimeType(MIME_TYPE);
  
          String prefix = "################ ~~~~This is a completeley irrelevant prefix header. ~~~~ ################";
          String main = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.";
          String postfix = "################ ~~~~POSTFIX Please ignore POSTFIX POSTFIX POSTFIX ~~~~ ################";
  
          ByteArrayOutputStream ba = new ByteArrayOutputStream();
          PrintStream printStream = new PrintStream(ba, false, ENCODING_UTF8);
          printStream.println(prefix);
          printStream.println(main);
          printStream.println(postfix);
  
          content.setContent(new ByteArrayInputStream(ba.toByteArray()));
  
          // Create document with content
          Properties props = createDocumentProperties("PartialContentTest", BaseTypeId.CMIS_DOCUMENT.value());
          String id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, content, VersioningState.NONE, null,
                  null, null, null);
          if (id != null) {
              log.info("createDocument succeeded with created id: " + id);
          }
  
          int offset = prefix.length() + System.getProperty("line.separator").length(); // for
                                                                                        // \n
          int length = main.length();
          ContentStream readContent = fObjSvc.getContentStream(fRepositoryId, id, null, BigInteger.valueOf(offset),
                  BigInteger.valueOf(length), null);
  
          assertEquals(MIME_TYPE, readContent.getMimeType());
          assertEquals(STREAM_NAME, readContent.getFileName());
          assertEquals(length, readContent.getBigLength().longValue());
  
          byte[] bytesRead = new byte[10240];
          InputStream is = readContent.getStream();
          int lengthRead = is.read(bytesRead);
          String result = new String(bytesRead, 0, lengthRead, ENCODING_UTF8);
          assertEquals(length, lengthRead);
          assertEquals(main, result);
  
          // cleanup
          fObjSvc.deleteObject(fRepositoryId, id, true, null);
  
          log.info("... testGetPartialContent() finished.");
      }
  
      @Test
      public void testBulkUpdateProperties() {
          log.info("starting testBulkUpdateProperties() ...");
          String MY_CUSTOM_NAME_2 = MY_CUSTOM_NAME + "_2";
          String id1 = createDocumentWithCustomType(MY_CUSTOM_NAME, fRootFolderId, false);
          String id2 = createDocumentWithCustomType(MY_CUSTOM_NAME_2, fRootFolderId, false);
          String changeToken1, changeToken2;
          try {
              ObjectData res = fObjSvc.getObject(fRepositoryId, id1, "*", false, IncludeRelationships.NONE, null, false,
                      false, null);
              assertNotNull(res);
              Map<String, PropertyData<?>> props = res.getProperties().getProperties();
              changeToken1 = (String) props.get(PropertyIds.CHANGE_TOKEN).getFirstValue();
  
              res = fObjSvc
                      .getObject(fRepositoryId, id2, "*", false, IncludeRelationships.NONE, null, false, false, null);
              assertNotNull(res);
              props = res.getProperties().getProperties();
              changeToken2 = (String) props.get(PropertyIds.CHANGE_TOKEN).getFirstValue();
  
              // check returned properties
              for (PropertyData<?> pd : props.values()) {
                  log.info("  return property id: " + pd.getId() + ", value: " + pd.getValues());
              }
  
              // update properties:
              log.info("updating property");
              List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
              properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID, NEW_STRING_PROP_VAL));
              properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, NEW_INT_PROP_VAL));
              Properties newProps = fFactory.createPropertiesData(properties);
              // wait some time to get a newer change token
  
              List<BulkUpdateObjectIdAndChangeToken> objs = new ArrayList<BulkUpdateObjectIdAndChangeToken>();
              objs.add(new BulkUpdateObjectIdAndChangeTokenImpl(id1, changeToken1));
              objs.add(new BulkUpdateObjectIdAndChangeTokenImpl(id2, changeToken2));
  
              List<BulkUpdateObjectIdAndChangeToken> newObjs;
              newObjs = fObjSvc.bulkUpdateProperties(fRepositoryId, objs, newProps, null, null, null);
              assertNotNull(newObjs);
              assertEquals(objs.size(), newObjs.size());
              for (int i = 0; i < newObjs.size(); i++) {
                  assertEquals(objs.get(i).getId(), newObjs.get(i).getId());
                  assertTrue(!objs.get(i).getChangeToken().equals(newObjs.get(i).getChangeToken()));
              }
              // check that new properties are set
              verifyUpdatedProperties(id1, MY_CUSTOM_NAME);
              verifyUpdatedProperties(id2, MY_CUSTOM_NAME_2);
  
          } catch (Exception e) {
              fail("testBulkUpdateProperties() failed with exception: " + e);
          }
          log.info("... testBulkUpdateProperties() finished.");
      }
  
      // CMIS 1.1: test item typpe
      @Test
      public void testItemCreation() {
  
          log.info("starting testItemCreation() ...");
          String propVal = "abc123";
          String name = "CoolItem";
          String id = createItem(name, fRootFolderId, propVal);
          if (id != null) {
              log.info("testItemCreation succeeded with created id: " + id);
          }
          log.info("... testCreateObject() finished.");
  
          // read document again and check properties
          ObjectData res = getDocumentObjectData(id);
          String returnedId = res.getId();
          Map<String, PropertyData<?>> props = res.getProperties().getProperties();
          testReturnedProperties(returnedId, name, TEST_ITEM_TYPE_ID, props);
          PropertyData<?> pd = props.get(ITEM_STRING_PROP);
          assertEquals(propVal, pd.getFirstValue());
          assertEquals(12, props.size()); // should not contain all the document
                                          // properties
          log.info("... finished testItemCreation()");
      }
  
      @Test
      public void testSecondaryTypes() {
          log.info("starting testItemCreation() ...");
          final String strPropVal = "Secondary";
          final BigInteger intPropVal = BigInteger.valueOf(100);
          final String primaryPropVal = "Sample Doc String Property";
  
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(PropertyIds.NAME, "ObjectWithSecondaryType"));
          properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_DOCUMENT_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal));
          properties.add(fFactory.createPropertyIdData(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, TEST_SECONDARY_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(SECONDARY_STRING_PROP, strPropVal));
          properties.add(fFactory.createPropertyIntegerData(SECONDARY_INTEGER_PROP, intPropVal));
          Properties props = fFactory.createPropertiesData(properties);
  
          String id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, null, VersioningState.NONE, null, null,
                  null, null);
          assertNotNull(id);
  
          Properties res = fObjSvc.getProperties(fRepositoryId, id, "*", null);
          assertNotNull(res.getProperties());
          Map<String, PropertyData<?>> returnedProps = res.getProperties();
          assertNotNull(returnedProps);
          String returnedValueStr = (String) returnedProps.get(SECONDARY_STRING_PROP).getFirstValue();
          BigInteger returnedValueInt = (BigInteger) returnedProps.get(SECONDARY_INTEGER_PROP).getFirstValue();
          assertEquals(strPropVal, returnedValueStr);
          assertEquals(intPropVal, returnedValueInt);
          String returnedPrimaryPropVal = (String) returnedProps.get(TEST_DOCUMENT_STRING_PROP_ID).getFirstValue();
          assertEquals(primaryPropVal, returnedPrimaryPropVal);
  
          // test updating properties
          final String strPropVal2 = "Secondary updated";
          final String primaryPropVal2 = "Sample Doc String Property updated";
          properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(SECONDARY_STRING_PROP, strPropVal2));
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal2));
          props = fFactory.createPropertiesData(properties);
          fObjSvc.updateProperties(fRepositoryId, new Holder<String>(id), new Holder<String>(), props, null);
  
          res = fObjSvc.getProperties(fRepositoryId, id, "*", null);
          assertNotNull(res.getProperties());
          returnedProps = res.getProperties();
          assertNotNull(returnedProps);
          returnedValueStr = (String) returnedProps.get(SECONDARY_STRING_PROP).getFirstValue();
          returnedValueInt = (BigInteger) returnedProps.get(SECONDARY_INTEGER_PROP).getFirstValue();
          assertEquals(strPropVal2, returnedValueStr);
          assertEquals(intPropVal, returnedValueInt);
          returnedPrimaryPropVal = (String) returnedProps.get(TEST_DOCUMENT_STRING_PROP_ID).getFirstValue();
          assertEquals(primaryPropVal2, returnedPrimaryPropVal);
  
          log.info("... finished testSecondaryTypes()");
      }
  
      @Test
      public void testSecondaryTypePropertiesNotSet() {
          log.info("starting testSecondaryTypePropertiesNotSet() ...");
  
          final String primaryPropVal = "Sample Doc String Property";
  
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(PropertyIds.NAME, "ObjectWithSecondaryType"));
          properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_DOCUMENT_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal));
          properties.add(fFactory.createPropertyIdData(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, TEST_SECONDARY_TYPE_ID));
          Properties props = fFactory.createPropertiesData(properties);
  
          String id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, null, VersioningState.NONE, null, null,
                  null, null);
          assertNotNull(id);
  
          Properties res = fObjSvc.getProperties(fRepositoryId, id, "*", null);
          assertNotNull(res.getProperties());
          Map<String, PropertyData<?>> returnedProps = res.getProperties();
          assertNotNull(returnedProps);
          boolean hasProp = returnedProps.containsKey(SECONDARY_STRING_PROP);
          assertTrue(hasProp);
          hasProp = returnedProps.containsKey(SECONDARY_INTEGER_PROP);
          assertTrue(hasProp);
          PropertyData<?> returnedValue = returnedProps.get(SECONDARY_STRING_PROP);
          assertNotNull(returnedValue);
          assertTrue(returnedValue.getValues().isEmpty());
          returnedValue = returnedProps.get(SECONDARY_INTEGER_PROP);
          assertNotNull(returnedValue);
          assertTrue(returnedValue.getValues().isEmpty());
  
          log.info("... finished testSecondaryTypePropertiesNotSet()");
      }
  
      @Test
      public void testUpdatePropertiesWithTypeCreation() {
          final String strPropVal = "Secondary";
          final BigInteger intPropVal = BigInteger.valueOf(100);
          final String primaryPropVal = "Sample Doc String Property";
          final String primaryPropVal2 = "Sample Doc String Property updated";
  
          log.info("starting testUpdatePropertiesWithTypeCreation() ...");
  
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(PropertyIds.NAME, "SimpleDocument"));
          properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_DOCUMENT_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal));
          Properties props = fFactory.createPropertiesData(properties);
  
          String id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, null, VersioningState.NONE, null, null,
                  null, null);
          assertNotNull(id);
  
          properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal2));
          properties.add(fFactory.createPropertyIdData(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, TEST_SECONDARY_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(SECONDARY_STRING_PROP, strPropVal));
          properties.add(fFactory.createPropertyIntegerData(SECONDARY_INTEGER_PROP, intPropVal));
          props = fFactory.createPropertiesData(properties);
          fObjSvc.updateProperties(fRepositoryId, new Holder<String>(id), new Holder<String>(), props, null);
  
          Properties res = fObjSvc.getProperties(fRepositoryId, id, "*", null);
          assertNotNull(res.getProperties());
          Map<String, PropertyData<?>> returnedProps = res.getProperties();
          assertNotNull(returnedProps);
          assertEquals(1, returnedProps.get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues().size());
          String secIds = (String) returnedProps.get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getFirstValue();
          assertEquals(TEST_SECONDARY_TYPE_ID, secIds);
          String returnedValueStr = (String) returnedProps.get(SECONDARY_STRING_PROP).getFirstValue();
          BigInteger returnedValueInt = (BigInteger) returnedProps.get(SECONDARY_INTEGER_PROP).getFirstValue();
          assertEquals(strPropVal, returnedValueStr);
          assertEquals(intPropVal, returnedValueInt);
          String returnedPrimaryPropVal = (String) returnedProps.get(TEST_DOCUMENT_STRING_PROP_ID).getFirstValue();
          assertEquals(primaryPropVal2, returnedPrimaryPropVal);
  
          log.info("... finished testUpdatePropertiesWithTypeCreation()");
      }
  
      @Test
      public void testDeleteSecondaryType() {
          final String primaryPropVal = "Sample Doc String Property";
          final String primaryPropVal2 = "Sample Doc String Property updated";
          final String strPropVal = "Secondary";
          final BigInteger intPropVal = BigInteger.valueOf(100);
  
          log.info("starting testDeleteSecondaryType() ...");
  
          // create a document with a secondary type
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(PropertyIds.NAME, "ObjectWithSecondaryType"));
          properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_DOCUMENT_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal));
          properties.add(fFactory.createPropertyIdData(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, TEST_SECONDARY_TYPE_ID));
          properties.add(fFactory.createPropertyStringData(SECONDARY_STRING_PROP, strPropVal));
          properties.add(fFactory.createPropertyIntegerData(SECONDARY_INTEGER_PROP, intPropVal));
          Properties props = fFactory.createPropertiesData(properties);
  
          String id = fObjSvc.createDocument(fRepositoryId, props, fRootFolderId, null, VersioningState.NONE, null, null,
                  null, null);
          assertNotNull(id);
  
          // delete the secondary type
          properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_STRING_PROP_ID, primaryPropVal2));
          properties.add(fFactory.createPropertyIdData(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, (String) null)); // set
                                                                                                               // list
                                                                                                               // to
                                                                                                               // empty
          props = fFactory.createPropertiesData(properties);
          fObjSvc.updateProperties(fRepositoryId, new Holder<String>(id), new Holder<String>(), props, null);
  
          // test that properties are gone
          Properties res = fObjSvc.getProperties(fRepositoryId, id, "*", null);
          assertNotNull(res.getProperties());
          Map<String, PropertyData<?>> returnedProps = res.getProperties();
          assertNotNull(returnedProps);
          assertEquals(0, returnedProps.get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS).getValues().size());
          PropertyData<?> pd = returnedProps.get(SECONDARY_STRING_PROP);
          assertNull(pd); // property must not exist any longer
          pd = returnedProps.get(SECONDARY_INTEGER_PROP);
          assertNull(pd); // property must not exist any longer
          String returnedPrimaryPropVal = (String) returnedProps.get(TEST_DOCUMENT_STRING_PROP_ID).getFirstValue();
          assertEquals(primaryPropVal2, returnedPrimaryPropVal); // other
                                                                 // properties
                                                                 // should be
                                                                 // updated
          // test that system properties are there
          pd = returnedProps.get(PropertyIds.NAME);
          assertNotNull(pd);
          pd = returnedProps.get(PropertyIds.OBJECT_ID);
          assertNotNull(pd);
          pd = returnedProps.get(PropertyIds.OBJECT_TYPE_ID);
          assertNotNull(pd);
  
          log.info("... finished testDeleteSecondaryType()");
      }
  
      // TODO: test constraints on secondary types
  
      private void verifyUpdatedProperties(String id, String name) {
  
          ObjectData res = fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE, null, false,
                  false, null);
          assertNotNull(res);
          Map<String, PropertyData<?>> props = res.getProperties().getProperties();
          for (PropertyData<?> pd2 : props.values()) {
              log.info("  return property id: " + pd2.getId() + ", value: " + pd2.getValues());
          }
  
          PropertyData<?> pd;
          pd = props.get(PropertyIds.NAME);
          assertNotNull(pd);
          assertEquals(name, pd.getFirstValue());
          pd = props.get(PropertyIds.OBJECT_TYPE_ID);
          assertEquals(TEST_CUSTOM_DOCUMENT_TYPE_ID, pd.getFirstValue());
          pd = props.get(TEST_DOCUMENT_MY_STRING_PROP_ID);
          assertEquals(NEW_STRING_PROP_VAL, pd.getFirstValue());
          pd = props.get(TEST_DOCUMENT_MY_INT_PROP_ID);
          assertEquals(NEW_INT_PROP_VAL, pd.getFirstValue());
      }
  
      protected String createDocumentFromStream(String name, String folderId, String typeId, InputStream is,
              String contentType) throws IOException {
  
          Properties props = createDocumentProperties(name, typeId);
  
          ContentStreamDataImpl content = new ContentStreamDataImpl(0);
          content.setFileName(name);
          content.setMimeType(contentType);
  
          ByteArrayOutputStream ba = new ByteArrayOutputStream();
  
          IOUtils.copy(is, ba, 64 * 1024);
  
          content.setContent(new ByteArrayInputStream(ba.toByteArray()));
  
          String id = fObjSvc.createDocument(fRepositoryId, props, folderId, content, VersioningState.NONE, null, null,
                  null, null);
          return id;
      }
  
      private void readThumbnailStream(InputStream stream) {
  
          byte[] buffer = new byte[65536];
          int noBytesRead = 0;
          int count = 0;
          try {
              while ((noBytesRead = stream.read(buffer)) >= 0) {
                  count += noBytesRead;
              }
          } catch (IOException e) {
              e.printStackTrace();
              fail("Reading rendition stream failed with exception " + e);
          }
          assertTrue(count > 0);
      }
  
      private static void verifyAllowableActionsDocument(Set<Action> actions, boolean isVersioned, boolean hasContent) {
          assertTrue(actions.contains(Action.CAN_DELETE_OBJECT));
          assertTrue(actions.contains(Action.CAN_UPDATE_PROPERTIES));
          assertTrue(actions.contains(Action.CAN_GET_PROPERTIES));
          assertFalse(actions.contains(Action.CAN_GET_OBJECT_RELATIONSHIPS));
          assertTrue(actions.contains(Action.CAN_GET_OBJECT_PARENTS));
  
          assertFalse(actions.contains(Action.CAN_GET_FOLDER_PARENT));
          assertFalse(actions.contains(Action.CAN_GET_FOLDER_TREE));
          assertFalse(actions.contains(Action.CAN_GET_DESCENDANTS));
          assertTrue(actions.contains(Action.CAN_MOVE_OBJECT));
          if (hasContent) {
              assertTrue(actions.contains(Action.CAN_DELETE_CONTENT_STREAM));
              assertTrue(actions.contains(Action.CAN_GET_CONTENT_STREAM));
              assertTrue(actions.contains(Action.CAN_GET_RENDITIONS));
          } else {
              assertFalse(actions.contains(Action.CAN_DELETE_CONTENT_STREAM));
              assertFalse(actions.contains(Action.CAN_GET_CONTENT_STREAM));
              assertFalse(actions.contains(Action.CAN_GET_RENDITIONS));
          }
          assertTrue(actions.contains(Action.CAN_ADD_OBJECT_TO_FOLDER));
          assertTrue(actions.contains(Action.CAN_REMOVE_OBJECT_FROM_FOLDER));
  
          if (isVersioned) {
              assertTrue(actions.contains(Action.CAN_CANCEL_CHECK_OUT));
              assertTrue(actions.contains(Action.CAN_CHECK_IN));
              assertTrue(actions.contains(Action.CAN_CHECK_OUT));
              assertTrue(actions.contains(Action.CAN_GET_ALL_VERSIONS));
  
          } else {
              assertFalse(actions.contains(Action.CAN_CANCEL_CHECK_OUT));
              assertFalse(actions.contains(Action.CAN_CHECK_IN));
              assertFalse(actions.contains(Action.CAN_CHECK_OUT));
              assertFalse(actions.contains(Action.CAN_GET_ALL_VERSIONS));
          }
          assertTrue(actions.contains(Action.CAN_SET_CONTENT_STREAM));
          assertTrue(actions.contains(Action.CAN_APPLY_POLICY));
          assertTrue(actions.contains(Action.CAN_GET_APPLIED_POLICIES));
          assertFalse(actions.contains(Action.CAN_REMOVE_POLICY));
          assertFalse(actions.contains(Action.CAN_GET_CHILDREN));
          assertFalse(actions.contains(Action.CAN_CREATE_DOCUMENT));
          assertFalse(actions.contains(Action.CAN_CREATE_FOLDER));
          assertFalse(actions.contains(Action.CAN_CREATE_RELATIONSHIP));
          assertFalse(actions.contains(Action.CAN_DELETE_TREE));
          assertTrue(actions.contains(Action.CAN_GET_ACL));
          assertTrue(actions.contains(Action.CAN_APPLY_ACL));
      }
  
      private String retrieveDocument(String id) {
          ObjectData res = getDocumentObjectData(id);
          String returnedId = res.getId();
          testReturnedProperties(returnedId, DOCUMENT_ID, DOCUMENT_TYPE_ID, res.getProperties().getProperties());
          return returnedId;
      }
  
      private void moveObjectTest(boolean isFolder) {
          final String propertyFilter = PropertyIds.OBJECT_ID + "," + PropertyIds.NAME;
          String rootFolderId = createFolder();
          ObjectGenerator gen = new ObjectGenerator(fFactory, fNavSvc, fObjSvc, fRepSvc, fRepositoryId,
                  ObjectGenerator.ContentKind.LOREM_IPSUM_TEXT);
          // Set the type id for all created documents:
          gen.setDocumentTypeId(DocumentTypeCreationHelper.getCmisDocumentType().getId());
          // Set the type id for all created folders:
          gen.setNumberOfDocumentsToCreatePerFolder(1); // create one document in
          // each folder
          gen.createFolderHierachy(3, 2, rootFolderId);
          gen.setFolderTypeId(DocumentTypeCreationHelper.getCmisFolderType().getId());
          gen.dumpFolder(fRootFolderId, propertyFilter);
          Holder<String> holder = new Holder<String>();
          String sourceIdToMove = gen.getFolderId(rootFolderId, 2, 1);
          if (!isFolder) {
              sourceIdToMove = gen.getDocumentId(sourceIdToMove, 0);
          }
          holder.setValue(sourceIdToMove); // "/Folder_1/My Folder 0/My Folder 1");
          String sourceFolderId = getSourceFolder(sourceIdToMove);
          log.info("Id before moveObject: " + holder.getValue());
          fObjSvc.moveObject(fRepositoryId, holder, rootFolderId, sourceFolderId, null);
          log.info("Id after moveObject: " + holder.getValue());
          gen.dumpFolder(fRootFolderId, propertyFilter);
  
          List<ObjectParentData> result = fNavSvc.getObjectParents(fRepositoryId, holder.getValue(), null, Boolean.FALSE,
                  IncludeRelationships.NONE, null, Boolean.FALSE, null);
          // check that new parent is set correctly
          String newParentId = result.get(0).getObject().getId();
          assertEquals(rootFolderId, newParentId);
  
          if (isFolder) {
              log.info("testing moveFolder to a subfolder");
              ObjectInFolderList ch = fNavSvc.getChildren(fRepositoryId, holder.getValue(), propertyFilter, null, false,
                      IncludeRelationships.NONE, null, false, null, null, null);
              String subFolderId = ch.getObjects().get(0).getObject().getId();
  
              try {
                  fObjSvc.moveObject(fRepositoryId, holder, subFolderId, sourceFolderId, null);
                  fail("moveObject to a folder that is a descendant of the source must fail.");
              } catch (Exception e) {
                  assertTrue(e instanceof CmisNotSupportedException);
              }
          }
      }
  
      private String createFolder() {
          return createFolder(FOLDER_ID, fRootFolderId, FOLDER_TYPE_ID);
      }
  
      private String createDocument(String folderId, boolean withContent) {
          return createDocument(DOCUMENT_ID, folderId, withContent);
      }
  
      private String createDocument(String name, String folderId, boolean withContent) {
          return createDocument(name, folderId, DOCUMENT_TYPE_ID, withContent);
      }
  
      private String createItem(String name, String folderId, String itemPropVal) {
  
          // create the properties:
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyStringData(PropertyIds.NAME, name));
          properties.add(fFactory.createPropertyStringData(ITEM_STRING_PROP, itemPropVal));
          properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_ITEM_TYPE_ID));
          Properties props = fFactory.createPropertiesData(properties);
  
          return fObjSvc.createItem(fRepositoryId, props, folderId, null, null, null, null);
      }
  
      private Properties createDocumentPropertiesForDocumentFromSource(String name) {
          // We only provide a name but not a type id, as spec says to copy
          // missing attributes
          // from the existing one
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, name));
          Properties props = fFactory.createPropertiesData(properties);
          return props;
      }
  
      private void testReturnedProperties(String objectId, String objectName, String typeId,
              Map<String, PropertyData<?>> props) {
          super.testReturnedProperties(objectId, props);
  
          if (null != objectName) {
              PropertyData<?> pd = props.get(PropertyIds.NAME);
              assertNotNull(pd);
              assertEquals(objectName, pd.getFirstValue());
          }
          if (null != typeId) {
              PropertyData<?> pd = props.get(PropertyIds.OBJECT_TYPE_ID);
              assertEquals(typeId, pd.getFirstValue());
          }
      }
  
      private String createDocumentWithCustomType(String name, String folderId, boolean withContent) {
          ContentStream contentStream = null;
          VersioningState versioningState = VersioningState.NONE;
          List<String> policies = null;
          Acl addACEs = null;
          Acl removeACEs = null;
          ExtensionsData extension = null;
  
          // create the properties:
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, name));
          properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_CUSTOM_DOCUMENT_TYPE_ID));
          // Generate some property values for custom attributes
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID, "My pretty string"));
          properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, BigInteger.valueOf(4711)));
  
          Properties props = fFactory.createPropertiesData(properties);
  
          if (withContent) {
              contentStream = createContent();
          }
  
          // create the document
          String id = null;
          id = fObjSvc.createDocument(fRepositoryId, props, folderId, contentStream, versioningState, policies, addACEs,
                  removeACEs, extension);
          if (null == id) {
              throw new RuntimeException("createDocument failed.");
          }
          return id;
      }
  
      private String createDocumentInheritedProperties(String folderId, boolean withContent) {
          ContentStream contentStream = null;
          VersioningState versioningState = VersioningState.NONE;
          List<String> policies = null;
          Acl addACEs = null;
          Acl removeACEs = null;
          ExtensionsData extension = null;
  
          // create the properties:
          List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
          properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, MY_CUSTOM_NAME));
          properties.add(fFactory
                  .createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID));
          // Generate some property values for custom attributes
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_STRING_PROP_ID, "My pretty string"));
          properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, BigInteger.valueOf(4711)));
          properties.add(fFactory.createPropertyStringData(TEST_DOCUMENT_MY_SUB_STRING_PROP_ID, "another cool string"));
          properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_SUB_INT_PROP_ID, BigInteger.valueOf(4712)));
  
          Properties props = fFactory.createPropertiesData(properties);
  
          if (withContent) {
              contentStream = createContent();
          }
  
          // create the document
          String id = null;
          id = fObjSvc.createDocument(fRepositoryId, props, folderId, contentStream, versioningState, policies, addACEs,
                  removeACEs, extension);
          if (null == id) {
              throw new RuntimeException("createDocument failed.");
          }
          return id;
      }
  
      private String getSourceFolder(String objectId) {
          // return the first parent found in the result list of all parents
          List<ObjectParentData> parents = fNavSvc.getObjectParents(fRepositoryId, objectId, "*", false,
                  IncludeRelationships.NONE, null, true, null);
          return parents.get(0).getObject().getId();
      }
  
      // Helper class to create some type for testing the ObjectService
  
      public static class ObjectTestTypeSystemCreator implements TypeCreator {
  
          static final TypeDefinitionFactory typeFactory = DocumentTypeCreationHelper.getTypeDefinitionFactory();
  
          /**
           * create root types and a sample type for folder and document
           * 
           * @return typesMap map filled with created types
           */
          @Override
          public List<TypeDefinition> createTypesList() {
              List<TypeDefinition> typesList = new LinkedList<TypeDefinition>();
  
              try {
                  MutableTypeDefinition cmisDocumentType;
                  cmisDocumentType = typeFactory.createChildTypeDefinition(
                          DocumentTypeCreationHelper.getCmisDocumentType(), TEST_DOCUMENT_TYPE_ID);
                  cmisDocumentType.setDisplayName("My Document Type");
                  cmisDocumentType.setDescription("InMemory test type definition " + TEST_DOCUMENT_TYPE_ID);
  
                  MutableFolderTypeDefinition cmisFolderType;
                  cmisFolderType = typeFactory.createFolderTypeDefinition(CmisVersion.CMIS_1_1,
                          DocumentTypeCreationHelper.getCmisFolderType().getId());
                  cmisFolderType.setId(TEST_FOLDER_TYPE_ID);
                  cmisFolderType.setDisplayName("My Folder Type");
                  cmisFolderType.setDescription("InMemory test type definition " + TEST_FOLDER_TYPE_ID);
                  // create a simple string property type and
                  // attach the property definition to the type definition for
                  // document and folder type
                  Map<String, PropertyDefinition<?>> propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
                  PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringDefinition(
                          TEST_DOCUMENT_STRING_PROP_ID, "Sample Doc String Property", Updatability.READWRITE);
                  propertyDefinitions.put(prop.getId(), prop);
                  cmisDocumentType.addPropertyDefinition(prop);
  
                  propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
                  prop = PropertyCreationHelper.createStringDefinition(TEST_FOLDER_STRING_PROP_ID,
                          "Sample Folder String Property", Updatability.READWRITE);
                  propertyDefinitions.put(prop.getId(), prop);
                  cmisFolderType.addPropertyDefinition(prop);
  
                  DocumentTypeDefinition customDocType = createCustomTypeWithStringIntProperty();
                  TypeDefinition noContentType = createCustomTypeNoContent();
                  TypeDefinition mustHaveContentType = createCustomTypeMustHaveContent();
                  TypeDefinition relType = createRelationshipType();
                  TypeDefinition relTypeRestricted = createRelationshipTypeRestricted();
                  TypeDefinition verType = createVersionableType();
                  TypeDefinition polType = createPolicyType();
  
                  // add type to types collection
                  typesList.add(cmisDocumentType);
                  typesList.add(cmisFolderType);
                  typesList.add(customDocType);
                  typesList.add(noContentType);
                  typesList.add(mustHaveContentType);
                  typesList.add(createCustomInheritedType(customDocType));
                  typesList.add(createDocumentTypeWithDefault());
                  typesList.add(createFolderTypeWithDefault());
                  typesList.add(createItemType());
                  typesList.add(createSecondaryType());
                  typesList.add(relType);
                  typesList.add(relTypeRestricted);
                  typesList.add(verType);
                  typesList.add(polType);
                  return typesList;
              } catch (Exception e) {
                  throw new CmisRuntimeException("Failed to create types.", e);
              }
          }
  
          private static DocumentTypeDefinition createCustomTypeWithStringIntProperty() throws InstantiationException,
                  IllegalAccessException {
              MutableDocumentTypeDefinition cmisDocumentType;
              cmisDocumentType = (MutableDocumentTypeDefinition) typeFactory.createChildTypeDefinition(
                      DocumentTypeCreationHelper.getCmisDocumentType(), TEST_CUSTOM_DOCUMENT_TYPE_ID);
              cmisDocumentType.setDisplayName("My Custom Document Type");
              cmisDocumentType.setDescription("InMemory test type definition " + TEST_CUSTOM_DOCUMENT_TYPE_ID);
  
              PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringDefinition(
                      TEST_DOCUMENT_MY_STRING_PROP_ID, "My String Property", Updatability.READWRITE);
              prop.setIsRequired(false);
              prop.setMaxLength(BigInteger.valueOf(20)); // max len to 20
              cmisDocumentType.addPropertyDefinition(prop);
  
              PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
                      TEST_DOCUMENT_MY_INT_PROP_ID, "My Integer Property", Updatability.READWRITE);
              prop2.setIsRequired(true);
              prop2.setMinValue(BigInteger.valueOf(-10000));
              prop2.setMaxValue(BigInteger.valueOf(10000));
              cmisDocumentType.addPropertyDefinition(prop2);
              return cmisDocumentType;
          }
  
          private static TypeDefinition createCustomInheritedType(DocumentTypeDefinition baseType)
                  throws InstantiationException, IllegalAccessException {
              MutableTypeDefinition cmisDocumentType;
              cmisDocumentType = typeFactory.createChildTypeDefinition(baseType, TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID);
              cmisDocumentType.setDisplayName("My Custom Document Type");
              cmisDocumentType.setDescription("InMemory test type definition " + TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID);
  
              PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringDefinition(
                      TEST_DOCUMENT_MY_SUB_STRING_PROP_ID, "Subtype String Property", Updatability.READWRITE);
              prop.setIsRequired(false);
              cmisDocumentType.addPropertyDefinition(prop);
  
              PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
                      TEST_DOCUMENT_MY_SUB_INT_PROP_ID, "Subtype", Updatability.READWRITE);
              prop2.setIsRequired(true);
              cmisDocumentType.addPropertyDefinition(prop2);
              return cmisDocumentType;
          }
  
          @SuppressWarnings("serial")
          private static TypeDefinition createDocumentTypeWithDefault() throws InstantiationException,
                  IllegalAccessException {
              MutableTypeDefinition cmisDocumentType;
              cmisDocumentType = typeFactory.createChildTypeDefinition(DocumentTypeCreationHelper.getCmisDocumentType(),
                      TEST_DOC_TYPE_WITH_DEFAULTS_ID);
              cmisDocumentType.setDisplayName("Document Type With default values");
              cmisDocumentType.setDescription("InMemory test type definition " + TEST_DOC_TYPE_WITH_DEFAULTS_ID);
  
              PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringMultiDefinition(
                      TEST_DOCUMENT_MY_MULTI_STRING_PROP_ID, "Test Multi String Property", Updatability.READWRITE);
              prop.setIsRequired(false);
              List<String> defValS = new ArrayList<String>() {
                  {
                      add("Apache");
                      add("CMIS");
                  }
              };
              prop.setDefaultValue(defValS);
              cmisDocumentType.addPropertyDefinition(prop);
  
              PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
                      TEST_DOCUMENT_MY_INT_PROP_ID, "Test Integer Property", Updatability.READWRITE);
              prop2.setIsRequired(false);
              List<BigInteger> defVal = new ArrayList<BigInteger>() {
                  {
                      add(BigInteger.valueOf(100));
                  }
              };
              prop2.setDefaultValue(defVal);
              cmisDocumentType.addPropertyDefinition(prop2);
  
              PropertyIntegerDefinitionImpl prop3 = PropertyCreationHelper.createIntegerDefinition(
                      TEST_DOCUMENT_MY_INT_PROP_ID_MANDATORY_DEFAULT, "Test Integer Property Mandatory default",
                      Updatability.READWRITE);
              prop3.setIsRequired(true);
              List<BigInteger> defVal2 = new ArrayList<BigInteger>() {
                  {
                      add(BigInteger.valueOf(100));
                  }
              };
              prop3.setDefaultValue(defVal2);
              cmisDocumentType.addPropertyDefinition(prop3);
  
              return cmisDocumentType;
          }
  
          private static TypeDefinition createCustomTypeNoContent() throws InstantiationException, IllegalAccessException {
              MutableDocumentTypeDefinition cmisDocumentType;
              cmisDocumentType = (MutableDocumentTypeDefinition) typeFactory.createChildTypeDefinition(
                      DocumentTypeCreationHelper.getCmisDocumentType(), TEST_CUSTOM_NO_CONTENT_TYPE_ID);
              cmisDocumentType.setDisplayName("No Content Document Type");
              cmisDocumentType.setDescription("InMemory test type definition " + TEST_CUSTOM_NO_CONTENT_TYPE_ID);
              cmisDocumentType.setContentStreamAllowed(ContentStreamAllowed.NOTALLOWED);
              return cmisDocumentType;
          }
  
          private static TypeDefinition createCustomTypeMustHaveContent() throws InstantiationException,
                  IllegalAccessException {
              MutableDocumentTypeDefinition cmisDocumentType;
              cmisDocumentType = (MutableDocumentTypeDefinition) typeFactory.createChildTypeDefinition(
                      DocumentTypeCreationHelper.getCmisDocumentType(), TEST_CUSTOM_MUST_CONTENT_TYPE_ID);
              cmisDocumentType.setDisplayName("Must Have Content Document Type");
              cmisDocumentType.setDescription("InMemory test type definition " + TEST_CUSTOM_MUST_CONTENT_TYPE_ID);
              cmisDocumentType.setContentStreamAllowed(ContentStreamAllowed.NOTALLOWED);
              cmisDocumentType.setContentStreamAllowed(ContentStreamAllowed.REQUIRED);
              return cmisDocumentType;
          }
  
          @SuppressWarnings("serial")
          private static TypeDefinition createFolderTypeWithDefault() throws InstantiationException,
                  IllegalAccessException {
              MutableFolderTypeDefinition cmisFolderType;
              cmisFolderType = typeFactory.createFolderTypeDefinition(CmisVersion.CMIS_1_1, DocumentTypeCreationHelper
                      .getCmisFolderType().getId());
              cmisFolderType.setId(TEST_FOLDER_TYPE_WITH_DEFAULTS_ID);
              cmisFolderType.setDisplayName("Folder Type With default values");
              cmisFolderType.setDescription("InMemory test type definition " + TEST_FOLDER_TYPE_WITH_DEFAULTS_ID);
  
              PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringMultiDefinition(
                      TEST_FOLDER_MY_MULTI_STRING_PROP_ID, "Test Multi String Property", Updatability.READWRITE);
              prop.setIsRequired(false);
              List<String> defValS = new ArrayList<String>() {
                  {
                      add("Apache");
                      add("CMIS");
                  }
              };
              prop.setDefaultValue(defValS);
              cmisFolderType.addPropertyDefinition(prop);
  
              PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
                      TEST_FOLDER_MY_INT_PROP_ID, "Test Integer Property", Updatability.READWRITE);
              prop2.setIsRequired(false);
              List<BigInteger> defVal = new ArrayList<BigInteger>() {
                  {
                      add(BigInteger.valueOf(100));
                  }
              };
              prop2.setDefaultValue(defVal);
              cmisFolderType.addPropertyDefinition(prop2);
  
              PropertyIntegerDefinitionImpl prop3 = PropertyCreationHelper.createIntegerDefinition(
                      TEST_FOLDER_MY_INT_PROP_ID_MANDATORY_DEFAULT, "Test Integer Property Mandatory default",
                      Updatability.READWRITE);
              prop3.setIsRequired(true);
              List<BigInteger> defVal2 = new ArrayList<BigInteger>() {
                  {
                      add(BigInteger.valueOf(100));
                  }
              };
              prop3.setDefaultValue(defVal2);
              cmisFolderType.addPropertyDefinition(prop3);
  
              return cmisFolderType;
          }
  
          private TypeDefinition createRelationshipType() throws InstantiationException, IllegalAccessException {
              MutableRelationshipTypeDefinition cmisRelType;
              cmisRelType = typeFactory.createRelationshipTypeDefinition(CmisVersion.CMIS_1_1, DocumentTypeCreationHelper
                      .getCmisRelationshipType().getId());
              cmisRelType.setId(TEST_RELATION_TYPE_ID);
              cmisRelType.setDisplayName("MyRelationshipType");
              cmisRelType.setDescription("InMemory test type definition " + TEST_RELATION_TYPE_ID);
              DocumentTypeCreationHelper.setDefaultTypeCapabilities(cmisRelType);
              cmisRelType.setIsFileable(false);
  
              // create a single String property definition
  
              PropertyStringDefinitionImpl prop1 = PropertyCreationHelper.createStringDefinition(REL_STRING_PROP,
                      "CrossReferenceType", Updatability.READWRITE);
              cmisRelType.addPropertyDefinition(prop1);
  
              return cmisRelType;
          }
  
          private TypeDefinition createRelationshipTypeRestricted() throws InstantiationException, IllegalAccessException {
              MutableRelationshipTypeDefinition cmisRelType;
              cmisRelType = typeFactory.createRelationshipTypeDefinition(CmisVersion.CMIS_1_1, DocumentTypeCreationHelper
                      .getCmisRelationshipType().getId());
              cmisRelType.setId(TEST_RESTRICTED_RELATION_TYPE_ID);
              cmisRelType.setDisplayName("RestrictedRelationshipType");
              cmisRelType.setDescription("InMemory test type definition " + TEST_RESTRICTED_RELATION_TYPE_ID);
              DocumentTypeCreationHelper.setDefaultTypeCapabilities(cmisRelType);
              cmisRelType.setIsFileable(false);
  
              List<String> allowedTypeIds = Collections.singletonList(TEST_CUSTOM_DOCUMENT_TYPE_ID);
              cmisRelType.setAllowedSourceTypes(allowedTypeIds);
              cmisRelType.setAllowedTargetTypes(allowedTypeIds);
              return cmisRelType;
          }
  
          private static TypeDefinition createItemType() throws InstantiationException, IllegalAccessException {
              // CMIS 1.1 create an item item type
              MutableItemTypeDefinition cmisItemType;
              cmisItemType = typeFactory.createItemTypeDefinition(CmisVersion.CMIS_1_1, DocumentTypeCreationHelper
                      .getCmisItemType().getId()); // ???
                                                   // DocumentTypeCreationHelper.getCmisItemType());
              cmisItemType.setId(TEST_ITEM_TYPE_ID);
              cmisItemType.setDisplayName("MyItemType");
              cmisItemType.setDescription("Builtin InMemory type definition " + TEST_ITEM_TYPE_ID);
              DocumentTypeCreationHelper.setDefaultTypeCapabilities(cmisItemType);
  
              // create a single String property definition
              PropertyStringDefinitionImpl prop1 = PropertyCreationHelper.createStringDefinition(ITEM_STRING_PROP,
                      "Item String Property", Updatability.READWRITE);
              cmisItemType.addPropertyDefinition(prop1);
              // add type to types collection
              return cmisItemType;
          }
  
          private static TypeDefinition createSecondaryType() throws InstantiationException, IllegalAccessException {
              // CMIS 1.1 create an item item type
              MutableSecondaryTypeDefinition cmisSecondaryType;
              cmisSecondaryType = typeFactory.createSecondaryTypeDefinition(CmisVersion.CMIS_1_1,
                      DocumentTypeCreationHelper.getCmisSecondaryType().getId());
              cmisSecondaryType.setId(TEST_SECONDARY_TYPE_ID);
              cmisSecondaryType.setDisplayName("MySecondaryType");
              cmisSecondaryType.setDescription("InMemory test type definition " + TEST_SECONDARY_TYPE_ID);
              DocumentTypeCreationHelper.setDefaultTypeCapabilities(cmisSecondaryType);
              cmisSecondaryType.setIsCreatable(false);
              cmisSecondaryType.setIsFileable(false);
  
              // create a single String property definition
  
              PropertyStringDefinitionImpl prop1 = PropertyCreationHelper.createStringDefinition(SECONDARY_STRING_PROP,
                      "Secondary String Property", Updatability.READWRITE);
              cmisSecondaryType.addPropertyDefinition(prop1);
  
              PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
                      SECONDARY_INTEGER_PROP, "Secondary Integer Property", Updatability.READWRITE);
              prop2.setIsRequired(true);
              cmisSecondaryType.addPropertyDefinition(prop2);
  
              return cmisSecondaryType;
          }
  
          private static TypeDefinition createVersionableType() throws InstantiationException, IllegalAccessException {
              // create a complex type with properties
              MutableDocumentTypeDefinition verType;
              verType = (MutableDocumentTypeDefinition) typeFactory.createChildTypeDefinition(
                      DocumentTypeCreationHelper.getCmisDocumentType(), TEST_VERSION_DOCUMENT_TYPE_ID);
              verType.setDisplayName("VersionedType");
              verType.setDescription("InMemory test type definition " + TEST_VERSION_DOCUMENT_TYPE_ID);
  
              verType.setIsVersionable(true); // make it a versionable type;
  
              // create a String property definition
              PropertyStringDefinitionImpl prop1 = PropertyCreationHelper.createStringDefinition(TEST_VER_PROPERTY_ID,
                      "Sample String Property", Updatability.WHENCHECKEDOUT);
              verType.addPropertyDefinition(prop1);
              return verType;
          }
  
          private static TypeDefinition createPolicyType() throws InstantiationException, IllegalAccessException {
              MutablePolicyTypeDefinition polType;
              polType = typeFactory.createPolicyTypeDefinition(CmisVersion.CMIS_1_1, DocumentTypeCreationHelper
                      .getCmisPolicyType().getId());
              polType.setId(TEST_POLICY_TYPE_ID);
              polType.setDisplayName("Audit Policy");
              polType.setDescription("InMemory type definition " + TEST_POLICY_TYPE_ID);
              DocumentTypeCreationHelper.setDefaultTypeCapabilities(polType);
              polType.setIsFileable(false);
  
              // create a String property definition
              PropertyStringDefinitionImpl prop1 = PropertyCreationHelper.createStringDefinition(TEST_POLICY_PROPERTY_ID,
                      "Audit Kind Property", Updatability.READWRITE);
              polType.addPropertyDefinition(prop1);
              return polType;
          }
      }
  
  }
  