You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by dc...@apache.org on 2010/02/16 17:04:07 UTC

svn commit: r910572 [32/36] - in /incubator/chemistry/trunk/opencmis: ./ _dev/ opencmis-client/ opencmis-client/opencmis-client-api/ opencmis-client/opencmis-client-api/src/ opencmis-client/opencmis-client-api/src/main/ opencmis-client/opencmis-client-...

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/ObjectServiceTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/ObjectServiceTest.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/ObjectServiceTest.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/ObjectServiceTest.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,985 @@
+/*
+ * 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.opencmis.inmemory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.opencmis.client.provider.factory.CmisProviderFactory;
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.SessionParameter;
+import org.apache.opencmis.commons.api.ExtensionsData;
+import org.apache.opencmis.commons.api.PropertyDefinition;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.enums.IncludeRelationships;
+import org.apache.opencmis.commons.enums.UnfileObjects;
+import org.apache.opencmis.commons.enums.VersioningState;
+import org.apache.opencmis.commons.exceptions.CmisConstraintException;
+import org.apache.opencmis.commons.exceptions.CmisNotSupportedException;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.exceptions.CmisUpdateConflictException;
+import org.apache.opencmis.commons.impl.dataobjects.ContentStreamDataImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl;
+import org.apache.opencmis.commons.provider.AccessControlList;
+import org.apache.opencmis.commons.provider.AllowableActionsData;
+import org.apache.opencmis.commons.provider.CmisProvider;
+import org.apache.opencmis.commons.provider.ContentStreamData;
+import org.apache.opencmis.commons.provider.Holder;
+import org.apache.opencmis.commons.provider.NavigationService;
+import org.apache.opencmis.commons.provider.ObjectData;
+import org.apache.opencmis.commons.provider.ObjectInFolderList;
+import org.apache.opencmis.commons.provider.ObjectParentData;
+import org.apache.opencmis.commons.provider.ObjectService;
+import org.apache.opencmis.commons.provider.PropertiesData;
+import org.apache.opencmis.commons.provider.PropertyData;
+import org.apache.opencmis.commons.provider.ProviderObjectFactory;
+import org.apache.opencmis.commons.provider.RepositoryInfoData;
+import org.apache.opencmis.commons.provider.RepositoryService;
+import org.apache.opencmis.inmemory.ConfigConstants;
+import org.apache.opencmis.inmemory.ConfigMap;
+import org.apache.opencmis.inmemory.MapConfigReader;
+import org.apache.opencmis.inmemory.TypeCreator;
+import org.apache.opencmis.inmemory.RepositoryServiceTest.UnitTestRepositoryInfo;
+import org.apache.opencmis.inmemory.server.RuntimeContext;
+import org.apache.opencmis.inmemory.types.InMemoryDocumentTypeDefinition;
+import org.apache.opencmis.inmemory.types.InMemoryFolderTypeDefinition;
+import org.apache.opencmis.inmemory.types.PropertyCreationHelper;
+import org.apache.opencmis.util.repository.ObjectGenerator;
+
+/**
+ * @author Jens
+ */
+
+public class ObjectServiceTest extends TestCase {
+
+  private static Log log = LogFactory.getLog(ObjectServiceTest.class);
+  private static final String REPOSITORY_ID = "UnitTestRepository";
+  private ProviderObjectFactory fFactory;
+  private CmisProvider fProvider;
+  ObjectService fObjSvc;
+  String fRepositoryId;
+  String fRootFolderId;
+  private static final String TEST_FOLDER_TYPE_ID = "MyFolderType";
+  private static final String TEST_DOCUMENT_TYPE_ID = "MyDocumentType";
+  private static final String TEST_FOLDER_STRING_PROP_ID = "MyFolderStringProp";
+  private static final String TEST_DOCUMENT_STRING_PROP_ID = "MyDocumentStringProp";
+  private static final String TEST_CUSTOM_DOCUMENT_TYPE_ID = "MyCustomDocumentType";
+  private static final String TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID ="MyCustomInheritedDocType";
+  private static final String TEST_DOCUMENT_MY_STRING_PROP_ID  = "MyCustomDocumentStringProp";
+  private static final String TEST_DOCUMENT_MY_INT_PROP_ID  = "MyCustomDocumentIntProp";
+  private static final String TEST_DOCUMENT_MY_SUB_STRING_PROP_ID  = "MyInheritedStringProp";
+  private static final String TEST_DOCUMENT_MY_SUB_INT_PROP_ID  = "MyInheritedIntProp";
+  ObjectCreator fCreator;
+  
+  protected void setUp() throws Exception {
+
+    Map<String, String> parameters = new HashMap<String, String>();
+    parameters.put(SessionParameter.BINDING_SPI_CLASS, CmisProviderFactory.BINDING_SPI_INMEMORY);
+    // attach repository info to the session:
+    parameters
+        .put(ConfigConstants.REPOSITORY_INFO_CREATOR_CLASS, UnitTestRepositoryInfo.class.getName());
+
+    parameters.put(ConfigConstants.TYPE_CREATOR_CLASS, ObjectTestTypeSystemCreator.class.getName());
+    parameters.put(ConfigConstants.REPOSITORY_ID, REPOSITORY_ID);
+    parameters.put(ConfigConstants.USERNAME, "TestUser");
+    
+    // get factory and create provider
+    CmisProviderFactory factory = CmisProviderFactory.newInstance();
+    fProvider = factory.createCmisProvider(parameters);
+    assertNotNull(fProvider);
+    fFactory = fProvider.getObjectFactory();
+    RepositoryService repSvc = fProvider.getRepositoryService();
+    RepositoryInfoData rep = repSvc.getRepositoryInfo(REPOSITORY_ID, null);
+    fObjSvc = fProvider.getObjectService();
+    fRepositoryId = rep.getRepositoryId();
+    fRootFolderId = rep.getRootFolderId();
+    fCreator = new ObjectCreator(fFactory, fObjSvc, fRepositoryId);
+
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    ConfigMap cfgReader = new MapConfigReader(parameters);  
+    RuntimeContext.getRuntimeConfig().attachCfg(cfgReader);
+  }
+
+  protected void tearDown() throws Exception {
+  }
+
+  private String createDocument(String folderId, boolean withContent) {
+    VersioningState versioningState = VersioningState.NONE;
+    String id = null;
+    id = fCreator.createDocument(DOCUMENT_ID, DOCUMENT_TYPE_ID, folderId, versioningState, null);
+
+    return id;
+  }
+  
+  private String createFolder() {
+    PropertiesData props = createFolderProperties();
+    String id = null;
+    try {
+      id = fObjSvc.createFolder(fRepositoryId, props, fRootFolderId, null, null, null, null);
+      if (null == id)
+        fail("createFolder failed.");
+    } catch (Exception e) {
+      fail("createFolder() failed with exception: " + e);
+    }
+    return id;
+  }
+
+  private String getDocument(String id) {
+    String returnedId=null;
+    try {
+      ObjectData res = fObjSvc.getObject(fRepositoryId, id, "*", false, IncludeRelationships.NONE,
+          null, false, false, null);
+      assertNotNull(res);
+      testReturnedProperties(res.getProperties().getProperties());
+      returnedId = res.getId();
+      assertEquals(id, returnedId);    
+    } catch (Exception e) {
+      fail("getObject() failed with exception: " + e);
+    }    
+    return returnedId;
+  }
+  
+  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.");
+  }
+
+
+  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");
+    getDocument(id);    
+    log.info("... testGetObject() finished.");
+  }
+  
+  public void testCreateDocumentWithContent() {
+    log.info("starting testCreateDocumentWithContent() ...");
+    String id = createDocument(fRootFolderId, true);
+    if (id != null)
+      log.info("createDocument succeeded with created id: " + id);
+    
+    ContentStreamData 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);
+    fObjSvc.deleteContentStream(fRepositoryId, idHolder, null, null);
+    sd = fObjSvc.getContentStream(fRepositoryId, id, null, BigInteger.valueOf(-1) /* offset */,
+        BigInteger.valueOf(-1) /* length */, null);
+    assertNull(sd);
+    
+    //create content again in a second call
+    ContentStreamData contentStream = createContent();
+    fObjSvc.setContentStream(fRepositoryId, idHolder, true, null, 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 {
+      fObjSvc.setContentStream(fRepositoryId, idHolder, false, null, contentStream, null);
+      fail ("setContentStream with existing content and no overWriteFlag should fail");
+    } catch (Exception e) {
+      assertTrue (e instanceof CmisConstraintException);
+    }
+
+    // cleanup
+    fObjSvc.deleteObject(fRepositoryId, id, true, null);
+    
+    log.info("... testCreateDocumentWithContent() finished.");
+  }
+
+  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;
+      PropertiesData 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
+    ContentStreamData 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.");
+  }
+
+  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.CMIS_NAME);
+      assertNotNull(pd);
+      assertEquals(MY_CUSTOM_NAME, pd.getFirstValue());
+      
+      pd = props.get(PropertyIds.CMIS_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.");
+  }
+  
+  public void testBuildFolderAndDocuments() {
+    // Create a hierarchy of folders and fill it with some documents
+    NavigationService navSvc = fProvider.getNavigationService();
+    ObjectService objSvc = fProvider.getObjectService();
+
+    ObjectGenerator gen = new ObjectGenerator(fFactory, navSvc, objSvc, fRepositoryId);
+    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);
+    }
+  }
+  
+  
+  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");
+    getDocument(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(id, 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.");    
+  }
+  
+  public void testDeleteTree() {
+    log.info("starting testDeleteTree() ...");
+    NavigationService navSvc = fProvider.getNavigationService();
+    ObjectService objSvc = fProvider.getObjectService();
+    ObjectGenerator gen = new ObjectGenerator(fFactory, navSvc, objSvc, fRepositoryId);
+    String rootFolderId = createFolder();
+    // Set the type id for all created documents:
+    gen.setDocumentTypeId(InMemoryDocumentTypeDefinition.getRootDocumentType().getId());    
+    // Set the type id for all created folders:
+    gen.setFolderTypeId(InMemoryFolderTypeDefinition.getRootFolderType().getId());
+    gen.setNumberOfDocumentsToCreatePerFolder(2); // create two documents in each folder    
+    gen.createFolderHierachy(1, 1, rootFolderId);
+    try {
+          fObjSvc.deleteTree(fRepositoryId, rootFolderId, null /*true*/, UnfileObjects.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.");
+  }
+
+  public void testMoveFolder() {
+    log.info("starting testMoveFolder() ...");
+    moveObjectTest(true);
+    log.info("... testMoveFolder() finished.");    
+  }
+  
+  public void testMoveDocument() {
+    log.info("starting testMoveDocument() ...");
+    moveObjectTest(false);
+    log.info("... testMoveDocument() finished.");    
+  }
+
+  public void testUpdateProperties() {
+    log.info("starting testUpdateProperties() ...");
+    String oldChangeToken, newChangeToken;
+    String id = createDocumentWithCustomType(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.CMIS_NAME);
+      assertNotNull(pd);
+      assertEquals(MY_CUSTOM_NAME, pd.getFirstValue());
+      pd = props.get(PropertyIds.CMIS_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");
+      final String newStringPropVal = "My ugly string";
+      final BigInteger newIntPropVal = BigInteger.valueOf(815);        
+      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, newStringPropVal));      
+      properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, newIntPropVal));     
+      PropertiesData 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 use
+      // check if we now retrieve new values
+      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());
+      }     
+      returnedId = res.getId();
+      assertEquals(id, returnedId);    
+      pd = props.get(PropertyIds.CMIS_NAME);
+      assertNotNull(pd);
+      assertEquals(MY_CUSTOM_NAME, pd.getFirstValue());
+      pd = props.get(PropertyIds.CMIS_OBJECT_TYPE_ID);
+      assertEquals(TEST_CUSTOM_DOCUMENT_TYPE_ID, pd.getFirstValue());
+      pd = props.get(TEST_DOCUMENT_MY_STRING_PROP_ID);
+      assertEquals(newStringPropVal, pd.getFirstValue());
+      pd = props.get(TEST_DOCUMENT_MY_INT_PROP_ID);
+      assertEquals(newIntPropVal, pd.getFirstValue());
+      
+      // 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);
+      // 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.CMIS_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.CMIS_NAME);
+      assertNotNull(pd);
+      assertEquals(newName, pd.getFirstValue());
+      
+      // test rename with a conflicting name
+      createDocumentWithCustomType(fRootFolderId, false);
+      properties = new ArrayList<PropertyData<?>>();
+      properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_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 CmisConstraintException);
+      }
+      
+    } catch (Exception e) {
+      fail("getObject() failed with exception: " + e);
+    }    
+    log.info("... testUpdateProperties() finished.");
+  }
+
+  public void testAllowableActions() {
+    log.info("starting testAllowableActions() ...");
+    String id = createDocument(fRootFolderId, false);
+    
+    // get allowable actions via getObject
+    ObjectData res = fObjSvc.getObject(fRepositoryId, id, "*", true, IncludeRelationships.NONE,
+        null, false, false, null);
+    assertNotNull(res.getAllowableActions());
+    Map<String, Boolean> actions = res.getAllowableActions().getAllowableActions();
+    assertNotNull(actions);
+    verifyAllowableActions(actions);
+    
+    // get allowable actions via getAllowableActions
+    AllowableActionsData allowableActions = fObjSvc.getAllowableActions(fRepositoryId, id, null);
+    assertNotNull(allowableActions);
+    actions = allowableActions.getAllowableActions();
+    assertNotNull(actions);
+    verifyAllowableActions(actions);
+
+    // cleanup
+    fObjSvc.deleteObject(fRepositoryId, id, true, null);
+    log.info("... testAllowableActions() finished.");    
+  }
+  
+  private void verifyAllowableActions(Map<String, Boolean> actions) {
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_DELETE_OBJECT));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_UPDATE_PROPERTIES));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_PROPERTIES));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_OBJECT_RELATIONSHIPS));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_OBJECT_PARENTS));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_FOLDER_PARENT));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_FOLDER_TREE));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_DESCENDANTS));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_MOVE_OBJECT));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_DELETE_CONTENT_STREAM));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CHECK_OUT));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CANCEL_CHECK_OUT));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CHECK_IN));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_SET_CONTENT_STREAM));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_ALL_VERSIONS));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_ADD_OBJECT_TO_FOLDER));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_REMOVE_OBJECT_FROM_FOLDER));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_CONTENT_STREAM));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_APPLY_POLICY));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_APPLIED_POLICIES));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_REMOVE_POLICY));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_CHILDREN));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CREATE_DOCUMENT));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CREATE_FOLDER));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CREATE_RELATIONSHIP));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_CREATE_POLICY));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_DELETE_TREE));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_RENDITIONS));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_GET_ACL));
+    assertNotNull(actions.get(AllowableActionsData.ACTION_CAN_APPLY_ACL));
+  }
+  
+  private void moveObjectTest(boolean isFolder) {
+    final String propertyFilter=PropertyIds.CMIS_OBJECT_ID+","+PropertyIds.CMIS_NAME; //+","+PropertyIds.CMIS_OBJECT_TYPE_ID+","+PropertyIds.CMIS_BASE_TYPE_ID;
+    String rootFolderId = createFolder();
+    NavigationService navSvc = fProvider.getNavigationService();
+    ObjectService objSvc = fProvider.getObjectService();
+    ObjectGenerator gen = new ObjectGenerator(fFactory, navSvc, objSvc, fRepositoryId);
+    // Set the type id for all created documents:
+    gen.setDocumentTypeId(InMemoryDocumentTypeDefinition.getRootDocumentType().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(InMemoryFolderTypeDefinition.getRootFolderType().getId());
+    gen.dumpFolder(fRootFolderId, propertyFilter);
+    Holder<String> holder = new Holder<String>();
+    String sourceIdToMove = gen.getFolderId(rootFolderId, 2, 1);
+    if (!isFolder) // get first document in this folder
+      sourceIdToMove = gen.getDocumentId(sourceIdToMove, 0);
+    holder.setValue(sourceIdToMove); // "/Folder_1/My Folder 0/My Folder 1");
+    log.info("Id before moveObject: " + holder.getValue());
+    fObjSvc.moveObject(fRepositoryId, holder, rootFolderId, null, null);
+    log.info("Id after moveObject: " + holder.getValue());
+    gen.dumpFolder(fRootFolderId, propertyFilter);
+
+    List<ObjectParentData> result = navSvc.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 = navSvc.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, null, null);
+        fail("moveObject to a folder that is a descendant of the source must fail.");
+      } catch (Exception e) {
+        assertTrue(e instanceof CmisNotSupportedException );
+      }
+    }
+  }
+  
+  private static final String DOCUMENT_TYPE_ID =  InMemoryDocumentTypeDefinition.getRootDocumentType().getId();
+  private static final String DOCUMENT_ID =  "Document_1";
+  private static final String FOLDER_TYPE_ID =  InMemoryFolderTypeDefinition.getRootFolderType().getId();
+  private static final String FOLDER_ID =  "Folder_1";
+  private static final String MY_CUSTOM_NAME = "My Custom Document";
+  
+  private PropertiesData createDocumentProperties() {
+    List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
+    properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_NAME, DOCUMENT_ID));
+    properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_OBJECT_TYPE_ID, DOCUMENT_TYPE_ID));
+    PropertiesData props = fFactory.createPropertiesData(properties);
+    return props;
+  }
+  
+  private PropertiesData 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.CMIS_NAME, name));
+    PropertiesData props = fFactory.createPropertiesData(properties);
+    return props;
+  }
+
+  private PropertiesData createDocumentProperties(String name) {
+    List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
+    properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_NAME, name));
+    properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_OBJECT_TYPE_ID, DOCUMENT_TYPE_ID));
+    PropertiesData props = fFactory.createPropertiesData(properties);
+    return props;
+  }
+  
+  private PropertiesData createFolderProperties() {
+    List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>();
+    properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_NAME, FOLDER_ID));
+    properties.add(fFactory.createPropertyIdData(PropertyIds.CMIS_OBJECT_TYPE_ID, FOLDER_TYPE_ID));
+    PropertiesData props = fFactory.createPropertiesData(properties);
+    return props;
+  }
+
+  private void testReturnedProperties(Map<String, PropertyData<?>> props) {
+    for (PropertyData<?> pd : props.values()) {
+      log.info("return property id: " + pd.getId() + ", value: " + pd.getValues());
+    }
+    
+    PropertyData<?> pd = props.get(PropertyIds.CMIS_NAME);
+    assertNotNull(pd);
+    assertEquals(DOCUMENT_ID, pd.getFirstValue());
+    pd = props.get(PropertyIds.CMIS_OBJECT_TYPE_ID);
+    assertEquals(DOCUMENT_TYPE_ID, pd.getFirstValue());
+  }
+ 
+  private String createDocumentWithCustomType(String folderId, boolean withContent) {
+    ContentStreamData contentStream = null;
+    VersioningState versioningState = VersioningState.NONE;
+    List<String> policies = null;
+    AccessControlList addACEs = null;
+    AccessControlList removeACEs = null;
+    ExtensionsData extension = null;
+    ObjectService objSvc = fProvider.getObjectService();
+
+    // create the properties:
+    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, "My pretty string"));      
+    properties.add(fFactory.createPropertyIntegerData(TEST_DOCUMENT_MY_INT_PROP_ID, BigInteger.valueOf(4711)));      
+
+    PropertiesData props = fFactory.createPropertiesData(properties);
+    
+    if (withContent)
+      contentStream = createContent();
+    
+    // create the document 
+    String id = null;
+    id = objSvc.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) {
+    ContentStreamData contentStream = null;
+    VersioningState versioningState = VersioningState.NONE;
+    List<String> policies = null;
+    AccessControlList addACEs = null;
+    AccessControlList removeACEs = null;
+    ExtensionsData extension = null;
+    ObjectService objSvc = fProvider.getObjectService();
+
+    // create the properties:
+    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_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)));
+        
+    PropertiesData props = fFactory.createPropertiesData(properties);
+    
+    if (withContent)
+      contentStream = createContent();
+    
+    // create the document 
+    String id = null;
+    id = objSvc.createDocument(fRepositoryId, props, folderId, contentStream, versioningState,
+        policies, addACEs, removeACEs, extension);
+    if (null == id)
+      throw new RuntimeException("createDocument failed.");
+    return id;
+  }
+
+  ContentStreamData createContent() {
+    ContentStreamDataImpl content = new ContentStreamDataImpl();
+    content.setFilename("data.txt");
+    content.setMimeType("text/plain");
+    int len = 32 * 1024;
+    byte[] b = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+                0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x0c, 0x0a,     
+                0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+                0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x0c, 0x0a
+                }; // 32 Bytes
+    ByteArrayOutputStream ba = new ByteArrayOutputStream(len);
+    try {
+      for (int i=0; i<1024; i++)
+        ba.write(b);
+    } catch (IOException e) {
+        throw new RuntimeException("Failed to fill content stream with data", e) ;
+    }
+    content.setStream(new ByteArrayInputStream(ba.toByteArray()));
+    return content;
+  }
+
+  private void verifyContentResult(ContentStreamData sd) {
+    assertEquals("text/plain", sd.getMimeType());
+    assertEquals("data.txt", sd.getFilename());
+    assertEquals(32 * 1024, sd.getLength().longValue());
+    byte[] ba = new byte[32];
+    InputStream is = sd.getStream();
+    int counter = 0;
+    try {
+      while (is.read(ba) == ba.length) {
+        ++counter;      
+        assertEquals(0x61, ba[0]);
+        assertEquals(0x6e, ba[29]);
+        assertEquals(0x0c, ba[30]);
+        assertEquals(0x0a, ba[31]);
+      }
+    }
+    catch (IOException e) {
+      junit.framework.Assert.fail("reading from content stream failed");
+    }
+    assertEquals(1024, counter);
+  }
+  
+  
+  // Helper class to create some type for testing the ObjectService
+  
+  public static class ObjectTestTypeSystemCreator implements TypeCreator {
+
+    /**
+     * create root types and a sample type for folder and document
+     * 
+     * @return typesMap map filled with created types
+     */
+    public List<TypeDefinition> createTypesList() {
+      List<TypeDefinition> typesList = new LinkedList<TypeDefinition>();
+      InMemoryDocumentTypeDefinition cmisDocumentType = new InMemoryDocumentTypeDefinition(TEST_DOCUMENT_TYPE_ID,
+          "My Document Type", InMemoryDocumentTypeDefinition.getRootDocumentType());
+
+      InMemoryFolderTypeDefinition cmisFolderType = new InMemoryFolderTypeDefinition(TEST_FOLDER_TYPE_ID,
+          "My Folder Type", InMemoryFolderTypeDefinition.getRootFolderType());
+      // 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");
+      propertyDefinitions.put(prop.getId(), prop);
+      cmisDocumentType.addCustomPropertyDefinitions(propertyDefinitions);
+
+      propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      prop = PropertyCreationHelper.createStringDefinition(TEST_FOLDER_STRING_PROP_ID, "Sample Folder String Property");
+      propertyDefinitions.put(prop.getId(), prop);
+      cmisFolderType.addCustomPropertyDefinitions(propertyDefinitions);
+
+      InMemoryDocumentTypeDefinition customDocType = createCustomTypeWithStringIntProperty();
+      // add type to types collection
+      typesList.add(cmisDocumentType);
+      typesList.add(cmisFolderType);
+      typesList.add(customDocType);
+      typesList.add(createCustomInheritedType(customDocType));
+      return typesList;
+    }
+    
+    private static InMemoryDocumentTypeDefinition createCustomTypeWithStringIntProperty() {
+      InMemoryDocumentTypeDefinition cmisDocumentType = new InMemoryDocumentTypeDefinition(TEST_CUSTOM_DOCUMENT_TYPE_ID,
+          "My Custom Document Type", InMemoryDocumentTypeDefinition.getRootDocumentType());
+      Map<String, PropertyDefinition<?>> propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringDefinition(
+          TEST_DOCUMENT_MY_STRING_PROP_ID, "My String Property");
+      prop.setIsRequired(false);
+      prop.setMaxLength(BigInteger.valueOf(20)); // max len to 20
+      propertyDefinitions.put(prop.getId(), prop);
+
+      PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
+          TEST_DOCUMENT_MY_INT_PROP_ID, "My Integer Property");
+      prop2.setIsRequired(true);
+      prop2.setMinValue(BigInteger.valueOf(-10000));
+      prop2.setMaxValue(BigInteger.valueOf(10000));
+      propertyDefinitions.put(prop2.getId(), prop2);
+      cmisDocumentType.addCustomPropertyDefinitions(propertyDefinitions);
+      return cmisDocumentType;
+    }
+    
+    private static InMemoryDocumentTypeDefinition createCustomInheritedType(InMemoryDocumentTypeDefinition baseType) {
+      InMemoryDocumentTypeDefinition cmisDocumentType = new InMemoryDocumentTypeDefinition(TEST_INHERITED_CUSTOM_DOCUMENT_TYPE_ID,
+          "My Custom Document Type", baseType);
+      Map<String, PropertyDefinition<?>> propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      PropertyStringDefinitionImpl prop = PropertyCreationHelper.createStringDefinition(
+          TEST_DOCUMENT_MY_SUB_STRING_PROP_ID, "Subtype String Property");
+      prop.setIsRequired(false);
+      propertyDefinitions.put(prop.getId(), prop);
+
+      PropertyIntegerDefinitionImpl prop2 = PropertyCreationHelper.createIntegerDefinition(
+          TEST_DOCUMENT_MY_SUB_INT_PROP_ID, "Subtype");
+      prop2.setIsRequired(true);
+      propertyDefinitions.put(prop2.getId(), prop2);
+      cmisDocumentType.addCustomPropertyDefinitions(propertyDefinitions);
+      return cmisDocumentType;
+    }
+    
+  }
+
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/ObjectServiceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/RepositoryServiceTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/RepositoryServiceTest.java?rev=910572&view=auto
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/RepositoryServiceTest.java (added)
+++ incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/RepositoryServiceTest.java Tue Feb 16 16:03:38 2010
@@ -0,0 +1,750 @@
+/*
+ * 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.opencmis.inmemory;
+
+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 junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.opencmis.client.provider.factory.CmisProviderFactory;
+import org.apache.opencmis.commons.PropertyIds;
+import org.apache.opencmis.commons.SessionParameter;
+import org.apache.opencmis.commons.api.Choice;
+import org.apache.opencmis.commons.api.PropertyDefinition;
+import org.apache.opencmis.commons.api.TypeDefinitionContainer;
+import org.apache.opencmis.commons.api.TypeDefinition;
+import org.apache.opencmis.commons.api.TypeDefinitionList;
+import org.apache.opencmis.commons.enums.BaseObjectTypeIds;
+import org.apache.opencmis.commons.enums.CapabilityAcl;
+import org.apache.opencmis.commons.enums.CapabilityChanges;
+import org.apache.opencmis.commons.enums.CapabilityContentStreamUpdates;
+import org.apache.opencmis.commons.enums.CapabilityJoin;
+import org.apache.opencmis.commons.enums.CapabilityQuery;
+import org.apache.opencmis.commons.enums.CapabilityRendition;
+import org.apache.opencmis.commons.exceptions.CmisObjectNotFoundException;
+import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
+import org.apache.opencmis.commons.impl.dataobjects.ChoiceImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyDateTimeDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyHtmlDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyIdDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.PropertyUriDefinitionImpl;
+import org.apache.opencmis.commons.impl.dataobjects.RepositoryCapabilitiesDataImpl;
+import org.apache.opencmis.commons.impl.dataobjects.RepositoryInfoDataImpl;
+import org.apache.opencmis.commons.provider.CmisProvider;
+import org.apache.opencmis.commons.provider.RepositoryInfoData;
+import org.apache.opencmis.inmemory.ConfigConstants;
+import org.apache.opencmis.inmemory.ConfigMap;
+import org.apache.opencmis.inmemory.MapConfigReader;
+import org.apache.opencmis.inmemory.RepositoryInfoCreator;
+import org.apache.opencmis.inmemory.server.RuntimeContext;
+import org.apache.opencmis.inmemory.types.DocumentTypeCreationHelper;
+import org.apache.opencmis.inmemory.types.InMemoryDocumentTypeDefinition;
+import org.apache.opencmis.inmemory.types.PropertyCreationHelper;
+/**
+ * @author Jens
+ */
+public class RepositoryServiceTest extends TestCase {
+
+  private CmisProvider fProvider;
+
+  private static Log log = LogFactory.getLog(RepositoryServiceTest.class);
+  private static final String REPOSITORY_ID = "UnitTestRepository";
+
+  static public class UnitTestRepositoryInfo implements RepositoryInfoCreator {
+
+    public RepositoryInfoData createRepositoryInfo() {
+      RepositoryCapabilitiesDataImpl caps = new RepositoryCapabilitiesDataImpl();
+      caps.setAllVersionsSearchable(false);
+      caps.setCapabilityAcl(CapabilityAcl.NONE);
+      caps.setCapabilityChanges(CapabilityChanges.NONE);
+      caps.setCapabilityContentStreamUpdates(CapabilityContentStreamUpdates.ANYTIME);
+      caps.setCapabilityJoin(CapabilityJoin.NONE);
+      caps.setCapabilityQuery(CapabilityQuery.NONE);
+      caps.setCapabilityRendition(CapabilityRendition.NONE);
+      caps.setIsPwcSearchable(false);
+      caps.setIsPwcUpdatable(true);
+      caps.setSupportsGetDescendants(true);
+      caps.setSupportsGetFolderTree(true);
+      caps.setSupportsMultifiling(false);
+      caps.setSupportsUnfiling(true);
+      caps.setSupportsVersionSpecificFiling(false);
+      
+      RepositoryInfoDataImpl repositoryInfo = new RepositoryInfoDataImpl();     
+      repositoryInfo.setRepositoryId(REPOSITORY_ID);
+      repositoryInfo.setRepositoryName("InMemory Repository");
+      repositoryInfo.setRepositoryDescription("InMemory Test Repository");
+      repositoryInfo.setCmisVersionSupported("0.7");
+      repositoryInfo.setRepositoryCapabilities(caps);
+      repositoryInfo.setRootFolder("/");
+      repositoryInfo.setAclCapabilities(null);
+      repositoryInfo.setPrincipalAnonymous("anonymous");
+      repositoryInfo.setPrincipalAnyone("anyone");
+      repositoryInfo.setThinClientUri(null);
+      repositoryInfo.setChangesIncomplete(Boolean.TRUE);
+      repositoryInfo.setChangesOnType(null);
+      repositoryInfo.setLatestChangeLogToken(null);
+      repositoryInfo.setVendorName("OpenCMIS");
+      repositoryInfo.setProductName("OpenCMIS Client");
+      repositoryInfo.setProductVersion("0.1");
+      return repositoryInfo;
+    }    
+  }
+  
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see junit.framework.TestCase#setUp()
+   */
+  protected void setUp() throws Exception {
+    // gather parameters
+    Map<String, String> parameters = new HashMap<String, String>();
+    parameters.put(SessionParameter.BINDING_SPI_CLASS, CmisProviderFactory.BINDING_SPI_INMEMORY);
+
+    // attach repository info to the session:
+    parameters.put(ConfigConstants.REPOSITORY_INFO_CREATOR_CLASS, UnitTestRepositoryInfo.class.getName());
+    // attach TypeSystem to the session
+    parameters.put(ConfigConstants.TYPE_CREATOR_CLASS, RepositoryTestTypeSystemCreator.class.getName());
+    parameters.put(ConfigConstants.REPOSITORY_ID, REPOSITORY_ID);
+
+    // get factory and create provider
+    CmisProviderFactory factory = CmisProviderFactory.newInstance();
+    fProvider = factory.createCmisProvider(parameters);
+    assertNotNull(fProvider);
+    
+    // Attach the CallContext to a thread local context that can be accessed from everywhere
+    ConfigMap cfgReader = new MapConfigReader(parameters);  
+    RuntimeContext.getRuntimeConfig().attachCfg(cfgReader);
+  }
+
+  public void testRepositoryInfo() throws Exception {
+    log.info("starting testRepositoryInfo() ...");
+    List<RepositoryInfoData> repositories = fProvider.getRepositoryService().getRepositoryInfos(
+        null);
+    assertNotNull(repositories);
+    assertFalse(repositories.isEmpty());
+
+    log.info("geRepositoryInfo(), found " + repositories.size() + " repository/repositories).");
+
+    for (RepositoryInfoData repository : repositories) {
+      RepositoryInfoData repository2 = fProvider.getRepositoryService().getRepositoryInfo(
+          repository.getRepositoryId(), null);
+      assertNotNull(repository2);
+      assertEquals(repository.getRepositoryId(), repository2.getRepositoryId());
+      log.info("found repository" + repository2.getRepositoryId());
+    }
+
+    log.info("... testRepositoryInfo() finished.");
+  }
+
+  public void testTypeDefinition() throws Exception {
+    log.info("");
+    log.info("starting testTypeDefinition() ...");
+    String repositoryId = getRepositoryId();
+    String typeId = "MyDocType1";
+    TypeDefinition ref = RepositoryTestTypeSystemCreator.getTypeById(typeId);
+    TypeDefinition type = fProvider.getRepositoryService().getTypeDefinition(repositoryId,
+        typeId, null);
+    assertEquals(ref.getId(), type.getId());
+    assertEquals(ref.getDescription(), type.getDescription());
+    assertEquals(ref.getDisplayName(), type.getDisplayName());
+    assertEquals(ref.getLocalName(), type.getLocalName());
+    assertEquals(ref.getLocalNamespace(), type.getLocalNamespace());
+    containsAllBasePropertyDefinitions(type);
+    log.info("... testTypeDefinition() finished.");
+  }
+
+  public void testGetAllTypesUnlimitedDepth() {
+    log.info("");
+    log.info("starting testGetAllTypesUnlimitedDepth()...");
+    String repositoryId = getRepositoryId();
+
+    // get types
+    List<TypeDefinitionContainer> types = fProvider.getRepositoryService().getTypeDescendants(
+        repositoryId, null/* all types */, BigInteger.valueOf(-1), Boolean.TRUE, null);
+    assertNotNull(types);
+    log.info("Repository " + repositoryId + " contains " + types.size() + " type(s).");
+    // check that we got all types
+    int expectedSize = RepositoryTestTypeSystemCreator.getTypesList().size()
+        + DocumentTypeCreationHelper.getDefaultTypes().size();
+    assertEquals(expectedSize, types.size());
+
+    for (TypeDefinitionContainer type : types) {
+      assertNotNull(type);
+      TypeDefinition typeDef = type.getTypeDefinition();
+      assertNotNull(typeDef);
+      assertNotNull(typeDef.getId());
+      assertNotNull(typeDef.getBaseId());
+      log.info("Found type: " + typeDef.getId() + ", display name is: " + typeDef.getDisplayName());
+      log.info("  Base type is: " + typeDef.getBaseId());
+      log.info("  Number of children types is: " + type.getChildren().size());
+      Map<String, PropertyDefinition<?>> propDefs = type.getTypeDefinition().getPropertyDefinitions();
+      log.info("  Number of properties is: " + (propDefs==null ? 0 : propDefs.size()));
+      containsAllBasePropertyDefinitions(typeDef);
+    }
+
+    log.info("... testGetAllTypesUnlimitedDepth() finished.");
+  }
+
+  public void testGetAllTypesLimitedDepth() {
+    log.info("");
+    log.info("starting testGetAllTypesLimitedDepth()...");
+    String repositoryId = getRepositoryId();
+
+    // get types
+    int depth = 2;
+    List<TypeDefinitionContainer> types = fProvider.getRepositoryService().getTypeDescendants(
+        repositoryId, null/* all types */, BigInteger.valueOf(depth), Boolean.TRUE, null);
+    assertNotNull(types);
+    log.info("Found in repository " + repositoryId + " " + types.size() + " type(s) with depth "
+        + depth + ".");
+
+    for (TypeDefinitionContainer type : types) {
+      TypeDefinition typeDef = type.getTypeDefinition();
+      log.info("Found type: " + typeDef.getId() + ", display name is: " + typeDef.getDisplayName());
+      log.info("  Base type is: " + typeDef.getBaseId());
+      log.info("  Number of children types is: " + type.getChildren().size());
+      containsAllBasePropertyDefinitions(typeDef);
+    }
+
+    assertEquals(21, types.size()); // Note that spec says that has to be ignored if type is null.
+    assertTrue(containsTypeById(BaseObjectTypeIds.CMIS_DOCUMENT.value(), types));
+    assertTrue(containsTypeById(BaseObjectTypeIds.CMIS_FOLDER.value(), types));
+    // Commented out, because spec requires not to deliver these types if policies and relations
+    // are not supported
+//    assertTrue(containsTypeById(BaseObjectTypeIds.CMIS_RELATIONSHIP.value(), types));
+//    assertTrue(containsTypeById(BaseObjectTypeIds.CMIS_POLICY.value(), types));
+    assertTrue(containsTypeById("MyDocType1", types));
+    assertTrue(containsTypeById("MyDocType2", types));
+
+    for (TypeDefinitionContainer type : types) {
+      assertNotNull(type);
+      TypeDefinition typeDef = type.getTypeDefinition();
+      assertNotNull(typeDef);
+      assertNotNull(typeDef.getId());
+      assertNotNull(typeDef.getBaseId());
+    }
+
+    log.info("... testGetAllTypesLimitedDepth() finished.");
+  }
+
+  public void testGetSpecificTypeLimitedDepth() {
+    log.info("");
+    log.info("starting testGetSpecificTypeLimitedDepth()...");
+    String repositoryId = getRepositoryId();
+
+    // get types
+    int depth = 2;
+    String typeId = "MyDocType1";
+    List<TypeDefinitionContainer> types = fProvider.getRepositoryService().getTypeDescendants(
+        repositoryId, typeId, BigInteger.valueOf(depth), Boolean.TRUE, null);
+    assertNotNull(types);
+    log.info("Found in repository " + repositoryId + " for type " + typeId + ", " + types.size()
+        + " type(s) with depth " + depth + ".");
+
+    assertEquals(4, types.size());
+    assertTrue(containsTypeById("MyDocType1.1", types));
+    assertTrue(containsTypeById("MyDocType1.1.1", types));
+    assertTrue(containsTypeById("MyDocType1.1.2", types));
+    assertTrue(containsTypeById("MyDocType1.2", types));
+
+    for (TypeDefinitionContainer type : types) {
+      assertNotNull(type);
+      TypeDefinition typeDef = type.getTypeDefinition();
+      assertNotNull(typeDef);
+      assertNotNull(typeDef.getId());
+      assertNotNull(typeDef.getBaseId());
+      log.info("Found type: " + typeDef.getId() + ", display name is: " + typeDef.getDisplayName());
+      log.info("  Base type is: " + typeDef.getBaseId());
+      log.info("  Number of children types is: " + type.getChildren().size());
+      containsAllBasePropertyDefinitions(typeDef);
+    }
+
+    log.info("... testGetSpecificTypeLimitedDepth() finished.");
+  }
+  
+  public void testGetTypesWithoutProperties() {
+    log.info("");
+    log.info("starting testGetTypesWithoutProperties()...");
+    String repositoryId = getRepositoryId();
+    String typeId = BaseObjectTypeIds.CMIS_DOCUMENT.value();
+
+    // get types
+    List<TypeDefinitionContainer> types = fProvider.getRepositoryService().getTypeDescendants(
+        repositoryId, typeId, BigInteger.valueOf(-1), false, null);
+    assertNotNull(types);
+    log.info("Repository " + repositoryId + " contains " + types.size() + " type(s).");
+
+    TypeDefinitionContainer typeWithProps = null;
+    for (TypeDefinitionContainer type : types) {
+      if (type.getTypeDefinition().getId().equals(RepositoryTestTypeSystemCreator.COMPLEX_TYPE)) {
+        typeWithProps = type;
+        break;
+      }
+    }
+    assertNotNull(typeWithProps);
+    TypeDefinition typeDef = typeWithProps.getTypeDefinition();
+    Map<String, PropertyDefinition<?>> propDefs = typeDef.getPropertyDefinitions();
+    log.info("Found type: " + typeDef.getId() + ", display name is: " + typeDef.getDisplayName());
+    log.info("  Base type is: " + typeDef.getBaseId());
+    log.info("  Number of properties is: " + (propDefs==null ? 0 : propDefs.size()));
+    assertTrue(propDefs==null || propDefs.size()==0);
+    log.info("... testGetTypesWithoutProperties() finished.");
+  }
+
+  public void testGetTypeChildren() {
+    log.info("");
+    log.info("starting testGetTypeChildren()...");
+    String repositoryId = getRepositoryId();
+    String typeId = "MyDocType2";
+
+    // get all children
+    BigInteger maxItems = BigInteger.valueOf(1000);
+    BigInteger skipCount = BigInteger.valueOf(0);
+    TypeDefinitionList children = fProvider.getRepositoryService().getTypeChildren(repositoryId,
+        typeId, true, maxItems, skipCount, null);
+
+    for (TypeDefinition type : children.getList()) {
+      log.info("Found type: " + type.getId() + ", display name is: " + type.getDisplayName());
+      containsAllBasePropertyDefinitions(type);
+    }
+    assertEquals(9, children.getList().size());
+    assertEquals(9, children.getNumItems().intValue());
+    assertFalse(children.hasMoreItems());
+
+    // get a chunk
+    maxItems = BigInteger.valueOf(5);
+    skipCount = BigInteger.valueOf(3);
+    children = fProvider.getRepositoryService().getTypeChildren(repositoryId, typeId, true,
+        maxItems, skipCount, null);
+
+    for (TypeDefinition type : children.getList()) {
+      log.info("Found type: " + type.getId() + ", display name is: " + type.getDisplayName());
+      containsAllBasePropertyDefinitions(type);
+    }
+    assertEquals(5, children.getList().size());
+    assertEquals(9, children.getNumItems().intValue());
+    assertTrue(children.hasMoreItems());
+
+    log.info("... testGetTypeChildren() finished.");
+  }
+
+  public void testGetWrongParameters() {
+    log.info("");
+    log.info("starting testGetWrongParameters()...");
+    String repositoryId = getRepositoryId();
+    String wrongRepositoryId = "NonExistantRepository";
+
+    // get types
+    int depth = -1;
+    String wrongTypeId = "UnknownType";
+
+    try {
+      RepositoryInfoData repInf = fProvider.getRepositoryService().getRepositoryInfo(
+          wrongRepositoryId, null);
+      log.debug("getRepositoryInfo(): " + repInf);
+      fail("getRepositoryInfo() with illegal repository id should throw InvalidArgumentException.");
+    }
+    catch (CmisInvalidArgumentException e) {
+      log.info("getRepositoryInfo() with depth==0 raised expected exception: " + e);
+    }
+
+    try {
+      List<TypeDefinitionContainer> types = fProvider.getRepositoryService().getTypeDescendants(
+          repositoryId, "CMISDocument", BigInteger.valueOf(0), Boolean.TRUE, null);
+      log.debug("getTypeDescendants(): " + types);
+      fail("getTypeDescendants() with depth 0 should throw InvalidArgumentException.");
+    }
+    catch (CmisInvalidArgumentException e) {
+      log.info("getTypeDescendants() with depth==0 raised expected exception: " + e);
+    }
+
+    try {
+      List<TypeDefinitionContainer> types = fProvider.getRepositoryService().getTypeDescendants(
+          repositoryId, wrongTypeId, BigInteger.valueOf(depth), Boolean.TRUE, null);
+      log.debug("getTypeDescendants(): " + types);
+      fail("getTypeDescendants() with unknown type should throw exception.");
+    }
+    catch (CmisInvalidArgumentException e) {
+      log.info("getTypeDescendants() with unknown type raised expected exception: " + e);
+    }
+
+    try {
+      TypeDefinition type = fProvider.getRepositoryService().getTypeDefinition(
+          wrongRepositoryId, "CMISDocument", null);
+      log.debug("getTypeDefinition(): " + type);
+      fail("getTypeDefinition() with unknown repository id should throw exception.");
+    }
+    catch (CmisInvalidArgumentException e) {
+      log.info("getTypeDefinition() with unknown repository id raised expected exception: " + e);
+    }
+
+    try {
+      TypeDefinition type = fProvider.getRepositoryService().getTypeDefinition(repositoryId,
+          wrongTypeId, null);
+      log.debug("getTypeDefinition(): " + type);
+      fail("getTypeDefinition() with unknown type should throw exception.");
+    }
+    catch (CmisObjectNotFoundException e) {
+      log.info("getTypeDefinition() with unknown type raised expected exception: " + e);
+    }
+
+    try {
+      TypeDefinitionList types = fProvider.getRepositoryService().getTypeChildren(
+          wrongRepositoryId, "CMISDocument", Boolean.TRUE, BigInteger.valueOf(100),
+          BigInteger.ZERO, null);
+      log.debug("getTypeChildren(): " + types);
+      fail("getTypeDescendants() with unknown type should throw InvalidArgumentException.");
+    }
+    catch (CmisInvalidArgumentException e) {
+      log.info("getTypeDescendants() with unknown repository id raised expected exception: " + e);
+    }
+
+    try {
+      TypeDefinitionList types = fProvider.getRepositoryService().getTypeChildren(repositoryId,
+          wrongTypeId, Boolean.TRUE, BigInteger.valueOf(100), BigInteger.ZERO, null);
+      log.debug("getTypeChildren(): " + types);
+      fail("getTypeDescendants() with unknown type should throw exception.");
+    }
+    catch (CmisInvalidArgumentException e) {
+      log.info("getTypeDescendants() with unknown type raised expected exception: " + e);
+    }
+
+    log.info("... testGetUnknownType() testGetWrongParameters.");
+
+  }
+
+  public void testInheritedProperties() {
+    log.info("");
+    log.info("starting testInheritedProperties()...");
+    String repositoryId = getRepositoryId();
+    String typeId = RepositoryTestTypeSystemCreator.TOPLEVEL_TYPE;
+
+    // get top level type
+    TypeDefinition typeContainer = fProvider.getRepositoryService().getTypeDefinition(
+        repositoryId, typeId, null);
+    assertNotNull(typeContainer);
+    Map<String, PropertyDefinition<?>> propDefMap = typeContainer.getPropertyDefinitions();
+    assertTrue(propDefMap.containsKey("StringPropTopLevel"));
+    assertFalse(propDefMap.get("StringPropTopLevel").isInherited());
+    assertFalse(propDefMap.containsKey("StringPropLevel1"));
+    assertFalse(propDefMap.containsKey("StringPropLevel2"));
+    containsAllBasePropertyDefinitions(typeContainer);
+    
+    // get level 1 type
+    typeId = RepositoryTestTypeSystemCreator.LEVEL1_TYPE;
+    typeContainer = fProvider.getRepositoryService().getTypeDefinition(
+        repositoryId, typeId, null);
+    assertNotNull(typeContainer);
+    propDefMap = typeContainer.getPropertyDefinitions();
+    assertTrue(propDefMap.containsKey("StringPropTopLevel"));
+    assertTrue(propDefMap.get("StringPropTopLevel").isInherited());
+    assertTrue(propDefMap.containsKey("StringPropLevel1"));
+    assertFalse(propDefMap.get("StringPropLevel1").isInherited());
+    assertFalse(propDefMap.containsKey("StringPropLevel2"));
+    containsAllBasePropertyDefinitions(typeContainer);
+    
+    // get level 2 type
+    typeId = RepositoryTestTypeSystemCreator.LEVEL2_TYPE;
+    typeContainer = fProvider.getRepositoryService().getTypeDefinition(
+        repositoryId, typeId, null);
+    assertNotNull(typeContainer);
+    propDefMap = typeContainer.getPropertyDefinitions();
+    assertTrue(propDefMap.containsKey("StringPropTopLevel"));
+    assertTrue(propDefMap.get("StringPropTopLevel").isInherited());
+    assertTrue(propDefMap.containsKey("StringPropLevel1"));
+    assertTrue(propDefMap.get("StringPropLevel1").isInherited());
+    assertTrue(propDefMap.containsKey("StringPropLevel2"));
+    assertFalse(propDefMap.get("StringPropLevel2").isInherited());
+    containsAllBasePropertyDefinitions(typeContainer);
+    
+    log.info("... testInheritedProperties() finished.");
+  }
+
+  private String getRepositoryId() {
+    List<RepositoryInfoData> repositories = fProvider.getRepositoryService().getRepositoryInfos(
+        null);
+    RepositoryInfoData repository = repositories.get(0);
+    assertNotNull(repository);
+    return repository.getRepositoryId();
+  }
+
+  private boolean containsTypeById(String typeId, List<TypeDefinitionContainer> types) {
+    for (TypeDefinitionContainer type : types) {
+      if (type.getTypeDefinition().getId().equals(typeId))
+        return true;
+    }
+    return false;
+  }
+  
+  private void containsAllBasePropertyDefinitions(TypeDefinition typeDef) {
+    Map<String, PropertyDefinition<?>> propDefs = typeDef.getPropertyDefinitions();
+    String baseTypeId = typeDef.getBaseId().value();
+    
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_NAME));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_OBJECT_ID));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_OBJECT_TYPE_ID));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_BASE_TYPE_ID));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_CREATED_BY));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_CREATION_DATE));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_LAST_MODIFIED_BY));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_LAST_MODIFICATION_DATE));
+    assertTrue(propDefs.containsKey(PropertyIds.CMIS_CHANGE_TOKEN));
+
+    if (baseTypeId.equals(BaseObjectTypeIds.CMIS_DOCUMENT.value())) {
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_IS_IMMUTABLE));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_IS_LATEST_VERSION));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_IS_MAJOR_VERSION));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_IS_LATEST_MAJOR_VERSION));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_VERSION_LABEL));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_VERSION_SERIES_ID));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_IS_VERSION_SERIES_CHECKED_OUT));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_VERSION_SERIES_CHECKED_OUT_BY));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_VERSION_SERIES_CHECKED_OUT_ID));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_CHECKIN_COMMENT));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_CONTENT_STREAM_LENGTH));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_CONTENT_STREAM_MIME_TYPE));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_CONTENT_STREAM_FILE_NAME));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_CONTENT_STREAM_ID));
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_CHANGE_TOKEN));      
+    } else if (baseTypeId.equals(BaseObjectTypeIds.CMIS_FOLDER.value())) {
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_PARENT_ID));      
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_ALLOWED_CHILD_OBJECT_TYPE_IDS));      
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_PATH));            
+    } else if (baseTypeId.equals(BaseObjectTypeIds.CMIS_POLICY.value())) {
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_POLICY_TEXT));            
+    } else if (baseTypeId.equals(BaseObjectTypeIds.CMIS_RELATIONSHIP.value())) {
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_SOURCE_ID));      
+      assertTrue(propDefs.containsKey(PropertyIds.CMIS_TARGET_ID));            
+    } else
+      fail("Unknown base type id in type definition");
+  }
+  
+  public static class RepositoryTestTypeSystemCreator implements TypeCreator {
+
+    public static final String COMPLEX_TYPE = "ComplexType";
+    public static final String TOPLEVEL_TYPE = "DocumentTopLevel";
+    public static final String LEVEL1_TYPE = "DocumentLevel1";;
+    public static final String LEVEL2_TYPE = "DocumentLevel2";
+    
+    static public List<TypeDefinition> singletonTypes = buildTypesList();
+    
+    public List<TypeDefinition> createTypesList() {
+      return singletonTypes;
+    }
+
+    private static List<TypeDefinition> buildTypesList() {
+      List<TypeDefinition> typesList = new LinkedList<TypeDefinition>();
+
+      InMemoryDocumentTypeDefinition cmisType1 = new InMemoryDocumentTypeDefinition("MyDocType1",
+          "My Type 1 Level 1", InMemoryDocumentTypeDefinition.getRootDocumentType());
+      typesList.add(cmisType1);
+      
+
+      InMemoryDocumentTypeDefinition cmisType2 = new InMemoryDocumentTypeDefinition("MyDocType2",
+          "My Type 2 Level 1", InMemoryDocumentTypeDefinition.getRootDocumentType());
+      typesList.add(cmisType2);
+
+      InMemoryDocumentTypeDefinition cmisType11 = new InMemoryDocumentTypeDefinition("MyDocType1.1",
+          "My Type 3 Level 2", cmisType1);
+      typesList.add(cmisType11);
+
+      InMemoryDocumentTypeDefinition cmisType111 = new InMemoryDocumentTypeDefinition("MyDocType1.1.1",
+          "My Type 4 Level 3", cmisType11);
+      typesList.add(cmisType111);
+
+      InMemoryDocumentTypeDefinition cmisType112 = new InMemoryDocumentTypeDefinition("MyDocType1.1.2",
+          "My Type 5 Level 3", cmisType11);
+      typesList.add(cmisType112);
+
+      InMemoryDocumentTypeDefinition cmisType12 = new InMemoryDocumentTypeDefinition("MyDocType1.2",
+          "My Type 6 Level 2", cmisType1);
+      typesList.add(cmisType12);
+
+      InMemoryDocumentTypeDefinition cmisType21 = new InMemoryDocumentTypeDefinition("MyDocType2.1",
+          "My Type 7 Level 2", cmisType2);
+      typesList.add(cmisType21);
+
+      InMemoryDocumentTypeDefinition cmisType22 = new InMemoryDocumentTypeDefinition("MyDocType2.2",
+          "My Type 8 Level 2", cmisType2);
+      typesList.add(cmisType22);
+      InMemoryDocumentTypeDefinition cmisType23 = new InMemoryDocumentTypeDefinition("MyDocType2.3",
+          "My Type 9 Level 2", cmisType2);
+      typesList.add(cmisType23);
+      InMemoryDocumentTypeDefinition cmisType24 = new InMemoryDocumentTypeDefinition("MyDocType2.4",
+          "My Type 10 Level 2", cmisType2);
+      typesList.add(cmisType24);
+      InMemoryDocumentTypeDefinition cmisType25 = new InMemoryDocumentTypeDefinition("MyDocType2.5",
+          "My Type 11 Level 2", cmisType2);
+      typesList.add(cmisType25);
+
+      InMemoryDocumentTypeDefinition cmisType26 = new InMemoryDocumentTypeDefinition("MyDocType2.6",
+          "My Type 12 Level 2", cmisType2);
+      typesList.add(cmisType26);
+      InMemoryDocumentTypeDefinition cmisType27 = new InMemoryDocumentTypeDefinition("MyDocType2.7",
+          "My Type 13 Level 2", cmisType2);
+      typesList.add(cmisType27);
+      InMemoryDocumentTypeDefinition cmisType28 = new InMemoryDocumentTypeDefinition("MyDocType2.8",
+          "My Type 14 Level 2", cmisType2);
+      typesList.add(cmisType28);
+      InMemoryDocumentTypeDefinition cmisType29 = new InMemoryDocumentTypeDefinition("MyDocType2.9",
+          "My Type 15 Level 2", cmisType2);
+      typesList.add(cmisType29);
+
+      // create a complex type with properties
+      InMemoryDocumentTypeDefinition cmisComplexType = new InMemoryDocumentTypeDefinition(COMPLEX_TYPE,
+          "Complex type with properties, Level 1", InMemoryDocumentTypeDefinition.getRootDocumentType());
+      
+      // create a boolean property definition
+      
+      Map<String, PropertyDefinition<?>> propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      
+      PropertyDefinition<Boolean> prop = PropertyCreationHelper.createBooleanDefinition("BooleanProp", "Sample Boolean Property");
+      propertyDefinitions.put(prop.getId(), prop);
+      
+      prop = PropertyCreationHelper.createBooleanMultiDefinition("BooleanPropMV", "Sample Boolean multi-value Property");
+      propertyDefinitions.put(prop.getId(), prop);
+
+      PropertyDateTimeDefinitionImpl prop2 = PropertyCreationHelper.createDateTimeDefinition("DateTimeProp", "Sample DateTime Property");
+      propertyDefinitions.put(prop2.getId(), prop2);
+      
+      prop2 = PropertyCreationHelper.createDateTimeMultiDefinition("DateTimePropMV", "Sample DateTime multi-value Property");
+      propertyDefinitions.put(prop2.getId(), prop2);
+
+      PropertyDecimalDefinitionImpl prop3 = PropertyCreationHelper.createDecimalDefinition("DecimalProp", "Sample Decimal Property");
+      propertyDefinitions.put(prop3.getId(), prop3);
+      
+      prop3 = PropertyCreationHelper.createDecimalDefinition("DecimalPropMV", "Sample Decimal multi-value Property");
+      propertyDefinitions.put(prop3.getId(), prop3);
+
+      PropertyHtmlDefinitionImpl prop4 = PropertyCreationHelper.createHtmlDefinition("HtmlProp", "Sample Html Property");
+      propertyDefinitions.put(prop4.getId(), prop4);
+      
+      prop4 = PropertyCreationHelper.createHtmlDefinition("HtmlPropMV", "Sample Html multi-value Property");
+      propertyDefinitions.put(prop4.getId(), prop4);
+
+      PropertyIdDefinitionImpl prop5 = PropertyCreationHelper.createIdDefinition("IdProp", "Sample Id Property");
+      propertyDefinitions.put(prop5.getId(), prop5);
+      
+      prop5 = PropertyCreationHelper.createIdDefinition("IdPropMV", "Sample Id Html multi-value Property");
+      propertyDefinitions.put(prop5.getId(), prop5);
+
+      PropertyIntegerDefinitionImpl prop6 = PropertyCreationHelper.createIntegerDefinition("IntProp", "Sample Int Property");
+      propertyDefinitions.put(prop6.getId(), prop6);
+      
+      prop6 = PropertyCreationHelper.createIntegerDefinition("IntPropMV", "Sample Int multi-value Property");
+      propertyDefinitions.put(prop6.getId(), prop6);
+
+      PropertyStringDefinitionImpl prop7 = PropertyCreationHelper.createStringDefinition("StringProp", "Sample String Property");
+      propertyDefinitions.put(prop7.getId(), prop7);
+      
+      PropertyUriDefinitionImpl prop8 = PropertyCreationHelper.createUriDefinition("UriProp", "Sample Uri Property");
+      propertyDefinitions.put(prop8.getId(), prop8);
+      
+      prop8 = PropertyCreationHelper.createUriDefinition("UriPropMV", "Sample Uri multi-value Property");
+      propertyDefinitions.put(prop8.getId(), prop8);
+
+      PropertyStringDefinitionImpl prop9 = PropertyCreationHelper.createStringDefinition("PickListProp", "Sample Pick List Property");
+      List<Choice<String>> choiceList = new ArrayList<Choice<String>>();
+      ChoiceImpl<String> elem = new ChoiceImpl<String>();
+      elem.setValue(Collections.singletonList("red"));
+      choiceList.add(elem);
+      elem = new ChoiceImpl<String>();
+      elem.setValue(Collections.singletonList("green"));
+      choiceList.add(elem);
+      elem = new ChoiceImpl<String>();
+      elem.setValue(Collections.singletonList("blue"));
+      choiceList.add(elem);
+      elem = new ChoiceImpl<String>();
+      elem.setValue(Collections.singletonList("black"));
+      choiceList.add(elem);   
+      prop9.setChoices(choiceList);
+      prop9.setDefaultValue(Collections.singletonList("blue"));
+      
+      /* try short form: * /
+      PropertyCreationHelper.addElemToPicklist(prop9, "red");    
+      PropertyCreationHelper.addElemToPicklist(prop9, "green");    
+      PropertyCreationHelper.addElemToPicklist(prop9, "blue");    
+      PropertyCreationHelper.addElemToPicklist(prop9, "black");
+      PropertyCreationHelper.setDefaultValue(prop9, "blue");    
+      /* */
+      
+      cmisComplexType.addCustomPropertyDefinitions(propertyDefinitions);    
+      
+      // add type to types collection
+      typesList.add(cmisComplexType);
+
+      // create a type hierarchy with inherited properties
+      InMemoryDocumentTypeDefinition cmisDocTypeTopLevel = new InMemoryDocumentTypeDefinition(TOPLEVEL_TYPE,
+          "Document type with properties, Level 1", InMemoryDocumentTypeDefinition.getRootDocumentType());
+
+      InMemoryDocumentTypeDefinition cmisDocTypeLevel1 = new InMemoryDocumentTypeDefinition(LEVEL1_TYPE,
+          "Document type with inherited properties, Level 2", cmisDocTypeTopLevel);
+      
+      InMemoryDocumentTypeDefinition cmisDocTypeLevel2 = new InMemoryDocumentTypeDefinition(LEVEL2_TYPE,
+          "Document type with inherited properties, Level 3", cmisDocTypeLevel1);
+      
+      propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      PropertyStringDefinitionImpl propTop = PropertyCreationHelper.createStringDefinition("StringPropTopLevel", "Sample String Property");
+      propertyDefinitions.put(propTop.getId(), propTop);
+      cmisDocTypeTopLevel.addCustomPropertyDefinitions(propertyDefinitions);    
+      
+      propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      PropertyStringDefinitionImpl propLevel1 = PropertyCreationHelper.createStringDefinition("StringPropLevel1", "String Property Level 1");
+      propertyDefinitions.put(propLevel1.getId(), propLevel1);
+      cmisDocTypeLevel1.addCustomPropertyDefinitions(propertyDefinitions);    
+
+      propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
+      PropertyStringDefinitionImpl propLevel2 = PropertyCreationHelper.createStringDefinition("StringPropLevel2", "String Property Level 2");
+      propertyDefinitions.put(propLevel2.getId(), propLevel2);
+      cmisDocTypeLevel2.addCustomPropertyDefinitions(propertyDefinitions);    
+
+      // add type to types collection
+      typesList.add(cmisDocTypeTopLevel);
+      typesList.add(cmisDocTypeLevel1);
+      typesList.add(cmisDocTypeLevel2);
+      
+      return typesList;
+    }
+    
+    public static List<TypeDefinition> getTypesList() {
+      return singletonTypes;
+    }
+    
+    static public TypeDefinition getTypeById(String typeId) {
+      for (TypeDefinition typeDef : singletonTypes)
+        if (typeDef.getId().equals(typeId))
+          return typeDef;
+      return null;
+    }
+    
+  }
+  
+}

Propchange: incubator/chemistry/trunk/opencmis/opencmis-server/opencmis-server-inmemory/src/test/java/org/apache/opencmis/inmemory/RepositoryServiceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native