added CmisObject implementations

git-svn-id: https://svn.apache.org/repos/asf/incubator/chemistry/dotcmis/trunk@1067465 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/DotCMIS/binding/atompub/atompub.cs b/DotCMIS/binding/atompub/atompub.cs
index 4db125c..f7c9fed 100644
--- a/DotCMIS/binding/atompub/atompub.cs
+++ b/DotCMIS/binding/atompub/atompub.cs
@@ -113,7 +113,7 @@
             // nothing to do

         }

 

-        public void Close()

+        public void Dispose()

         {

             // nothing to do

         }

@@ -2118,7 +2118,7 @@
         }

 

         public void CheckIn(string repositoryId, ref string objectId, bool? major, IProperties properties,

-            IContentStream contentStream, string checkinComment, List<string> policies, IAcl addAces, IAcl removeAces,

+            IContentStream contentStream, string checkinComment, IList<string> policies, IAcl addAces, IAcl removeAces,

             IExtensionsData extension)

         {

             // we need an object id

diff --git a/DotCMIS/binding/binding-impl.cs b/DotCMIS/binding/binding-impl.cs
index 450034a..ec3fa86 100644
--- a/DotCMIS/binding/binding-impl.cs
+++ b/DotCMIS/binding/binding-impl.cs
@@ -35,7 +35,6 @@
     internal class CmisBinding : ICmisBinding

     {

         private BindingSession session;

-        private BindingsObjectFactory objectFactory;

         private BindingRepositoryService repositoryServiceWrapper;

 

         public CmisBinding(IDictionary<string, string> sessionParameters)

@@ -57,9 +56,6 @@
                 session.PutValue(key, sessionParameters[key]);

             }

 

-            // set up object factory

-            objectFactory = new BindingsObjectFactory();

-

             // set up authentication provider

             string authenticationProviderClass;

             if (sessionParameters.TryGetValue(SessionParameter.AuthenticationProviderClass, out authenticationProviderClass))

@@ -149,11 +145,6 @@
             return spi.GetPolicyService();

         }

 

-        public IBindingsObjectFactory GetObjectFactory()

-        {

-            return objectFactory;

-        }

-

         public void ClearAllCaches()

         {

             CheckSession();

@@ -200,14 +191,14 @@
             }

         }

 

-        public void Close()

+        public void Dispose()

         {

             CheckSession();

 

             session.Lock();

             try

             {

-                GetSpi().Close();

+                GetSpi().Dispose();

             }

             finally

             {

@@ -564,41 +555,21 @@
     }

 

     /// <summary>

-    /// Object factory implementation.

-    /// </summary>

-    internal class BindingsObjectFactory : IBindingsObjectFactory

-    {

-    }

-

-    /// <summary>

     /// SPI interface.

     /// </summary>

-    internal interface ICmisSpi

+    internal interface ICmisSpi : IDisposable

     {

         void initialize(BindingSession session);

-

         IRepositoryService GetRepositoryService();

-

         INavigationService GetNavigationService();

-

         IObjectService GetObjectService();

-

         IVersioningService GetVersioningService();

-

         IRelationshipService GetRelationshipService();

-

         IDiscoveryService GetDiscoveryService();

-

         IMultiFilingService GetMultiFilingService();

-

         IAclService GetAclService();

-

         IPolicyService GetPolicyService();

-

         void ClearAllCaches();

-

         void ClearRepositoryCache(string repositoryId);

-

-        void Close();

     }

 }

diff --git a/DotCMIS/binding/binding-intf.cs b/DotCMIS/binding/binding-intf.cs
index 9b38241..ca3ba34 100644
--- a/DotCMIS/binding/binding-intf.cs
+++ b/DotCMIS/binding/binding-intf.cs
@@ -18,16 +18,14 @@
  */

 using System;

 using System.Collections.Generic;

-using System.Linq;

-using System.Text;

-using DotCMIS.Binding.Services;

-using DotCMIS.Binding.Impl;

-using DotCMIS.CMISWebServicesReference;

 using System.Net;

+using DotCMIS.Binding.Impl;

+using DotCMIS.Binding.Services;

+using DotCMIS.CMISWebServicesReference;

 

 namespace DotCMIS.Binding

 {

-    public interface ICmisBinding

+    public interface ICmisBinding : IDisposable

     {

         IRepositoryService GetRepositoryService();

         INavigationService GetNavigationService();

@@ -38,10 +36,8 @@
         IMultiFilingService GetMultiFilingService();

         IAclService GetAclService();

         IPolicyService GetPolicyService();

-        IBindingsObjectFactory GetObjectFactory();

         void ClearAllCaches();

         void ClearRepositoryCache(string repositoryId);

-        void Close();

     }

 

     public interface IBindingSession

@@ -131,11 +127,6 @@
         }

     }

 

-

-    public interface IBindingsObjectFactory

-    {

-    }

-

     public class CmisBindingFactory

     {

         // Default CMIS AtomPub binding SPI implementation

diff --git a/DotCMIS/binding/converter.cs b/DotCMIS/binding/converter.cs
index c261cc8..2bdda14 100644
--- a/DotCMIS/binding/converter.cs
+++ b/DotCMIS/binding/converter.cs
@@ -424,9 +424,9 @@
             result.DisplayName = propDef.displayName;

             result.QueryName = propDef.queryName;

             result.Description = propDef.description;

-            result.PropertyType = (PropertyType?)CmisValue.SerializerToCmisEnum(propDef.propertyType);

-            result.Cardinality = (Cardinality?)CmisValue.SerializerToCmisEnum(propDef.cardinality);

-            result.Updatability = (Updatability?)CmisValue.SerializerToCmisEnum(propDef.updatability);

+            result.PropertyType = (PropertyType)CmisValue.SerializerToCmisEnum(propDef.propertyType);

+            result.Cardinality = (Cardinality)CmisValue.SerializerToCmisEnum(propDef.cardinality);

+            result.Updatability = (Updatability)CmisValue.SerializerToCmisEnum(propDef.updatability);

             result.IsInherited = (propDef.inheritedSpecified ? (bool?)propDef.inherited : null);

             result.IsRequired = propDef.required;

             result.IsQueryable = propDef.queryable;

@@ -702,7 +702,7 @@
         {

             if (property == null) { return null; }

 

-            PropertyData result = null;

+            AbstractPropertyData result = null;

             if (property is cmisPropertyString)

             {

                 result = new PropertyString();

diff --git a/DotCMIS/binding/services.cs b/DotCMIS/binding/services.cs
index f7b1844..ff0446a 100644
--- a/DotCMIS/binding/services.cs
+++ b/DotCMIS/binding/services.cs
@@ -123,7 +123,7 @@
         void CancelCheckOut(string repositoryId, string objectId, IExtensionsData extension);

 

         void CheckIn(string repositoryId, ref string objectId, bool? major, IProperties properties,

-            IContentStream contentStream, string checkinComment, List<string> policies, IAcl addAces, IAcl removeAces,

+            IContentStream contentStream, string checkinComment, IList<string> policies, IAcl addAces, IAcl removeAces,

             IExtensionsData extension);

 

         IObjectData GetObjectOfLatestVersion(string repositoryId, string objectId, string versionSeriesId, bool major,

diff --git a/DotCMIS/binding/webservices/webservices.cs b/DotCMIS/binding/webservices/webservices.cs
index 3b8efed..d27d297 100644
--- a/DotCMIS/binding/webservices/webservices.cs
+++ b/DotCMIS/binding/webservices/webservices.cs
@@ -114,7 +114,7 @@
             // nothing to do

         }

 

-        public void Close()

+        public void Dispose()

         {

             // nothing to do

         }

@@ -1110,7 +1110,7 @@
         }

 

         public void CheckIn(string repositoryId, ref string objectId, bool? major, IProperties properties,

-            IContentStream contentStream, string checkinComment, List<string> policies, IAcl addAces, IAcl removeAces,

+            IContentStream contentStream, string checkinComment, IList<string> policies, IAcl addAces, IAcl removeAces,

             IExtensionsData extension)

         {

             VersioningServicePortClient port = Provider.GetVersioningService();

diff --git a/DotCMIS/client/client-impl.cs b/DotCMIS/client/client-impl.cs
index 603b912..9319ab9 100644
--- a/DotCMIS/client/client-impl.cs
+++ b/DotCMIS/client/client-impl.cs
@@ -243,15 +243,15 @@
                     cacheType = typeof(NoCache);

                 }

 

-                object cacheObject = Activator.CreateInstance(cacheType);

-                if (!(cacheObject is ICache))

+                ICache cacheObject = Activator.CreateInstance(cacheType) as ICache;

+                if (cacheObject == null)

                 {

                     throw new Exception("Class does not implement ICache!");

                 }

 

-                ((ICache)cacheObject).Initialize(this, parameters);

+                cacheObject.Initialize(this, parameters);

 

-                return (ICache)cacheObject;

+                return cacheObject;

             }

             catch (Exception e)

             {

@@ -275,15 +275,15 @@
                     ofType = typeof(ObjectFactory);

                 }

 

-                object ofObject = Activator.CreateInstance(ofType);

-                if (!(ofObject is IObjectFactory))

+                IObjectFactory ofObject = Activator.CreateInstance(ofType) as IObjectFactory;

+                if (ofObject == null)

                 {

                     throw new Exception("Class does not implement IObjectFactory!");

                 }

 

-                ((IObjectFactory)ofObject).Initialize(this, parameters);

+                ofObject.Initialize(this, parameters);

 

-                return (IObjectFactory)ofObject;

+                return ofObject;

             }

             catch (Exception e)

             {

@@ -335,12 +335,12 @@
 

         public IItemEnumerable<IObjectType> GetTypeChildren(string typeId, bool includePropertyDefinitions)

         {

-            IRepositoryService repositoryService = Binding.GetRepositoryService();

+            IRepositoryService service = Binding.GetRepositoryService();

 

             PageFetcher<IObjectType>.FetchPage fetchPageDelegate = delegate(long maxNumItems, long skipCount)

             {

                 // fetch the data

-                ITypeDefinitionList tdl = repositoryService.GetTypeChildren(RepositoryId, typeId, includePropertyDefinitions, maxNumItems, skipCount, null);

+                ITypeDefinitionList tdl = service.GetTypeChildren(RepositoryId, typeId, includePropertyDefinitions, maxNumItems, skipCount, null);

 

                 // convert type definitions

                 IList<IObjectType> page = new List<IObjectType>(tdl.List.Count);

@@ -388,13 +388,13 @@
 

         public IFolder GetRootFolder(IOperationContext context)

         {

-            ICmisObject rootFolder = GetObject(CreateObjectId(RepositoryInfo.RootFolderId), context);

-            if (!(rootFolder is IFolder))

+            IFolder rootFolder = GetObject(CreateObjectId(RepositoryInfo.RootFolderId), context) as IFolder;

+            if (rootFolder == null)

             {

                 throw new CmisRuntimeException("Root folder object is not a folder!");

             }

 

-            return (IFolder)rootFolder;

+            return rootFolder;

         }

 

         public IItemEnumerable<IDocument> GetCheckedOutDocs()

diff --git a/DotCMIS/client/client-intf.cs b/DotCMIS/client/client-intf.cs
index f551d5b..dbe44ce 100644
--- a/DotCMIS/client/client-intf.cs
+++ b/DotCMIS/client/client-intf.cs
@@ -120,7 +120,7 @@
         // ACL and ACE

         IAcl ConvertAces(IList<IAce> aces);

         IAcl CreateAcl(IList<IAce> aces);

-        IAce CreateAce(string principal, List<string> permissions);

+        IAce CreateAce(string principal, IList<string> permissions);

 

         // policies

         IList<string> ConvertPolicies(IList<IPolicy> policies);

@@ -130,14 +130,13 @@
 

         // content stream

         IContentStream CreateContentStream(string filename, long length, string mimetype, Stream stream);

-        IContentStream ConvertContentStream(IContentStream contentStream);

 

         // types

         IObjectType ConvertTypeDefinition(ITypeDefinition typeDefinition);

         IObjectType GetTypeFromObjectData(IObjectData objectData);

 

         // properties

-        IProperty CreateProperty(IPropertyDefinition type, IList<object> values);

+        IProperty CreateProperty<T>(IPropertyDefinition type, IList<T> values);

         IDictionary<string, IProperty> ConvertProperties(IObjectType objectType, IProperties properties);

         IProperties ConvertProperties(IDictionary<string, object> properties, IObjectType type, HashSet<Updatability> updatabilityFilter);

         IList<IPropertyData> ConvertQueryProperties(IProperties properties);

@@ -223,12 +222,18 @@
         IContentStream GetContentStream();

     }

 

-    public interface IProperty : IPropertyData

+    public interface IProperty

     {

+        string Id { get; }

+        string LocalName { get; }

+        string DisplayName { get; }

+        string QueryName { get; }

         bool IsMultiValued { get; }

-        PropertyType PropertyType { get; }

-        PropertyDefinition PropertyDefinition { get; }

+        PropertyType? PropertyType { get; }

+        IPropertyDefinition PropertyDefinition { get; }

         object Value { get; }

+        IList<object> Values { get; }

+        object FirstValue { get; }

         string ValueAsString { get; }

         string ValuesAsString { get; }

     }

@@ -296,8 +301,8 @@
         IFileableCmisObject Move(IObjectId sourceFolderId, IObjectId targetFolderId);

 

         // navigation service

-        IList<IFolder> GetParents();

-        IList<string> GetPaths();

+        IList<IFolder> Parents { get; }

+        IList<string> Paths { get; }

 

         // multifiling service

         void AddToFolder(IObjectId folderId, bool allVersions);

@@ -312,11 +317,11 @@
         bool? IsLatestMajorVersion { get; }

         string VersionLabel { get; }

         string VersionSeriesId { get; }

-        bool? VersionSeriesCheckedOut { get; }

+        bool? IsVersionSeriesCheckedOut { get; }

         string VersionSeriesCheckedOutBy { get; }

         string VersionSeriesCheckedOutId { get; }

         string CheckinComment { get; }

-        long ContentStreamLength { get; }

+        long? ContentStreamLength { get; }

         string ContentStreamMimeType { get; }

         string ContentStreamFileName { get; }

         string ContentStreamId { get; }

@@ -335,7 +340,7 @@
         void CancelCheckOut();

         IObjectId CheckIn(bool major, IDictionary<string, object> properties, IContentStream contentStream, string checkinComment,

                 IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces);

-        IObjectId checkIn(bool major, IDictionary<string, object> properties, IContentStream contentStream, string checkinComment);

+        IObjectId CheckIn(bool major, IDictionary<string, object> properties, IContentStream contentStream, string checkinComment);

         IDocument GetObjectOfLatestVersion(bool major);

         IDocument GetObjectOfLatestVersion(bool major, IOperationContext context);

         IList<IDocument> GetAllVersions();

@@ -361,7 +366,7 @@
         IFolder CreateFolder(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces,

                 IOperationContext context);

         IFolder CreateFolder(IDictionary<string, object> properties);

-        IPolicy CreatePolicy(IDictionary<string, object> properties, List<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces,

+        IPolicy CreatePolicy(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces,

                 IOperationContext context);

         IPolicy CreatePolicy(IDictionary<string, object> properties);

         IList<string> DeleteTree(bool allversions, UnfileObject? unfile, bool continueOnFailure);

diff --git a/DotCMIS/client/client-objectfactory.cs b/DotCMIS/client/client-objectfactory.cs
index 43d6d63..1de2d67 100644
--- a/DotCMIS/client/client-objectfactory.cs
+++ b/DotCMIS/client/client-objectfactory.cs
@@ -24,6 +24,7 @@
 using System.IO;

 using DotCMIS.Enums;

 using DotCMIS.Exceptions;

+using System.Collections;

 

 namespace DotCMIS.Client

 {

@@ -37,55 +38,469 @@
         }

 

         // ACL and ACE

-        public IAcl ConvertAces(IList<IAce> aces) { return null; }

-        public IAcl CreateAcl(IList<IAce> aces) { return null; }

-        public IAce CreateAce(string principal, List<string> permissions) { return null; }

+        public IAcl ConvertAces(IList<IAce> aces)

+        {

+            if (aces == null) { return null; }

+

+            Acl result = new Acl();

+            result.Aces = new List<IAce>();

+

+            foreach (IAce ace in aces)

+            {

+                result.Aces.Add(ace);

+            }

+

+            return result;

+        }

+

+        public IAcl CreateAcl(IList<IAce> aces)

+        {

+            Acl acl = new Acl();

+            acl.Aces = aces;

+

+            return acl;

+        }

+

+        public IAce CreateAce(string principal, IList<string> permissions)

+        {

+            Ace ace = new Ace();

+            Principal acePrincipal = new Principal();

+            acePrincipal.Id = principal;

+            ace.Principal = acePrincipal;

+            ace.Permissions = permissions;

+

+            return ace;

+        }

 

         // policies

-        public IList<string> ConvertPolicies(IList<IPolicy> policies) { return null; }

+        public IList<string> ConvertPolicies(IList<IPolicy> policies)

+        {

+            if (policies == null) { return null; }

+

+            IList<string> result = new List<string>();

+            foreach (IPolicy policy in policies)

+            {

+                if (policy != null && policy.Id != null)

+                {

+                    result.Add(policy.Id);

+                }

+            }

+

+            return result;

+        }

 

         // renditions

-        public IRendition ConvertRendition(string objectId, IRenditionData rendition) { return null; }

+        public IRendition ConvertRendition(string objectId, IRenditionData rendition)

+        {

+            if (rendition == null)

+            {

+                throw new ArgumentException("rendition");

+            }

+

+            return new Rendition(this.session, objectId, rendition.StreamId, rendition.MimeType, rendition.Length, rendition.Kind,

+                      rendition.Title, rendition.Height, rendition.Height, rendition.RenditionDocumentId);

+        }

 

         // content stream

-        public IContentStream CreateContentStream(string filename, long length, string mimetype, Stream stream) { return null; }

-        public IContentStream ConvertContentStream(IContentStream contentStream) { return null; }

+        public IContentStream CreateContentStream(string filename, long length, string mimetype, Stream stream)

+        {

+            ContentStream result = new ContentStream();

+            result.FileName = filename;

+            result.Length = length;

+            result.MimeType = mimetype;

+            result.Stream = stream;

+

+            return result;

+        }

 

         // types

         public IObjectType ConvertTypeDefinition(ITypeDefinition typeDefinition)

         {

-            if (typeDefinition is IDocumentTypeDefinition)

+            switch (typeDefinition.BaseTypeId)

             {

-                return new DocumentType(session, (IDocumentTypeDefinition)typeDefinition);

-            }

-            else if (typeDefinition is IFolderTypeDefinition)

-            {

-                return new FolderType(session, (IFolderTypeDefinition)typeDefinition);

-            }

-            else if (typeDefinition is IRelationshipTypeDefinition)

-            {

-                return new RelationshipType(session, (IRelationshipTypeDefinition)typeDefinition);

-            }

-            else if (typeDefinition is IPolicyTypeDefinition)

-            {

-                return new PolicyType(session, (IPolicyTypeDefinition)typeDefinition);

-            }

-            else

-            {

-                throw new CmisRuntimeException("Unknown base type!");

+                case BaseTypeId.CmisDocument:

+                    return new DocumentType(session, (IDocumentTypeDefinition)typeDefinition);

+                case BaseTypeId.CmisFolder:

+                    return new FolderType(session, (IFolderTypeDefinition)typeDefinition);

+                case BaseTypeId.CmisRelationship:

+                    return new RelationshipType(session, (IRelationshipTypeDefinition)typeDefinition);

+                case BaseTypeId.CmisPolicy:

+                    return new PolicyType(session, (IPolicyTypeDefinition)typeDefinition);

+                default:

+                    throw new CmisRuntimeException("Unknown base type!");

             }

         }

 

-        public IObjectType GetTypeFromObjectData(IObjectData objectData) { return null; }

+        public IObjectType GetTypeFromObjectData(IObjectData objectData)

+        {

+            if (objectData == null || objectData.Properties == null)

+            {

+                return null;

+            }

+

+            IPropertyId typeProperty = objectData.Properties[PropertyIds.ObjectTypeId] as IPropertyId;

+            if (typeProperty == null)

+            {

+                return null;

+            }

+

+            return session.GetTypeDefinition(typeProperty.FirstValue);

+        }

 

         // properties

-        public IProperty CreateProperty(IPropertyDefinition type, IList<object> values) { return null; }

-        public IDictionary<string, IProperty> ConvertProperties(IObjectType objectType, IProperties properties) { return null; }

-        public IProperties ConvertProperties(IDictionary<string, object> properties, IObjectType type, HashSet<Updatability> updatabilityFilter) { return null; }

-        public IList<IPropertyData> ConvertQueryProperties(IProperties properties) { return null; }

+        public IProperty CreateProperty<T>(IPropertyDefinition type, IList<T> values)

+        {

+            return new Property(type, (IList<object>)values);

+        }

+

+        protected IProperty ConvertProperty(IObjectType objectType, IPropertyData pd)

+        {

+            IPropertyDefinition definition = objectType[pd.Id];

+            if (definition == null)

+            {

+                // property without definition

+                throw new CmisRuntimeException("Property '" + pd.Id + "' doesn't exist!");

+            }

+

+            switch (definition.PropertyType)

+            {

+                case PropertyType.String:

+                    return CreateProperty(definition, ((IPropertyString)pd).Values);

+                case PropertyType.Id:

+                    return CreateProperty(definition, ((IPropertyId)pd).Values);

+                case PropertyType.Integer:

+                    return CreateProperty(definition, ((IPropertyInteger)pd).Values);

+                case PropertyType.Boolean:

+                    return CreateProperty(definition, ((IPropertyBoolean)pd).Values);

+                case PropertyType.Decimal:

+                    return CreateProperty(definition, ((IPropertyDecimal)pd).Values);

+                case PropertyType.Uri:

+                    return CreateProperty(definition, ((IPropertyUri)pd).Values);

+                case PropertyType.Html:

+                    return CreateProperty(definition, ((IPropertyHtml)pd).Values);

+                default:

+                    return null;

+            }

+        }

+

+        public IDictionary<string, IProperty> ConvertProperties(IObjectType objectType, IProperties properties)

+        {

+            if (objectType == null)

+            {

+                throw new ArgumentNullException("objectType");

+            }

+

+            if (objectType.PropertyDefintions == null)

+            {

+                throw new ArgumentException("Object type has no property defintions!");

+            }

+

+            if (properties == null || properties.PropertyList == null)

+            {

+                throw new ArgumentException("Properties must be set!");

+            }

+

+            // iterate through properties and convert them

+            IDictionary<string, IProperty> result = new Dictionary<string, IProperty>();

+            foreach (IPropertyData property in properties.PropertyList)

+            {

+                // find property definition

+                IProperty apiProperty = ConvertProperty(objectType, property);

+                result[property.Id] = apiProperty;

+            }

+

+            return result;

+        }

+

+        public IProperties ConvertProperties(IDictionary<string, object> properties, IObjectType type, HashSet<Updatability> updatabilityFilter)

+        {

+            // check input

+            if (properties == null)

+            {

+                return null;

+            }

+

+            // get the type

+            if (type == null)

+            {

+                string typeId = properties[PropertyIds.ObjectTypeId] as string;

+                if (typeId == null)

+                {

+                    throw new ArgumentException("Type or type property must be set!");

+                }

+

+                type = session.GetTypeDefinition(typeId);

+            }

+

+            Properties result = new Properties();

+

+            // the big loop

+            foreach (KeyValuePair<string, object> property in properties)

+            {

+                string id = property.Key;

+                object value = property.Value;

+

+                if (value is IProperty)

+                {

+                    IProperty p = (IProperty)value;

+                    if (id != p.Id)

+                    {

+                        throw new ArgumentException("Property id mismatch: '" + id + "' != '" + p.Id + "'!");

+                    }

+                    value = (p.PropertyDefinition.Cardinality == Cardinality.Single ? p.FirstValue : p.Values);

+                }

+

+                // get the property definition

+                IPropertyDefinition definition = type[id];

+                if (definition == null)

+                {

+                    throw new ArgumentException("Property +'" + id + "' is not valid for this type!");

+                }

+

+                // check updatability

+                if (updatabilityFilter != null)

+                {

+                    if (!updatabilityFilter.Contains(definition.Updatability))

+                    {

+                        continue;

+                    }

+                }

+

+                // single and multi value check

+                IList<dynamic> values;

+                if (value == null)

+                {

+                    values = null;

+                }

+                else if (value is IList<dynamic>)

+                {

+                    if (definition.Cardinality != Cardinality.Multi)

+                    {

+                        throw new ArgumentException("Property '" + id + "' is not a multi value property!");

+                    }

+                    values = (IList<dynamic>)value;

+

+                    // check if the list is homogeneous and does not contain null values

+                    Type valueType = null;

+                    foreach (object o in values)

+                    {

+                        if (o == null)

+                        {

+                            throw new ArgumentException("Property '" + id + "' contains null values!");

+                        }

+                        if (valueType == null)

+                        {

+                            valueType = o.GetType();

+                        }

+                        else

+                        {

+                            if (!valueType.IsInstanceOfType(o))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is inhomogeneous!");

+                            }

+                        }

+                    }

+                }

+                else

+                {

+                    if (definition.Cardinality != Cardinality.Single)

+                    {

+                        throw new ArgumentException("Property '" + id + "' is not a single value property!");

+                    }

+                    values = new List<dynamic>();

+                    values.Add(value);

+                }

+

+                // assemble property

+                object firstValue = (values == null || values.Count == 0 ? null : values[0]);

+

+                switch (definition.PropertyType)

+                {

+                    case PropertyType.String:

+                        PropertyString stringProperty = new PropertyString();

+                        stringProperty.Id = id;

+                        stringProperty.Values = new List<string>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is string))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a String property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                stringProperty.Values.Add((string)o);

+                            }

+                        }

+                        result.AddProperty(stringProperty);

+                        break;

+                    case PropertyType.Id:

+                        PropertyId idProperty = new PropertyId();

+                        idProperty.Id = id;

+                        idProperty.Values = new List<string>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is string))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a Id property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                idProperty.Values.Add((string)o);

+                            }

+                        }

+                        result.AddProperty(idProperty);

+                        break;

+                    case PropertyType.Integer:

+                        PropertyInteger intProperty = new PropertyInteger();

+                        intProperty.Id = id;

+                        intProperty.Values = new List<long>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is sbyte || firstValue is byte || firstValue is short || firstValue is ushort || firstValue is int || firstValue is uint || firstValue is long))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is an Integer property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                intProperty.Values.Add((long)o);

+                            }

+                        }

+                        result.AddProperty(intProperty);

+                        break;

+                    case PropertyType.Boolean:

+                        PropertyBoolean booleanProperty = new PropertyBoolean();

+                        booleanProperty.Id = id;

+                        booleanProperty.Values = new List<bool>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is bool))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a boolean property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                booleanProperty.Values.Add((bool)o);

+                            }

+                        }

+                        result.AddProperty(booleanProperty);

+                        break;

+                    case PropertyType.DateTime:

+                        PropertyDateTime dateTimeProperty = new PropertyDateTime();

+                        dateTimeProperty.Id = id;

+                        dateTimeProperty.Values = new List<DateTime>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is DateTime))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a Boolean property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                dateTimeProperty.Values.Add((DateTime)o);

+                            }

+                        }

+                        result.AddProperty(dateTimeProperty);

+                        break;

+                    case PropertyType.Decimal:

+                        PropertyDecimal decimalProperty = new PropertyDecimal();

+                        decimalProperty.Id = id;

+                        decimalProperty.Values = new List<decimal>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is DateTime))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a Decimal property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                decimalProperty.Values.Add((decimal)o);

+                            }

+                        }

+                        result.AddProperty(decimalProperty);

+                        break;

+                    case PropertyType.Uri:

+                        PropertyUri uriProperty = new PropertyUri();

+                        uriProperty.Id = id;

+                        uriProperty.Values = new List<string>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is string))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a URI property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                uriProperty.Values.Add((string)o);

+                            }

+                        }

+                        result.AddProperty(uriProperty);

+                        break;

+                    case PropertyType.Html:

+                        PropertyHtml htmlProperty = new PropertyHtml();

+                        htmlProperty.Id = id;

+                        htmlProperty.Values = new List<string>(values.Count);

+                        if (values != null)

+                        {

+                            if (firstValue != null && !(firstValue is string))

+                            {

+                                throw new ArgumentException("Property '" + id + "' is a HTML property!");

+                            }

+

+                            foreach (object o in values)

+                            {

+                                htmlProperty.Values.Add((string)o);

+                            }

+                        }

+                        result.AddProperty(htmlProperty);

+                        break;

+                }

+            }

+

+            return result;

+        }

+

+        public IList<IPropertyData> ConvertQueryProperties(IProperties properties)

+        {

+            if ((properties == null) || (properties.PropertyList == null))

+            {

+                throw new ArgumentException("Properties must be set!");

+            }

+

+            return new List<IPropertyData>(properties.PropertyList);

+        }

 

         // objects

-        public ICmisObject ConvertObject(IObjectData objectData, IOperationContext context) { return null; }

+        public ICmisObject ConvertObject(IObjectData objectData, IOperationContext context)

+        {

+            if (objectData == null)

+            {

+                throw new ArgumentNullException("objectData");

+            }

+

+            IObjectType type = GetTypeFromObjectData(objectData);

+

+            switch (objectData.BaseTypeId)

+            {

+                case BaseTypeId.CmisDocument:

+                    return new Document(session, type, objectData, context);

+                case BaseTypeId.CmisFolder:

+                    return new Folder(session, type, objectData, context);

+                case BaseTypeId.CmisPolicy:

+                    return new Policy(session, type, objectData, context);

+                case BaseTypeId.CmisRelationship:

+                    return new Relationship(session, type, objectData, context);

+                default:

+                    throw new CmisRuntimeException("Unsupported type: " + objectData.BaseTypeId);

+            }

+        }

+

         public IQueryResult ConvertQueryResult(IObjectData objectData) { return null; }

         public IChangeEvent ConvertChangeEvent(IObjectData objectData) { return null; }

         public IChangeEvents ConvertChangeEvents(String changeLogToken, IObjectList objectList) { return null; }

diff --git a/DotCMIS/client/client-objects.cs b/DotCMIS/client/client-objects.cs
index c77d8bb..cc75cc9 100644
--- a/DotCMIS/client/client-objects.cs
+++ b/DotCMIS/client/client-objects.cs
@@ -27,10 +27,14 @@
 using DotCMIS.Data.Extensions;

 using DotCMIS.Enums;

 using DotCMIS.Exceptions;

+using DotCMIS.Binding.Services;

 

 namespace DotCMIS.Client

 {

-    internal abstract class AbstractCmisObject : ICmisObject

+    /// <summary>

+    /// CMIS object base class.

+    /// </summary>

+    public abstract class AbstractCmisObject : ICmisObject

     {

         protected ISession Session { get; private set; }

         protected string RepositoryId { get { return Session.RepositoryInfo.Id; } }

@@ -80,7 +84,7 @@
 

         private object objectLock = new object();

 

-        protected void initialize(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context)

+        protected void Initialize(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context)

         {

             if (session == null)

             {

@@ -104,7 +108,6 @@
             this.CreationContext = new OperationContext(context);

             this.RefreshTimestamp = DateTime.UtcNow;

 

-

             IObjectFactory of = Session.ObjectFactory;

 

             if (objectData != null)

@@ -146,10 +149,10 @@
                     policies = new List<IPolicy>();

                     foreach (string pid in objectData.PolicyIds.PolicyIds)

                     {

-                        ICmisObject policy = Session.GetObject(Session.CreateObjectId(pid));

-                        if (policy is IPolicy)

+                        IPolicy policy = Session.GetObject(Session.CreateObjectId(pid)) as IPolicy;

+                        if (policy != null)

                         {

-                            policies.Add((IPolicy)policy);

+                            policies.Add(policy);

                         }

                     }

                     extensions[ExtensionLevel.Policies] = objectData.PolicyIds.Extensions;

@@ -161,10 +164,10 @@
                     relationships = new List<IRelationship>();

                     foreach (IObjectData rod in objectData.Relationships)

                     {

-                        ICmisObject relationship = of.ConvertObject(rod, CreationContext);

-                        if (relationship is IRelationship)

+                        IRelationship relationship = of.ConvertObject(rod, CreationContext) as IRelationship;

+                        if (relationship != null)

                         {

-                            relationships.Add((IRelationship)relationship);

+                            relationships.Add(relationship);

                         }

                     }

                 }

@@ -274,7 +277,7 @@
 

         // --- properties ---

 

-        public IObjectType BaseType { get { return Session.GetTypeDefinition(BaseTypeId.GetCmisValue()); } }

+        public IObjectType BaseType { get { return Session.GetTypeDefinition(GetPropertyValue(PropertyIds.BaseTypeId) as string); } }

 

         public BaseTypeId BaseTypeId

         {

@@ -521,7 +524,7 @@
                     oc.IncludeRelationships, oc.RenditionFilterString, oc.IncludePolicies, oc.IncludeAcls, null);

 

                 // reset this object

-                initialize(Session, ObjectType, objectData, CreationContext);

+                Initialize(Session, ObjectType, objectData, CreationContext);

             }

             finally

             {

@@ -555,4 +558,1106 @@
             Monitor.Exit(objectLock);

         }

     }

-}

+

+    /// <summary>

+    /// Fileable object base class.

+    /// </summary>

+    public abstract class AbstractFileableCmisObject : AbstractCmisObject, IFileableCmisObject

+    {

+        public IFileableCmisObject Move(IObjectId sourceFolderId, IObjectId targetFolderId)

+        {

+            string objectId = ObjectId;

+

+            if (sourceFolderId == null || sourceFolderId.Id == null)

+            {

+                throw new ArgumentException("Source folder id must be set!");

+            }

+

+            if (targetFolderId == null || targetFolderId.Id == null)

+            {

+                throw new ArgumentException("Target folder id must be set!");

+            }

+

+            Binding.GetObjectService().MoveObject(RepositoryId, ref objectId, targetFolderId.Id, sourceFolderId.Id, null);

+

+            if (objectId == null)

+            {

+                return null;

+            }

+

+            IFileableCmisObject movedObject = Session.GetObject(Session.CreateObjectId(objectId)) as IFileableCmisObject;

+            if (movedObject == null)

+            {

+                throw new CmisRuntimeException("Moved object is invalid!");

+            }

+

+            return movedObject;

+        }

+

+        public virtual IList<IFolder> Parents

+        {

+            get

+            {

+                // get object ids of the parent folders

+                IList<IObjectParentData> providerParents = Binding.GetNavigationService().GetObjectParents(

+                        RepositoryId, ObjectId, GetPropertyQueryName(PropertyIds.ObjectId), false,

+                        IncludeRelationshipsFlag.None, null, false, null);

+

+                IList<IFolder> parents = new List<IFolder>();

+

+                foreach (IObjectParentData p in providerParents)

+                {

+                    if (p == null || p.Object == null || p.Object.Properties == null)

+                    {

+                        // should not happen...

+                        throw new CmisRuntimeException("Repository sent invalid data!");

+                    }

+

+                    // get id property

+                    IPropertyId idProperty = p.Object.Properties[PropertyIds.ObjectId] as IPropertyId;

+                    if (idProperty == null)

+                    {

+                        // the repository sent an object without a valid object id...

+                        throw new CmisRuntimeException("Repository sent invalid data! No object id!");

+                    }

+

+                    // fetch the object and make sure it is a folder

+                    IObjectId parentId = Session.CreateObjectId(idProperty.FirstValue);

+                    IFolder parentFolder = Session.GetObject(parentId) as IFolder;

+                    if (parentFolder == null)

+                    {

+                        // the repository sent an object that is not a folder...

+                        throw new CmisRuntimeException("Repository sent invalid data! Object is not a folder!");

+                    }

+

+                    parents.Add(parentFolder);

+                }

+

+                return parents;

+            }

+        }

+

+        public virtual IList<string> Paths

+        {

+            get

+            {

+                // get object paths of the parent folders

+                IList<IObjectParentData> parents = Binding.GetNavigationService().GetObjectParents(

+                        RepositoryId, ObjectId, GetPropertyQueryName(PropertyIds.Path), false, IncludeRelationshipsFlag.None,

+                        null, true, null);

+

+                IList<string> paths = new List<string>();

+

+                foreach (IObjectParentData p in parents)

+                {

+                    if (p == null || p.Object == null || p.Object.Properties == null)

+                    {

+                        // should not happen...

+                        throw new CmisRuntimeException("Repository sent invalid data!");

+                    }

+

+                    // get path property

+                    IPropertyString pathProperty = p.Object.Properties[PropertyIds.Path] as IPropertyString;

+                    if (pathProperty == null)

+                    {

+                        // the repository sent a folder without a valid path...

+                        throw new CmisRuntimeException("Repository sent invalid data! No path property!");

+                    }

+

+                    if (p.RelativePathSegment == null)

+                    {

+                        // the repository didn't send a relative path segment

+                        throw new CmisRuntimeException("Repository sent invalid data! No relative path segement!");

+                    }

+

+                    string folderPath = pathProperty.FirstValue;

+                    paths.Add(folderPath + (folderPath.EndsWith("/") ? "" : "/") + p.RelativePathSegment);

+                }

+

+                return paths;

+            }

+        }

+

+        public void AddToFolder(IObjectId folderId, bool allVersions)

+        {

+            if (folderId == null || folderId.Id == null)

+            {

+                throw new ArgumentException("Folder Id must be set!");

+            }

+

+            Binding.GetMultiFilingService().AddObjectToFolder(RepositoryId, ObjectId, folderId.Id, allVersions, null);

+        }

+

+        public void RemoveFromFolder(IObjectId folderId)

+        {

+            if (folderId == null || folderId.Id == null)

+            {

+                throw new ArgumentException("Folder Id must be set!");

+            }

+

+            Binding.GetMultiFilingService().RemoveObjectFromFolder(RepositoryId, ObjectId, folderId.Id, null);

+        }

+    }

+

+    /// <summary>

+    /// Document implemetation.

+    /// </summary>

+    public class Document : AbstractFileableCmisObject, IDocument

+    {

+        public Document(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context)

+        {

+            Initialize(session, objectType, objectData, context);

+        }

+

+        // properties

+

+        public bool? IsImmutable { get { return GetPropertyValue(PropertyIds.IsImmutable) as bool?; } }

+

+        public bool? IsLatestVersion { get { return GetPropertyValue(PropertyIds.IsLatestVersion) as bool?; } }

+

+        public bool? IsMajorVersion { get { return GetPropertyValue(PropertyIds.IsMajorVersion) as bool?; } }

+

+        public bool? IsLatestMajorVersion { get { return GetPropertyValue(PropertyIds.IsLatestMajorVersion) as bool?; } }

+

+        public string VersionLabel { get { return GetPropertyValue(PropertyIds.VersionLabel) as string; } }

+

+        public string VersionSeriesId { get { return GetPropertyValue(PropertyIds.VersionSeriesId) as string; } }

+

+        public bool? IsVersionSeriesCheckedOut { get { return GetPropertyValue(PropertyIds.IsVersionSeriesCheckedOut) as bool?; } }

+

+        public string VersionSeriesCheckedOutBy { get { return GetPropertyValue(PropertyIds.VersionSeriesCheckedOutBy) as string; } }

+

+        public string VersionSeriesCheckedOutId { get { return GetPropertyValue(PropertyIds.VersionSeriesCheckedOutId) as string; } }

+

+        public string CheckinComment { get { return GetPropertyValue(PropertyIds.CheckinComment) as string; } }

+

+        public long? ContentStreamLength { get { return GetPropertyValue(PropertyIds.ContentStreamLength) as long?; } }

+

+        public string ContentStreamMimeType { get { return GetPropertyValue(PropertyIds.ContentStreamMimeType) as string; } }

+

+        public string ContentStreamFileName { get { return GetPropertyValue(PropertyIds.ContentStreamFileName) as string; } }

+

+        public string ContentStreamId { get { return GetPropertyValue(PropertyIds.ContentStreamId) as string; } }

+

+        // operations

+

+        public IDocument Copy(IObjectId targetFolderId, IDictionary<string, object> properties, VersioningState? versioningState,

+                IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context)

+        {

+

+            IObjectId newId = Session.CreateDocumentFromSource(this, properties, targetFolderId, versioningState, policies, addAces, removeAces);

+

+            // if no context is provided the object will not be fetched

+            if (context == null || newId == null)

+            {

+                return null;

+            }

+            // get the new object

+            IDocument newDoc = Session.GetObject(newId, context) as IDocument;

+            if (newDoc == null)

+            {

+                throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);

+            }

+

+            return newDoc;

+        }

+

+        public IDocument Copy(IObjectId targetFolderId)

+        {

+            return Copy(targetFolderId, null, null, null, null, null, Session.DefaultContext);

+        }

+

+        public void DeleteAllVersions()

+        {

+            Delete(true);

+        }

+

+        // versioning

+

+        public IObjectId CheckOut()

+        {

+            string newObjectId = null;

+

+            Lock();

+            try

+            {

+                string objectId = ObjectId;

+                bool? contentCopied;

+

+                Binding.GetVersioningService().CheckOut(RepositoryId, ref objectId, null, out contentCopied);

+                newObjectId = objectId;

+            }

+            finally

+            {

+                Unlock();

+            }

+

+            if (newObjectId == null)

+            {

+                return null;

+            }

+

+            return Session.CreateObjectId(newObjectId);

+        }

+

+        public void CancelCheckOut()

+        {

+            Binding.GetVersioningService().CancelCheckOut(RepositoryId, ObjectId, null);

+        }

+

+        public IObjectId CheckIn(bool major, IDictionary<string, object> properties, IContentStream contentStream,

+                string checkinComment, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces)

+        {

+            String newObjectId = null;

+

+            Lock();

+            try

+            {

+                string objectId = ObjectId;

+

+                IObjectFactory of = Session.ObjectFactory;

+

+                HashSet<Updatability> updatebility = new HashSet<Updatability>();

+                updatebility.Add(Updatability.ReadWrite);

+                updatebility.Add(Updatability.WhenCheckedOut);

+

+                Binding.GetVersioningService().CheckIn(RepositoryId, ref objectId, major, of.ConvertProperties(properties, ObjectType, updatebility),

+                    contentStream, checkinComment, of.ConvertPolicies(policies), of.ConvertAces(addAces), of.ConvertAces(removeAces), null);

+

+                newObjectId = objectId;

+            }

+            finally

+            {

+                Unlock();

+            }

+

+            if (newObjectId == null)

+            {

+                return null;

+            }

+

+            return Session.CreateObjectId(newObjectId);

+

+        }

+

+        public IList<IDocument> GetAllVersions()

+        {

+            return GetAllVersions(Session.DefaultContext);

+        }

+

+        public IList<IDocument> GetAllVersions(IOperationContext context)

+        {

+            string objectId;

+            string versionSeriesId;

+

+            Lock();

+            try

+            {

+                objectId = ObjectId;

+                versionSeriesId = VersionSeriesId;

+            }

+            finally

+            {

+                Unlock();

+            }

+

+            IList<IObjectData> versions = Binding.GetVersioningService().GetAllVersions(RepositoryId, objectId, versionSeriesId,

+                context.FilterString, context.IncludeAllowableActions, null);

+

+            IObjectFactory of = Session.ObjectFactory;

+

+            IList<IDocument> result = new List<IDocument>();

+            if (versions != null)

+            {

+                foreach (IObjectData objectData in versions)

+                {

+                    IDocument doc = of.ConvertObject(objectData, context) as IDocument;

+                    if (doc == null)

+                    {

+                        // should not happen...

+                        continue;

+                    }

+

+                    result.Add(doc);

+                }

+            }

+

+            return result;

+        }

+

+        public IDocument GetObjectOfLatestVersion(bool major)

+        {

+            return GetObjectOfLatestVersion(major, Session.DefaultContext);

+        }

+

+        public IDocument GetObjectOfLatestVersion(bool major, IOperationContext context)

+        {

+            string objectId;

+            string versionSeriesId;

+

+            Lock();

+            try

+            {

+                objectId = ObjectId;

+                versionSeriesId = VersionSeriesId;

+            }

+            finally

+            {

+                Unlock();

+            }

+

+            if (versionSeriesId == null)

+            {

+                throw new CmisRuntimeException("Version series id is unknown!");

+            }

+

+            IObjectData objectData = Binding.GetVersioningService().GetObjectOfLatestVersion(RepositoryId, objectId, versionSeriesId, major,

+                context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString,

+                context.IncludePolicies, context.IncludeAcls, null);

+

+            IDocument result = Session.ObjectFactory.ConvertObject(objectData, context) as IDocument;

+            if (result == null)

+            {

+                throw new CmisRuntimeException("Latest version is not a document!");

+            }

+

+            return result;

+        }

+

+        // content operations

+

+        public IContentStream GetContentStream()

+        {

+            return GetContentStream(null);

+        }

+

+        public IContentStream GetContentStream(String streamId)

+        {

+            IContentStream contentStream;

+            try

+            {

+                contentStream = Binding.GetObjectService().GetContentStream(RepositoryId, ObjectId, streamId, null, null, null);

+            }

+            catch (CmisConstraintException)

+            {

+                // no content stream

+                return null;

+            }

+

+            // the AtomPub binding doesn't return a file name

+            // -> get the file name from properties, if present

+            if (contentStream.FileName == null && ContentStreamFileName != null)

+            {

+                ContentStream newContentStream = new ContentStream();

+                newContentStream.FileName = ContentStreamFileName;

+                newContentStream.Length = contentStream.Length;

+                newContentStream.MimeType = contentStream.MimeType;

+                newContentStream.Stream = contentStream.Stream;

+                newContentStream.Extensions = contentStream.Extensions;

+

+                contentStream = newContentStream;

+            }

+

+            return contentStream;

+        }

+

+        public IDocument SetContentStream(IContentStream contentStream, bool overwrite)

+        {

+            IObjectId objectId = SetContentStream(contentStream, overwrite, true);

+            if (objectId == null)

+            {

+                return null;

+            }

+

+            if (ObjectId != objectId.Id)

+            {

+                return (IDocument)Session.GetObject(objectId, CreationContext);

+            }

+

+            return this;

+        }

+

+        public IObjectId SetContentStream(IContentStream contentStream, bool overwrite, bool refresh)

+        {

+            string newObjectId = null;

+

+            Lock();

+            try

+            {

+                string objectId = ObjectId;

+                string changeToken = ChangeToken;

+

+                Binding.GetObjectService().SetContentStream(RepositoryId, ref objectId, overwrite, ref changeToken, contentStream, null);

+

+                newObjectId = objectId;

+            }

+            finally

+            {

+                Unlock();

+            }

+

+            if (refresh)

+            {

+                Refresh();

+            }

+

+            if (newObjectId == null)

+            {

+                return null;

+            }

+

+            return Session.CreateObjectId(newObjectId);

+        }

+

+        public IDocument DeleteContentStream()

+        {

+            IObjectId objectId = DeleteContentStream(true);

+            if (objectId == null)

+            {

+                return null;

+            }

+

+            if (ObjectId != objectId.Id)

+            {

+                return (IDocument)Session.GetObject(objectId, CreationContext);

+            }

+

+            return this;

+        }

+

+        public IObjectId DeleteContentStream(bool refresh)

+        {

+            string newObjectId = null;

+

+            Lock();

+            try

+            {

+                string objectId = ObjectId;

+                string changeToken = ChangeToken;

+

+                Binding.GetObjectService().DeleteContentStream(RepositoryId, ref objectId, ref changeToken, null);

+

+                newObjectId = objectId;

+            }

+            finally

+            {

+                Unlock();

+            }

+

+            if (refresh)

+            {

+                Refresh();

+            }

+

+            if (newObjectId == null)

+            {

+                return null;

+            }

+

+            return Session.CreateObjectId(newObjectId);

+        }

+

+        public IObjectId CheckIn(bool major, IDictionary<String, object> properties, IContentStream contentStream, string checkinComment)

+        {

+            return this.CheckIn(major, properties, contentStream, checkinComment, null, null, null);

+        }

+    }

+

+    /// <summary>

+    /// Folder implemetation.

+    /// </summary>

+    public class Folder : AbstractFileableCmisObject, IFolder

+    {

+        private static HashSet<Updatability> CreateUpdatability = new HashSet<Updatability>();

+        static Folder()

+        {

+            CreateUpdatability.Add(Updatability.OnCreate);

+            CreateUpdatability.Add(Updatability.ReadWrite);

+        }

+

+        public Folder(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context)

+        {

+            Initialize(session, objectType, objectData, context);

+        }

+

+        public IDocument CreateDocument(IDictionary<string, object> properties, IContentStream contentStream, VersioningState? versioningState,

+            IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context)

+        {

+            IObjectId newId = Session.CreateDocument(properties, this, contentStream, versioningState, policies, addAces, removeAces);

+

+            // if no context is provided the object will not be fetched

+            if (context == null || newId == null)

+            {

+                return null;

+            }

+

+            // get the new object

+            IDocument newDoc = Session.GetObject(newId, context) as IDocument;

+            if (newDoc == null)

+            {

+                throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);

+            }

+

+            return newDoc;

+        }

+

+        public IDocument CreateDocumentFromSource(IObjectId source, IDictionary<string, object> properties, VersioningState? versioningState,

+            IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context)

+        {

+            IObjectId newId = Session.CreateDocumentFromSource(source, properties, this, versioningState, policies, addAces, removeAces);

+

+            // if no context is provided the object will not be fetched

+            if (context == null || newId == null)

+            {

+                return null;

+            }

+

+            // get the new object

+            IDocument newDoc = Session.GetObject(newId, context) as IDocument;

+            if (newDoc == null)

+            {

+                throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId);

+            }

+

+            return newDoc;

+        }

+

+        public IFolder CreateFolder(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context)

+        {

+            IObjectId newId = Session.CreateFolder(properties, this, policies, addAces, removeAces);

+

+            // if no context is provided the object will not be fetched

+            if (context == null || newId == null)

+            {

+                return null;

+            }

+

+            // get the new object

+            IFolder newFolder = Session.GetObject(newId, context) as IFolder;

+            if (newFolder == null)

+            {

+                throw new CmisRuntimeException("Newly created object is not a folder! New id: " + newId);

+            }

+

+            return newFolder;

+        }

+

+        public IPolicy CreatePolicy(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context)

+        {

+            IObjectId newId = Session.CreatePolicy(properties, this, policies, addAces, removeAces);

+

+            // if no context is provided the object will not be fetched

+            if (context == null || newId == null)

+            {

+                return null;

+            }

+

+            // get the new object

+            IPolicy newPolicy = Session.GetObject(newId, context) as IPolicy;

+            if (newPolicy == null)

+            {

+                throw new CmisRuntimeException("Newly created object is not a policy! New id: " + newId);

+            }

+

+            return newPolicy;

+        }

+

+        public IList<string> DeleteTree(bool allVersions, UnfileObject? unfile, bool continueOnFailure)

+        {

+            IFailedToDeleteData failed = Binding.GetObjectService().DeleteTree(RepositoryId, ObjectId, allVersions, unfile, continueOnFailure, null);

+            return failed.Ids;

+        }

+

+        public IList<IObjectType> AllowedChildObjectTypes

+        {

+            get

+            {

+                IList<IObjectType> result = new List<IObjectType>();

+

+                Lock();

+                try

+                {

+                    IList<string> otids = GetPropertyValue(PropertyIds.AllowedChildObjectTypeIds) as IList<string>;

+                    if (otids == null)

+                    {

+                        return result;

+                    }

+

+                    foreach (string otid in otids)

+                    {

+                        result.Add(Session.GetTypeDefinition(otid));

+                    }

+                }

+                finally

+                {

+                    Unlock();

+                }

+

+                return result;

+            }

+        }

+

+        public IItemEnumerable<IDocument> GetCheckedOutDocs()

+        {

+            return GetCheckedOutDocs(Session.DefaultContext);

+        }

+

+        public IItemEnumerable<IDocument> GetCheckedOutDocs(IOperationContext context)

+        {

+            string objectId = ObjectId;

+            INavigationService service = Binding.GetNavigationService();

+            IObjectFactory of = Session.ObjectFactory;

+            IOperationContext ctxt = new OperationContext(context);

+

+            PageFetcher<IDocument>.FetchPage fetchPageDelegate = delegate(long maxNumItems, long skipCount)

+            {

+                // get checked out documents for this folder

+                IObjectList checkedOutDocs = service.GetCheckedOutDocs(RepositoryId, objectId, ctxt.FilterString, ctxt.OrderBy, ctxt.IncludeAllowableActions,

+                    ctxt.IncludeRelationships, ctxt.RenditionFilterString, maxNumItems, skipCount, null);

+

+                IList<IDocument> page = new List<IDocument>();

+                if (checkedOutDocs.Objects != null)

+                {

+                    foreach (IObjectData objectData in checkedOutDocs.Objects)

+                    {

+                        IDocument doc = of.ConvertObject(objectData, ctxt) as IDocument;

+                        if (doc == null)

+                        {

+                            // should not happen...

+                            continue;

+                        }

+

+                        page.Add(doc);

+                    }

+                }

+

+

+                return new PageFetcher<IDocument>.Page<IDocument>(page, checkedOutDocs.NumItems, checkedOutDocs.HasMoreItems);

+            };

+

+            return new CollectionEnumerable<IDocument>(new PageFetcher<IDocument>(ctxt.MaxItemsPerPage, fetchPageDelegate));

+        }

+

+        public IItemEnumerable<ICmisObject> GetChildren()

+        {

+            return GetChildren(Session.DefaultContext);

+        }

+

+        public IItemEnumerable<ICmisObject> GetChildren(IOperationContext context)

+        {

+            string objectId = ObjectId;

+            INavigationService service = Binding.GetNavigationService();

+            IObjectFactory of = Session.ObjectFactory;

+            IOperationContext ctxt = new OperationContext(context);

+

+            PageFetcher<ICmisObject>.FetchPage fetchPageDelegate = delegate(long maxNumItems, long skipCount)

+            {

+                // get the children

+                IObjectInFolderList children = service.GetChildren(RepositoryId, objectId, ctxt.FilterString, ctxt.OrderBy, ctxt.IncludeAllowableActions,

+                    ctxt.IncludeRelationships, ctxt.RenditionFilterString, ctxt.IncludePathSegments, maxNumItems, skipCount, null);

+

+                // convert objects

+                IList<ICmisObject> page = new List<ICmisObject>();

+                if (children.Objects != null)

+                {

+                    foreach (IObjectInFolderData objectData in children.Objects)

+                    {

+                        if (objectData.Object != null)

+                        {

+                            page.Add(of.ConvertObject(objectData.Object, ctxt));

+                        }

+                    }

+                }

+

+                return new PageFetcher<ICmisObject>.Page<ICmisObject>(page, children.NumItems, children.HasMoreItems);

+            };

+

+            return new CollectionEnumerable<ICmisObject>(new PageFetcher<ICmisObject>(ctxt.MaxItemsPerPage, fetchPageDelegate));

+        }

+

+        public IList<ITree<IFileableCmisObject>> GetDescendants(int depth)

+        {

+            return GetDescendants(depth, Session.DefaultContext);

+        }

+

+        public IList<ITree<IFileableCmisObject>> GetDescendants(int depth, IOperationContext context)

+        {

+            IList<IObjectInFolderContainer> bindingContainerList = Binding.GetNavigationService().GetDescendants(RepositoryId, ObjectId, depth,

+                context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString,

+                context.IncludePathSegments, null);

+

+            return ConvertProviderContainer(bindingContainerList, context);

+        }

+

+        public IList<ITree<IFileableCmisObject>> GetFolderTree(int depth)

+        {

+            return GetFolderTree(depth, Session.DefaultContext);

+        }

+

+        public IList<ITree<IFileableCmisObject>> GetFolderTree(int depth, IOperationContext context)

+        {

+            IList<IObjectInFolderContainer> bindingContainerList = Binding.GetNavigationService().GetFolderTree(RepositoryId, ObjectId, depth,

+                context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString,

+                context.IncludePathSegments, null);

+

+            return ConvertProviderContainer(bindingContainerList, context);

+        }

+

+        private IList<ITree<IFileableCmisObject>> ConvertProviderContainer(IList<IObjectInFolderContainer> bindingContainerList, IOperationContext context)

+        {

+            if (bindingContainerList == null)

+            {

+                return null;

+            }

+

+            IList<ITree<IFileableCmisObject>> result = new List<ITree<IFileableCmisObject>>();

+            foreach (IObjectInFolderContainer oifc in bindingContainerList)

+            {

+                if (oifc.Object == null || oifc.Object.Object == null)

+                {

+                    // shouldn't happen ...

+                    continue;

+                }

+

+                // convert the object

+                IFileableCmisObject cmisObject = Session.ObjectFactory.ConvertObject(oifc.Object.Object, context) as IFileableCmisObject;

+                if (cmisObject == null)

+                {

+                    // the repository must not return objects that are not fileable, but you never know...

+                    continue;

+                }

+

+                // convert the children

+                IList<ITree<IFileableCmisObject>> children = ConvertProviderContainer(oifc.Children, context);

+

+                // add both to current container

+                Tree<IFileableCmisObject> tree = new Tree<IFileableCmisObject>();

+                tree.Item = cmisObject;

+                tree.Children = children;

+

+                result.Add(tree);

+            }

+

+            return result;

+        }

+

+        public bool IsRootFolder { get { return ObjectId == Session.RepositoryInfo.RootFolderId; } }

+

+        public IFolder FolderParent

+        {

+            get

+            {

+                if (IsRootFolder)

+                {

+                    return null;

+                }

+

+                IList<IFolder> parents = Parents;

+                if (parents == null || parents.Count == 0)

+                {

+                    return null;

+                }

+

+                return parents[0];

+            }

+        }

+

+        public string Path

+        {

+            get

+            {

+                string path;

+

+                Lock();

+                try

+                {

+                    // get the path property

+                    path = GetPropertyValue(PropertyIds.Path) as string;

+

+                    // if the path property isn't set, get it

+                    if (path == null)

+                    {

+                        IObjectData objectData = Binding.GetObjectService().GetObject(RepositoryId, ObjectId,

+                                GetPropertyQueryName(PropertyIds.Path), false, IncludeRelationshipsFlag.None, "cmis:none", false,

+                                false, null);

+

+                        if (objectData.Properties != null)

+                        {

+                            PropertyString pathProperty = objectData.Properties[PropertyIds.Path] as PropertyString;

+                            if (pathProperty != null)

+                            {

+                                path = pathProperty.FirstValue;

+                            }

+                        }

+                    }

+                }

+                finally

+                {

+                    Unlock();

+                }

+

+                // we still don't know the path ... it's not a CMIS compliant repository

+                if (path == null)

+                {

+                    throw new CmisRuntimeException("Repository didn't return " + PropertyIds.Path + "!");

+                }

+

+                return path;

+            }

+        }

+

+        public override IList<string> Paths

+        {

+            get

+            {

+                IList<string> result = new List<string>();

+                result.Add(Path);

+

+                return result;

+            }

+        }

+

+        public IDocument CreateDocument(IDictionary<string, object> properties, IContentStream contentStream, VersioningState? versioningState)

+        {

+            return CreateDocument(properties, contentStream, versioningState, null, null, null, Session.DefaultContext);

+        }

+

+        public IDocument CreateDocumentFromSource(IObjectId source, IDictionary<string, object> properties, VersioningState? versioningState)

+        {

+            return CreateDocumentFromSource(source, properties, versioningState, null, null, null, Session.DefaultContext);

+        }

+

+        public IFolder CreateFolder(IDictionary<string, object> properties)

+        {

+            return CreateFolder(properties, null, null, null, Session.DefaultContext);

+        }

+

+        public IPolicy CreatePolicy(IDictionary<string, object> properties)

+        {

+            return CreatePolicy(properties, null, null, null, Session.DefaultContext);

+        }

+    }

+

+    /// <summary>

+    /// Policy implemetation.

+    /// </summary>

+    public class Policy : AbstractFileableCmisObject, IPolicy

+    {

+        public Policy(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context)

+        {

+            Initialize(session, objectType, objectData, context);

+        }

+

+        public string PolicyText { get { return GetPropertyValue(PropertyIds.PolicyText) as string; } }

+    }

+

+    /// <summary>

+    /// Relationship implemetation.

+    /// </summary>

+    public class Relationship : AbstractCmisObject, IRelationship

+    {

+

+        public Relationship(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context)

+        {

+            Initialize(session, objectType, objectData, context);

+        }

+

+        public ICmisObject GetSource()

+        {

+            return GetSource(Session.DefaultContext);

+        }

+

+        public ICmisObject GetSource(IOperationContext context)

+        {

+            Lock();

+            try

+            {

+                IObjectId sourceId = SourceId;

+                if (sourceId == null)

+                {

+                    return null;

+                }

+

+                return Session.GetObject(sourceId, context);

+            }

+            finally

+            {

+                Unlock();

+            }

+        }

+

+        public IObjectId SourceId

+        {

+            get

+            {

+                string sourceId = GetPropertyValue(PropertyIds.SourceId) as string;

+                if (sourceId == null || sourceId.Length == 0)

+                {

+                    return null;

+                }

+

+                return Session.CreateObjectId(sourceId);

+            }

+        }

+

+        public ICmisObject GetTarget()

+        {

+            return GetTarget(Session.DefaultContext);

+        }

+

+        public ICmisObject GetTarget(IOperationContext context)

+        {

+            Lock();

+            try

+            {

+                IObjectId targetId = TargetId;

+                if (targetId == null)

+                {

+                    return null;

+                }

+

+                return Session.GetObject(targetId, context);

+            }

+            finally

+            {

+                Unlock();

+            }

+        }

+

+        public IObjectId TargetId

+        {

+            get

+            {

+                string targetId = GetPropertyValue(PropertyIds.TargetId) as string;

+                if (targetId == null || targetId.Length == 0)

+                {

+                    return null;

+                }

+

+                return Session.CreateObjectId(targetId);

+            }

+        }

+    }

+

+    public class Property : IProperty

+    {

+        public Property(IPropertyDefinition propertyDefinition, IList<object> values)

+        {

+            PropertyDefinition = propertyDefinition;

+            Values = values;

+        }

+

+        public string Id { get { return PropertyDefinition.Id; } }

+

+        public string LocalName { get { return PropertyDefinition.LocalName; } }

+

+        public string DisplayName { get { return PropertyDefinition.DisplayName; } }

+

+        public string QueryName { get { return PropertyDefinition.QueryName; } }

+

+        public bool IsMultiValued { get { return PropertyDefinition.Cardinality == Cardinality.Multi; } }

+

+        public PropertyType? PropertyType { get { return PropertyDefinition.PropertyType; } }

+

+        public IPropertyDefinition PropertyDefinition { get; protected set; }

+

+        public object Value

+        {

+            get

+            {

+                if (PropertyDefinition.Cardinality == Cardinality.Single)

+                {

+                    return Values.Count == 0 ? null : Values[0];

+                }

+                else

+                {

+                    return Values;

+                }

+            }

+        }

+

+        public IList<object> Values { get; protected set; }

+

+        public object FirstValue { get { return Values.Count == 0 ? null : Values[0]; } }

+

+        public string ValueAsString { get { return FormatValue(FirstValue); } }

+

+        public string ValuesAsString

+        {

+            get

+            {

+                StringBuilder result = new StringBuilder();

+                foreach (object value in Values)

+                {

+                    if (result.Length > 0)

+                    {

+                        result.Append(", ");

+                    }

+

+                    result.Append(FormatValue(value));

+                }

+

+                return "[" + result.ToString() + "]";

+            }

+        }

+

+        private string FormatValue(object value)

+        {

+            if (value == null)

+            {

+                return null;

+            }

+

+            // for future formating

+

+            return value.ToString();

+        }

+    }

+

+    public class Rendition : RenditionData, IRendition

+    {

+        private ISession session;

+        private string objectId;

+

+        public Rendition(ISession session, string objectId, string streamId, string mimeType, long? length, string kind,

+            string title, long? height, long? width, string renditionDocumentId)

+        {

+            this.session = session;

+            this.objectId = objectId;

+

+            StreamId = streamId;

+            MimeType = mimeType;

+            Length = length;

+            Kind = kind;

+            Title = title;

+            Height = height;

+            Width = width;

+            RenditionDocumentId = renditionDocumentId;

+        }

+

+        public IDocument GetRenditionDocument()

+        {

+            return GetRenditionDocument(session.DefaultContext);

+        }

+

+        public IDocument GetRenditionDocument(IOperationContext context)

+        {

+            if (RenditionDocumentId == null)

+            {

+                return null;

+            }

+

+            return session.GetObject(session.CreateObjectId(RenditionDocumentId), context) as IDocument;

+        }

+

+        public IContentStream GetContentStream()

+        {

+            if (objectId == null || StreamId == null)

+            {

+                return null;

+            }

+

+            return session.Binding.GetObjectService().GetContentStream(session.RepositoryInfo.Id, objectId, StreamId, null, null, null);

+        }

+    }

+}
\ No newline at end of file
diff --git a/DotCMIS/client/client-types.cs b/DotCMIS/client/client-types.cs
index 3b4a93a..e6b333f 100644
--- a/DotCMIS/client/client-types.cs
+++ b/DotCMIS/client/client-types.cs
@@ -43,7 +43,7 @@
 

         public ISession Session { get { return session; } }

 

-        public bool IsBaseType { get { return objectType.ParentTypeId == null; } }

+        public bool IsBaseType { get { return objectType.ParentTypeId == null || objectType.ParentTypeId.Length == 0; } }

 

         public IObjectType GetBaseType()

         {

diff --git a/DotCMIS/const.cs b/DotCMIS/const.cs
index 4d81286..83424be 100644
--- a/DotCMIS/const.cs
+++ b/DotCMIS/const.cs
@@ -91,7 +91,7 @@
         public const string IsImmutable = "cmis:isImmutable";

         public const string IsLatestVersion = "cmis:isLatestVersion";

         public const string IsMajorVersion = "cmis:isMajorVersion";

-        public const string isLatestMajorVersion = "cmis:isLatestMajorVersion";

+        public const string IsLatestMajorVersion = "cmis:isLatestMajorVersion";

         public const string VersionLabel = "cmis:versionLabel";

         public const string VersionSeriesId = "cmis:versionSeriesId";

         public const string IsVersionSeriesCheckedOut = "cmis:isVersionSeriesCheckedOut";

diff --git a/DotCMIS/data/data-impl.cs b/DotCMIS/data/data-impl.cs
index 6aaa1ab..78d09eb 100644
--- a/DotCMIS/data/data-impl.cs
+++ b/DotCMIS/data/data-impl.cs
@@ -225,9 +225,9 @@
         public string DisplayName { get; set; }

         public string QueryName { get; set; }

         public string Description { get; set; }

-        public PropertyType? PropertyType { get; set; }

-        public Cardinality? Cardinality { get; set; }

-        public Updatability? Updatability { get; set; }

+        public PropertyType PropertyType { get; set; }

+        public Cardinality Cardinality { get; set; }

+        public Updatability Updatability { get; set; }

         public bool? IsInherited { get; set; }

         public bool? IsRequired { get; set; }

         public bool? IsQueryable { get; set; }

@@ -427,7 +427,7 @@
         }

     }

 

-    public abstract class PropertyData : ExtensionsData, IPropertyData

+    public abstract class AbstractPropertyData : ExtensionsData, IPropertyData

     {

         public string Id { get; set; }

         public string LocalName { get; set; }

@@ -438,37 +438,37 @@
         {

             get

             {

-                if (this is PropertyBoolean)

+                if (this is IPropertyString)

                 {

-                    return ((PropertyBoolean)this).FirstValue;

+                    return ((IPropertyString)this).FirstValue;

                 }

-                else if (this is PropertyDateTime)

+                else if (this is IPropertyInteger)

                 {

-                    return ((PropertyDateTime)this).FirstValue;

+                    return ((IPropertyInteger)this).FirstValue;

                 }

-                else if (this is PropertyDecimal)

+                else if (this is IPropertyId)

                 {

-                    return ((PropertyDecimal)this).FirstValue;

+                    return ((IPropertyId)this).FirstValue;

                 }

-                else if (this is PropertyHtml)

+                else if (this is IPropertyBoolean)

                 {

-                    return ((PropertyHtml)this).FirstValue;

+                    return ((IPropertyBoolean)this).FirstValue;

                 }

-                else if (this is PropertyId)

+                else if (this is IPropertyDateTime)

                 {

-                    return ((PropertyId)this).FirstValue;

+                    return ((IPropertyDateTime)this).FirstValue;

                 }

-                else if (this is PropertyInteger)

+                else if (this is IPropertyDecimal)

                 {

-                    return ((PropertyInteger)this).FirstValue;

+                    return ((IPropertyDecimal)this).FirstValue;

                 }

-                else if (this is PropertyString)

+                else if (this is IPropertyHtml)

                 {

-                    return ((PropertyString)this).FirstValue;

+                    return ((IPropertyHtml)this).FirstValue;

                 }

-                else if (this is PropertyUri)

+                else if (this is IPropertyUri)

                 {

-                    return ((PropertyUri)this).FirstValue;

+                    return ((IPropertyUri)this).FirstValue;

                 }

 

                 return null;

@@ -481,49 +481,49 @@
         }

     }

 

-    public class PropertyBoolean : PropertyData, IPropertyBoolean

+    public class PropertyBoolean : AbstractPropertyData, IPropertyBoolean

     {

         public IList<bool> Values { get; set; }

         public bool? FirstValue { get { return Values == null || Values.Count < 1 ? null : (bool?)Values[0]; } }

     }

 

-    public class PropertyDateTime : PropertyData, IPropertyDateTime

+    public class PropertyDateTime : AbstractPropertyData, IPropertyDateTime

     {

         public IList<DateTime> Values { get; set; }

         public DateTime? FirstValue { get { return Values == null || Values.Count < 1 ? null : (DateTime?)Values[0]; } }

     }

 

-    public class PropertyDecimal : PropertyData, IPropertyDecimal

+    public class PropertyDecimal : AbstractPropertyData, IPropertyDecimal

     {

         public IList<decimal> Values { get; set; }

         public decimal? FirstValue { get { return Values == null || Values.Count < 1 ? null : (decimal?)Values[0]; } }

     }

 

-    public class PropertyHtml : PropertyData, IPropertyHtml

+    public class PropertyHtml : AbstractPropertyData, IPropertyHtml

     {

         public IList<string> Values { get; set; }

         public string FirstValue { get { return Values == null || Values.Count < 1 ? null : Values[0]; } }

     }

 

-    public class PropertyId : PropertyData, IPropertyId

+    public class PropertyId : AbstractPropertyData, IPropertyId

     {

         public IList<string> Values { get; set; }

         public string FirstValue { get { return Values == null || Values.Count < 1 ? null : Values[0]; } }

     }

 

-    public class PropertyInteger : PropertyData, IPropertyInteger

+    public class PropertyInteger : AbstractPropertyData, IPropertyInteger

     {

         public IList<long> Values { get; set; }

         public long? FirstValue { get { return Values == null || Values.Count < 1 ? null : (long?)Values[0]; } }

     }

 

-    public class PropertyString : PropertyData, IPropertyString

+    public class PropertyString : AbstractPropertyData, IPropertyString

     {

         public IList<string> Values { get; set; }

         public string FirstValue { get { return Values == null || Values.Count < 1 ? null : Values[0]; } }

     }

 

-    public class PropertyUri : PropertyData, IPropertyUri

+    public class PropertyUri : AbstractPropertyData, IPropertyUri

     {

         public IList<string> Values { get; set; }

         public string FirstValue { get { return Values == null || Values.Count < 1 ? null : Values[0]; } }

diff --git a/DotCMIS/data/data-intf.cs b/DotCMIS/data/data-intf.cs
index d243b9e..6260b7e 100644
--- a/DotCMIS/data/data-intf.cs
+++ b/DotCMIS/data/data-intf.cs
@@ -145,9 +145,9 @@
         string DisplayName { get; }

         string QueryName { get; }

         string Description { get; }

-        PropertyType? PropertyType { get; }

-        Cardinality? Cardinality { get; }

-        Updatability? Updatability { get; }

+        PropertyType PropertyType { get; }

+        Cardinality Cardinality { get; }

+        Updatability Updatability { get; }

         bool? IsInherited { get; }

         bool? IsRequired { get; }

         bool? IsQueryable { get; }

diff --git a/DotCMISUnitTest/TestFramework.cs b/DotCMISUnitTest/TestFramework.cs
index 9246e9d..57883ee 100644
--- a/DotCMISUnitTest/TestFramework.cs
+++ b/DotCMISUnitTest/TestFramework.cs
@@ -334,6 +334,8 @@
             Assert.NotNull(expected);

             Assert.NotNull(actual);

 

+            Assert.NotNull(actual.Id);

+

             Assert.AreEqual(expected.Id, actual.Id);

             Assert.AreEqual(expected.IsBaseType, actual.IsBaseType);

             Assert.AreEqual(expected.BaseTypeId, actual.BaseTypeId);

@@ -343,6 +345,39 @@
             Assert.AreEqual(expected.LocalNamespace, actual.LocalNamespace);

             Assert.AreEqual(expected.QueryName, actual.QueryName);

             Assert.AreEqual(expected.PropertyDefintions.Count, actual.PropertyDefintions.Count);

+

+            foreach (IPropertyDefinition propDef in expected.PropertyDefintions)

+            {

+                Assert.NotNull(propDef);

+                Assert.NotNull(propDef.Id);

+

+                IPropertyDefinition propDef2 = actual[propDef.Id];

+

+                AssertAreEqual(propDef, propDef2);

+            }

+        }

+

+        public void AssertAreEqual(IPropertyDefinition expected, IPropertyDefinition actual)

+        {

+            if (expected == null && actual == null)

+            {

+                return;

+            }

+

+            Assert.NotNull(expected);

+            Assert.NotNull(actual);

+

+            Assert.NotNull(actual.Id);

+

+            Assert.AreEqual(expected.Id, actual.Id);

+            Assert.AreEqual(expected.LocalName, actual.LocalName);

+            Assert.AreEqual(expected.LocalNamespace, actual.LocalNamespace);

+            Assert.AreEqual(expected.DisplayName, actual.DisplayName);

+            Assert.AreEqual(expected.Description, actual.Description);

+            Assert.AreEqual(expected.QueryName, actual.QueryName);

+            Assert.AreEqual(expected.PropertyType, actual.PropertyType);

+            Assert.AreEqual(expected.Cardinality, actual.Cardinality);

+            Assert.AreEqual(expected.Updatability, actual.Updatability);

         }

     }

 }