- simplified property handling
- implemented GetObject and GetObjectByPath
- added root folder smoke test

git-svn-id: https://svn.apache.org/repos/asf/incubator/chemistry/dotcmis/trunk@1067499 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/DotCMIS.suo b/DotCMIS.suo
index f786b4b..81c2f10 100644
--- a/DotCMIS.suo
+++ b/DotCMIS.suo
Binary files differ
diff --git a/DotCMIS/binding/atompub/atompub.cs b/DotCMIS/binding/atompub/atompub.cs
index f7c9fed..5d0c2b0 100644
--- a/DotCMIS/binding/atompub/atompub.cs
+++ b/DotCMIS/binding/atompub/atompub.cs
@@ -1577,12 +1577,12 @@
 

             // find source id

             IPropertyData sourceIdProperty = properties[PropertyIds.SourceId];

-            if (!(sourceIdProperty is IPropertyId))

+            if (sourceIdProperty == null || sourceIdProperty.PropertyType != PropertyType.Id)

             {

                 throw new CmisInvalidArgumentException("Source Id is not set!");

             }

 

-            string sourceId = ((IPropertyId)sourceIdProperty).FirstValue;

+            string sourceId = sourceIdProperty.FirstValue as string;

             if (sourceId == null)

             {

                 throw new CmisInvalidArgumentException("Source Id is not set!");

diff --git a/DotCMIS/binding/binding-impl.cs b/DotCMIS/binding/binding-impl.cs
index ec3fa86..8194088 100644
--- a/DotCMIS/binding/binding-impl.cs
+++ b/DotCMIS/binding/binding-impl.cs
@@ -325,7 +325,6 @@
                     return spi;

                 }

 

-

                 // ok, we have to create it...

                 try

                 {

diff --git a/DotCMIS/binding/converter.cs b/DotCMIS/binding/converter.cs
index 2bdda14..e1b7dbe 100644
--- a/DotCMIS/binding/converter.cs
+++ b/DotCMIS/binding/converter.cs
@@ -702,100 +702,92 @@
         {

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

 

-            AbstractPropertyData result = null;

+            PropertyData result = null;

             if (property is cmisPropertyString)

             {

-                result = new PropertyString();

+                result = new PropertyData(PropertyType.String);

                 if (((cmisPropertyString)property).value != null)

                 {

-                    ((PropertyString)result).Values = new List<string>();

                     foreach (string value in ((cmisPropertyString)property).value)

                     {

-                        ((PropertyString)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

             else if (property is cmisPropertyId)

             {

-                result = new PropertyId();

+                result = new PropertyData(PropertyType.Id);

                 if (((cmisPropertyId)property).value != null)

                 {

-                    ((PropertyId)result).Values = new List<string>();

                     foreach (string value in ((cmisPropertyId)property).value)

                     {

-                        ((PropertyId)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

             else if (property is cmisPropertyInteger)

             {

-                result = new PropertyInteger();

+                result = new PropertyData(PropertyType.Integer);

                 if (((cmisPropertyInteger)property).value != null)

                 {

-                    ((PropertyInteger)result).Values = new List<long>();

                     foreach (string value in ((cmisPropertyInteger)property).value)

                     {

-                        ((PropertyInteger)result).Values.Add(Int64.Parse(value));

+                        result.AddValue(Int64.Parse(value));

                     }

                 }

             }

             else if (property is cmisPropertyBoolean)

             {

-                result = new PropertyBoolean();

+                result = new PropertyData(PropertyType.Boolean);

                 if (((cmisPropertyBoolean)property).value != null)

                 {

-                    ((PropertyBoolean)result).Values = new List<bool>();

                     foreach (bool value in ((cmisPropertyBoolean)property).value)

                     {

-                        ((PropertyBoolean)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

             else if (property is cmisPropertyDateTime)

             {

-                result = new PropertyDateTime();

+                result = new PropertyData(PropertyType.DateTime);

                 if (((cmisPropertyDateTime)property).value != null)

                 {

-                    ((PropertyDateTime)result).Values = new List<DateTime>();

                     foreach (DateTime value in ((cmisPropertyDateTime)property).value)

                     {

-                        ((PropertyDateTime)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

             else if (property is cmisPropertyDecimal)

             {

-                result = new PropertyDecimal();

+                result = new PropertyData(PropertyType.Decimal);

                 if (((cmisPropertyDecimal)property).value != null)

                 {

-                    ((PropertyDecimal)result).Values = new List<decimal>();

                     foreach (decimal value in ((cmisPropertyDecimal)property).value)

                     {

-                        ((PropertyDecimal)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

             else if (property is cmisPropertyHtml)

             {

-                result = new PropertyHtml();

+                result = new PropertyData(PropertyType.Html);

                 if (((cmisPropertyHtml)property).value != null)

                 {

-                    ((PropertyHtml)result).Values = new List<string>();

                     foreach (string value in ((cmisPropertyHtml)property).value)

                     {

-                        ((PropertyHtml)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

             else if (property is cmisPropertyUri)

             {

-                result = new PropertyUri();

+                result = new PropertyData(PropertyType.Uri);

                 if (((cmisPropertyUri)property).value != null)

                 {

-                    ((PropertyUri)result).Values = new List<string>();

                     foreach (string value in ((cmisPropertyUri)property).value)

                     {

-                        ((PropertyUri)result).Values.Add(value);

+                        result.AddValue(value);

                     }

                 }

             }

@@ -836,109 +828,112 @@
 

             cmisProperty result = null;

 

-            if (property is IPropertyString)

+            switch (property.PropertyType)

             {

-                result = new cmisPropertyString();

-                IList<string> propValues = ((IPropertyString)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyString)result).value = new string[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                case PropertyType.String:

+                    result = new cmisPropertyString();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyString)result).value[i] = propValues[i];

+                        ((cmisPropertyString)result).value = new string[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            ((cmisPropertyString)result).value[i] = property.Values[i] as string;

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyId)

-            {

-                result = new cmisPropertyId();

-                IList<string> propValues = ((IPropertyId)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyId)result).value = new string[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.Id:

+                    result = new cmisPropertyId();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyId)result).value[i] = propValues[i];

+                        ((cmisPropertyId)result).value = new string[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            ((cmisPropertyId)result).value[i] = property.Values[i] as string;

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyInteger)

-            {

-                result = new cmisPropertyInteger();

-                IList<long> propValues = ((IPropertyInteger)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyInteger)result).value = new string[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.Integer:

+                    result = new cmisPropertyInteger();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyInteger)result).value[i] = propValues[i].ToString();

+                        ((cmisPropertyInteger)result).value = new string[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            long? value = property.Values[i] as long?;

+                            if (value.HasValue)

+                            {

+                                ((cmisPropertyInteger)result).value[i] = value.ToString();

+                            }

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyBoolean)

-            {

-                result = new cmisPropertyInteger();

-                IList<bool> propValues = ((IPropertyBoolean)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyBoolean)result).value = new bool[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.Boolean:

+                    result = new cmisPropertyBoolean();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyBoolean)result).value[i] = propValues[i];

+                        ((cmisPropertyBoolean)result).value = new bool[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            bool? value = property.Values[i] as bool?;

+                            if (value.HasValue)

+                            {

+                                ((cmisPropertyBoolean)result).value[i] = value.Value;

+                            }

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyDateTime)

-            {

-                result = new cmisPropertyDateTime();

-                IList<DateTime> propValues = ((IPropertyDateTime)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyDateTime)result).value = new DateTime[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.DateTime:

+                    result = new cmisPropertyDateTime();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyDateTime)result).value[i] = propValues[i];

+                        ((cmisPropertyDateTime)result).value = new DateTime[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            DateTime? value = property.Values[i] as DateTime?;

+                            if (value.HasValue)

+                            {

+                                ((cmisPropertyDateTime)result).value[i] = value.Value;

+                            }

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyDecimal)

-            {

-                result = new cmisPropertyDecimal();

-                IList<decimal> propValues = ((IPropertyDecimal)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyDecimal)result).value = new decimal[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.Decimal:

+                    result = new cmisPropertyDecimal();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyDecimal)result).value[i] = propValues[i];

+                        ((cmisPropertyDecimal)result).value = new decimal[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            decimal? value = property.Values[i] as decimal?;

+                            if (value.HasValue)

+                            {

+                                ((cmisPropertyDecimal)result).value[i] = value.Value;

+                            }

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyHtml)

-            {

-                result = new cmisPropertyHtml();

-                IList<string> propValues = ((IPropertyHtml)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyHtml)result).value = new string[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.Html:

+                    result = new cmisPropertyHtml();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyHtml)result).value[i] = propValues[i];

+                        ((cmisPropertyHtml)result).value = new string[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            ((cmisPropertyHtml)result).value[i] = property.Values[i] as string;

+                        }

                     }

-                }

-            }

-            else if (property is IPropertyUri)

-            {

-                result = new cmisPropertyUri();

-                IList<string> propValues = ((IPropertyUri)property).Values;

-                if (propValues != null)

-                {

-                    ((cmisPropertyUri)result).value = new string[propValues.Count];

-                    for (int i = 0; i < propValues.Count; i++)

+                    break;

+                case PropertyType.Uri:

+                    result = new cmisPropertyUri();

+                    if (property.Values != null)

                     {

-                        ((cmisPropertyUri)result).value[i] = propValues[i];

+                        ((cmisPropertyUri)result).value = new string[property.Values.Count];

+                        for (int i = 0; i < property.Values.Count; i++)

+                        {

+                            ((cmisPropertyUri)result).value[i] = property.Values[i] as string;

+                        }

                     }

-                }

+                    break;

             }

 

             result.propertyDefinitionId = property.Id;

diff --git a/DotCMIS/binding/http.cs b/DotCMIS/binding/http.cs
index a3864a7..b787788 100644
--- a/DotCMIS/binding/http.cs
+++ b/DotCMIS/binding/http.cs
@@ -157,9 +157,9 @@
             {

                 response = exception.Response;

 

-                if (response is HttpWebResponse)

+                HttpWebResponse httpResponse = response as HttpWebResponse;

+                if (httpResponse != null)

                 {

-                    HttpWebResponse httpResponse = (HttpWebResponse)response;

                     StatusCode = httpResponse.StatusCode;

                     Message = httpResponse.StatusDescription;

                     ContentType = httpResponse.ContentType;

diff --git a/DotCMIS/client/client-impl.cs b/DotCMIS/client/client-impl.cs
index 9319ab9..341ab89 100644
--- a/DotCMIS/client/client-impl.cs
+++ b/DotCMIS/client/client-impl.cs
@@ -54,7 +54,7 @@
 

         public IList<IRepository> GetRepositories(IDictionary<string, string> parameters)

         {

-            ICmisBinding binding = CmisBindingHelper.CreateProvider(parameters);

+            ICmisBinding binding = CmisBindingHelper.CreateBinding(parameters);

 

             IList<IRepositoryInfo> repositoryInfos = binding.GetRepositoryService().GetRepositoryInfos(null);

 

@@ -73,7 +73,7 @@
     /// </summary>

     internal class CmisBindingHelper

     {

-        public static ICmisBinding CreateProvider(IDictionary<string, string> parameters)

+        public static ICmisBinding CreateBinding(IDictionary<string, string> parameters)

         {

             if (parameters == null)

             {

@@ -163,6 +163,7 @@
 

         public IObjectFactory ObjectFactory { get; protected set; }

         protected ICache Cache { get; set; }

+        protected bool cachePathOmit;

 

         private IOperationContext context = FallbackContext;

         public IOperationContext DefaultContext

@@ -204,6 +205,16 @@
 

             ObjectFactory = CreateObjectFactory();

             Cache = CreateCache();

+

+            string cachePathOmitStr;

+            if (parameters.TryGetValue(SessionParameter.CachePathOmit, out cachePathOmitStr))

+            {

+                cachePathOmit = cachePathOmitStr.ToLower() == "true";

+            }

+            else

+            {

+                cachePathOmit = false;

+            }

         }

 

         public void Connect()

@@ -211,7 +222,7 @@
             Lock();

             try

             {

-                Binding = CmisBindingHelper.CreateProvider(parameters);

+                Binding = CmisBindingHelper.CreateBinding(parameters);

 

                 string repositoryId;

                 if (!parameters.TryGetValue(SessionParameter.RepositoryId, out repositoryId))

@@ -409,7 +420,43 @@
         }

 

         public ICmisObject GetObject(IObjectId objectId, IOperationContext context)

-        { throw new CmisNotSupportedException("Client not implemented!"); }

+        {

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

+            {

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

+            }

+            if (context == null)

+            {

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

+            }

+

+            ICmisObject result = null;

+

+            // ask the cache first

+            if (context.CacheEnabled)

+            {

+                result = Cache.GetById(objectId.Id, context.CacheKey);

+                if (result != null)

+                {

+                    return result;

+                }

+            }

+

+            // get the object

+            IObjectData objectData = Binding.GetObjectService().GetObject(RepositoryId, objectId.Id, context.FilterString,

+                context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, context.IncludePolicies,

+                context.IncludeAcls, null);

+

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

+

+            // put into cache

+            if (context.CacheEnabled)

+            {

+                Cache.Put(result, context.CacheKey);

+            }

+

+            return result;

+        }

 

         public ICmisObject GetObjectByPath(string path)

         {

@@ -417,7 +464,43 @@
         }

 

         public ICmisObject GetObjectByPath(string path, IOperationContext context)

-        { throw new CmisNotSupportedException("Client not implemented!"); }

+        {

+            if (path == null)

+            {

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

+            }

+            if (context == null)

+            {

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

+            }

+

+            ICmisObject result = null;

+

+            // ask the cache first

+            if (context.CacheEnabled && !cachePathOmit)

+            {

+                result = Cache.GetByPath(path, context.CacheKey);

+                if (result != null)

+                {

+                    return result;

+                }

+            }

+

+            // get the object

+            IObjectData objectData = Binding.GetObjectService().GetObjectByPath(RepositoryId, path, context.FilterString,

+                context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, context.IncludePolicies,

+                context.IncludeAcls, null);

+

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

+

+            // put into cache

+            if (context.CacheEnabled)

+            {

+                Cache.PutPath(path, result, context.CacheKey);

+            }

+

+            return result;

+        }

 

         // discovery

 

diff --git a/DotCMIS/client/client-objectfactory.cs b/DotCMIS/client/client-objectfactory.cs
index 1de2d67..833130e 100644
--- a/DotCMIS/client/client-objectfactory.cs
+++ b/DotCMIS/client/client-objectfactory.cs
@@ -138,13 +138,19 @@
                 return null;

             }

 

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

+            IPropertyData typeProperty = objectData.Properties[PropertyIds.ObjectTypeId];

             if (typeProperty == null)

             {

                 return null;

             }

 

-            return session.GetTypeDefinition(typeProperty.FirstValue);

+            string typeId = typeProperty.FirstValue as string;

+            if (typeId == null)

+            {

+                return null;

+            }

+

+            return session.GetTypeDefinition(typeId);

         }

 

         // properties

@@ -162,25 +168,7 @@
                 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;

-            }

+            return CreateProperty(definition, pd.Values);

         }

 

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

@@ -266,39 +254,32 @@
                     }

                 }

 

+                PropertyData propertyData = new PropertyData(definition.PropertyType);

+                propertyData.Id = id;

+

                 // single and multi value check

-                IList<dynamic> values;

                 if (value == null)

                 {

-                    values = null;

+                    propertyData.Values = null;

                 }

-                else if (value is IList<dynamic>)

+                else if (value is IList)

                 {

                     if (definition.Cardinality != Cardinality.Multi)

                     {

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

                     }

-                    values = (IList<dynamic>)value;

+

+                    IList valueList = (IList)value;

 

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

-                    Type valueType = null;

-                    foreach (object o in values)

+                    foreach (object o in valueList)

                     {

                         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!");

-                            }

-                        }

+

+                        propertyData.AddValue(o);

                     }

                 }

                 else

@@ -307,160 +288,11 @@
                     {

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

                     }

-                    values = new List<dynamic>();

-                    values.Add(value);

+

+                    propertyData.AddValue(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;

-                }

+                result.AddProperty(propertyData);

             }

 

             return result;

diff --git a/DotCMIS/client/client-objects.cs b/DotCMIS/client/client-objects.cs
index cc75cc9..3131ce2 100644
--- a/DotCMIS/client/client-objects.cs
+++ b/DotCMIS/client/client-objects.cs
@@ -599,13 +599,12 @@
             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<IObjectParentData> bindingParents = 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)

+                foreach (IObjectParentData p in bindingParents)

                 {

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

                     {

@@ -614,15 +613,15 @@
                     }

 

                     // get id property

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

-                    if (idProperty == null)

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

+                    if (idProperty == null || idProperty.PropertyType != PropertyType.Id)

                     {

                         // 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);

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

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

                     if (parentFolder == null)

                     {

@@ -657,8 +656,8 @@
                     }

 

                     // get path property

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

-                    if (pathProperty == null)

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

+                    if (pathProperty == null || pathProperty.PropertyType != PropertyType.String)

                     {

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

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

@@ -670,7 +669,7 @@
                         throw new CmisRuntimeException("Repository sent invalid data! No relative path segement!");

                     }

 

-                    string folderPath = pathProperty.FirstValue;

+                    string folderPath = pathProperty.FirstValue as string;

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

                 }

 

@@ -1068,13 +1067,6 @@
     /// </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);

@@ -1383,10 +1375,10 @@
 

                         if (objectData.Properties != null)

                         {

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

-                            if (pathProperty != null)

+                            IPropertyData pathProperty = objectData.Properties[PropertyIds.Path];

+                            if (pathProperty != null && pathProperty.PropertyType == PropertyType.String)

                             {

-                                path = pathProperty.FirstValue;

+                                path = pathProperty.FirstValue as string;

                             }

                         }

                     }

diff --git a/DotCMIS/client/client-utils.cs b/DotCMIS/client/client-utils.cs
index d9a229c..bff191e 100644
--- a/DotCMIS/client/client-utils.cs
+++ b/DotCMIS/client/client-utils.cs
@@ -63,12 +63,12 @@
 

         public OperationContext(IOperationContext source)

         {

-            filter = new HashSet<string>(source.Filter);

+            filter = (source.Filter == null ? null : new HashSet<string>(source.Filter));

             includeAcls = source.IncludeAcls;

             includeAllowableActions = source.IncludeAllowableActions;

             includePolicies = source.IncludePolicies;

             includeRelationships = source.IncludeRelationships;

-            renditionFilter = new HashSet<string>(source.RenditionFilter);

+            renditionFilter = (source.RenditionFilter == null ? null : new HashSet<string>(source.RenditionFilter));

             includePathSegments = source.IncludePathSegments;

             orderBy = source.OrderBy;

             cacheEnabled = source.CacheEnabled;

@@ -97,7 +97,7 @@
 

         public HashSet<string> Filter

         {

-            get { return new HashSet<string>(filter); }

+            get { return filter == null ? null : new HashSet<string>(filter); }

             set

             {

                 if (value != null)

@@ -206,7 +206,7 @@
 

         public HashSet<string> RenditionFilter

         {

-            get { return new HashSet<string>(renditionFilter); }

+            get { return renditionFilter == null ? null : new HashSet<string>(renditionFilter); }

             set

             {

                 HashSet<string> tempSet = new HashSet<string>();

diff --git a/DotCMIS/const.cs b/DotCMIS/const.cs
index 83424be..cade7fe 100644
--- a/DotCMIS/const.cs
+++ b/DotCMIS/const.cs
@@ -65,6 +65,8 @@
         public const string ObjectFactoryClass = "org.apache.chemistry.dotcmis.objectfactory.classname";

         public const string CacheClass = "org.apache.chemistry.dotcmis.cache.classname";

         public const string RepositoryId = "org.apache.chemistry.dotcmis.session.repository.id";

+

+        public const string CachePathOmit = "org.apache.chemistry.dotcmis.cache.path.omit";

     }

 

     public static class BindingType

diff --git a/DotCMIS/data/data-impl.cs b/DotCMIS/data/data-impl.cs
index 78d09eb..26945d3 100644
--- a/DotCMIS/data/data-impl.cs
+++ b/DotCMIS/data/data-impl.cs
@@ -338,7 +338,7 @@
                 return null;

             }

 

-            return property.FirstObject;

+            return property.FirstValue;

         }

     }

 

@@ -427,108 +427,121 @@
         }

     }

 

-    public abstract class AbstractPropertyData : ExtensionsData, IPropertyData

+    public class PropertyData : ExtensionsData, IPropertyData

     {

+        private IList<object> values;

+

+        public PropertyData(PropertyType propertyType)

+        {

+            PropertyType = propertyType;

+        }

+

         public string Id { get; set; }

+

         public string LocalName { get; set; }

+

         public string DisplayName { get; set; }

+

         public string QueryName { get; set; }

 

-        public object FirstObject

-        {

-            get

-            {

-                if (this is IPropertyString)

-                {

-                    return ((IPropertyString)this).FirstValue;

-                }

-                else if (this is IPropertyInteger)

-                {

-                    return ((IPropertyInteger)this).FirstValue;

-                }

-                else if (this is IPropertyId)

-                {

-                    return ((IPropertyId)this).FirstValue;

-                }

-                else if (this is IPropertyBoolean)

-                {

-                    return ((IPropertyBoolean)this).FirstValue;

-                }

-                else if (this is IPropertyDateTime)

-                {

-                    return ((IPropertyDateTime)this).FirstValue;

-                }

-                else if (this is IPropertyDecimal)

-                {

-                    return ((IPropertyDecimal)this).FirstValue;

-                }

-                else if (this is IPropertyHtml)

-                {

-                    return ((IPropertyHtml)this).FirstValue;

-                }

-                else if (this is IPropertyUri)

-                {

-                    return ((IPropertyUri)this).FirstValue;

-                }

+        public PropertyType PropertyType { get; protected set; }

 

-                return null;

+        public IList<object> Values

+        {

+            get { return values; }

+            set

+            {

+                if (value == null)

+                {

+                    values = null;

+                }

+                else

+                {

+                    foreach (object o in value)

+                    {

+                        CheckValue(o);

+                    }

+

+                    values = value;

+                }

+            }

+        }

+

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

+

+        public void AddValue(object value)

+        {

+            CheckValue(value);

+

+            if (Values == null)

+            {

+                Values = new List<object>();

+            }

+

+            Values.Add(value);

+        }

+

+        public void CheckValue(object value)

+        {

+            switch (PropertyType)

+            {

+                case PropertyType.String:

+                    if (!(value is string))

+                    {

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

+                    }

+                    break;

+                case PropertyType.Id:

+                    if (!(value is string))

+                    {

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

+                    }

+                    break;

+                case PropertyType.Integer:

+                    if (!(value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long))

+                    {

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

+                    }

+                    break;

+                case PropertyType.Boolean:

+                    if (!(value is bool))

+                    {

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

+                    }

+                    break;

+                case PropertyType.DateTime:

+                    if (!(value is DateTime))

+                    {

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

+                    }

+                    break;

+                case PropertyType.Decimal:

+                    if (!(value is decimal))

+                    {

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

+                    }

+                    break;

+                case PropertyType.Uri:

+                    if (!(value is string))

+                    {

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

+                    }

+                    break;

+                case PropertyType.Html:

+                    if (!(value is string))

+                    {

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

+                    }

+                    break;

             }

         }

 

         public override string ToString()

         {

-            return Id + ": " + FirstObject;

+            return Id + ": " + values;

         }

     }

 

-    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 : 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 : 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 : AbstractPropertyData, IPropertyHtml

-    {

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

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

-    }

-

-    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 : 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 : AbstractPropertyData, IPropertyString

-    {

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

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

-    }

-

-    public class PropertyUri : AbstractPropertyData, IPropertyUri

-    {

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

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

-    }

-

     public class Principal : ExtensionsData, IPrincipal

     {

         public string Id { get; set; }

diff --git a/DotCMIS/data/data-intf.cs b/DotCMIS/data/data-intf.cs
index 6260b7e..a2d6c9f 100644
--- a/DotCMIS/data/data-intf.cs
+++ b/DotCMIS/data/data-intf.cs
@@ -275,55 +275,9 @@
         string LocalName { get; }

         string DisplayName { get; }

         string QueryName { get; }

-        object FirstObject { get; }

-    }

-

-    public interface IPropertyBoolean : IPropertyData

-    {

-        IList<bool> Values { get; }

-        bool? FirstValue { get; }

-    }

-

-    public interface IPropertyDateTime : IPropertyData

-    {

-        IList<DateTime> Values { get; }

-        DateTime? FirstValue { get; }

-    }

-

-    public interface IPropertyDecimal : IPropertyData

-    {

-        IList<decimal> Values { get; }

-        decimal? FirstValue { get; }

-    }

-

-    public interface IPropertyHtml : IPropertyData

-    {

-        IList<string> Values { get; }

-        string FirstValue { get; }

-    }

-

-    public interface IPropertyId : IPropertyData

-    {

-        IList<string> Values { get; }

-        string FirstValue { get; }

-    }

-

-    public interface IPropertyInteger : IPropertyData

-    {

-        IList<long> Values { get; }

-        long? FirstValue { get; }

-    }

-

-    public interface IPropertyString : IPropertyData

-    {

-        IList<string> Values { get; }

-        string FirstValue { get; }

-    }

-

-    public interface IPropertyUri : IPropertyData

-    {

-        IList<string> Values { get; }

-        string FirstValue { get; }

+        PropertyType PropertyType { get; }

+        IList<object> Values { get; }

+        object FirstValue { get; }

     }

 

     public interface IPrincipal : IExtensionsData

diff --git a/DotCMISUnitTest/SmokeTest.cs b/DotCMISUnitTest/SmokeTest.cs
index 9b26d8f..fa7b19f 100644
--- a/DotCMISUnitTest/SmokeTest.cs
+++ b/DotCMISUnitTest/SmokeTest.cs
@@ -23,6 +23,7 @@
 using NUnit.Framework;

 using DotCMIS.Client;

 using DotCMIS.Enums;

+using DotCMIS;

 

 namespace DotCMISUnitTest

 {

@@ -125,5 +126,24 @@
             Assert.True(count >= 2);

             Assert.True(count <= 4);

         }

+

+        [Test]

+        public void SmokeRootFolder()

+        {

+            ICmisObject rootFolderObject = Session.GetRootFolder();

+

+            Assert.NotNull(rootFolderObject);

+            Assert.NotNull(rootFolderObject.Id);

+            Assert.True(rootFolderObject is IFolder);

+

+            IFolder rootFolder = (IFolder)rootFolderObject;

+

+            Assert.AreEqual("/", rootFolder.Path);

+            Assert.AreEqual(1, rootFolder.Paths.Count);

+

+            Assert.NotNull(rootFolder.AllowableActions);

+            Assert.True(rootFolder.AllowableActions.Actions.Contains(Actions.CanGetProperties));

+            Assert.False(rootFolder.AllowableActions.Actions.Contains(Actions.CanGetFolderParent));

+        }

     }

 }

diff --git a/DotCMISUnitTest/TestFramework.cs b/DotCMISUnitTest/TestFramework.cs
index 57883ee..bf1289e 100644
--- a/DotCMISUnitTest/TestFramework.cs
+++ b/DotCMISUnitTest/TestFramework.cs
@@ -132,15 +132,15 @@
         {

             Properties properties = new Properties();

 

-            PropertyId objectTypeIdProperty = new PropertyId();

+            PropertyData objectTypeIdProperty = new PropertyData(PropertyType.Id);

             objectTypeIdProperty.Id = PropertyIds.ObjectTypeId;

-            objectTypeIdProperty.Values = new List<string>();

+            objectTypeIdProperty.Values = new List<object>();

             objectTypeIdProperty.Values.Add(DefaultDocumentType);

             properties.AddProperty(objectTypeIdProperty);

 

-            PropertyString nameProperty = new PropertyString();

+            PropertyData nameProperty = new PropertyData(PropertyType.String);

             nameProperty.Id = PropertyIds.Name;

-            nameProperty.Values = new List<string>();

+            nameProperty.Values = new List<object>();

             nameProperty.Values.Add(name);

             properties.AddProperty(nameProperty);

 

@@ -166,10 +166,12 @@
             Assert.NotNull(doc.Id);

             Assert.AreEqual(BaseTypeId.CmisDocument, doc.BaseTypeId);

             Assert.NotNull(doc.Properties);

-            Assert.True(doc.Properties[PropertyIds.ObjectTypeId] is PropertyId);

-            Assert.AreEqual(DefaultDocumentType, ((PropertyId)doc.Properties[PropertyIds.ObjectTypeId]).FirstValue);

-            Assert.True(doc.Properties[PropertyIds.Name] is PropertyString);

-            Assert.AreEqual(name, ((PropertyString)doc.Properties[PropertyIds.Name]).FirstValue);

+            Assert.NotNull(doc.Properties[PropertyIds.ObjectTypeId]);

+            Assert.AreEqual(PropertyType.Id, doc.Properties[PropertyIds.ObjectTypeId].PropertyType);

+            Assert.AreEqual(DefaultDocumentType, doc.Properties[PropertyIds.ObjectTypeId].FirstValue as string);

+            Assert.NotNull(doc.Properties[PropertyIds.Name]);

+            Assert.AreEqual(PropertyType.String, doc.Properties[PropertyIds.Name].PropertyType);

+            Assert.AreEqual(name, doc.Properties[PropertyIds.Name].FirstValue as string);

 

             if (folderId != null)

             {

@@ -183,15 +185,15 @@
         {

             Properties properties = new Properties();

 

-            PropertyId objectTypeIdProperty = new PropertyId();

+            PropertyData objectTypeIdProperty = new PropertyData(PropertyType.Id);

             objectTypeIdProperty.Id = PropertyIds.ObjectTypeId;

-            objectTypeIdProperty.Values = new List<string>();

+            objectTypeIdProperty.Values = new List<object>();

             objectTypeIdProperty.Values.Add(DefaultFolderType);

             properties.AddProperty(objectTypeIdProperty);

 

-            PropertyString nameProperty = new PropertyString();

+            PropertyData nameProperty = new PropertyData(PropertyType.String);

             nameProperty.Id = PropertyIds.Name;

-            nameProperty.Values = new List<string>();

+            nameProperty.Values = new List<object>();

             nameProperty.Values.Add(name);

             properties.AddProperty(nameProperty);

 

@@ -205,10 +207,12 @@
             Assert.NotNull(folder.Id);

             Assert.AreEqual(BaseTypeId.CmisFolder, folder.BaseTypeId);

             Assert.NotNull(folder.Properties);

-            Assert.True(folder.Properties[PropertyIds.ObjectTypeId] is PropertyId);

-            Assert.AreEqual(DefaultFolderType, ((PropertyId)folder.Properties[PropertyIds.ObjectTypeId]).FirstValue);

-            Assert.True(folder.Properties[PropertyIds.Name] is PropertyString);

-            Assert.AreEqual(name, ((PropertyString)folder.Properties[PropertyIds.Name]).FirstValue);

+            Assert.NotNull(folder.Properties[PropertyIds.ObjectTypeId]);

+            Assert.AreEqual(PropertyType.Id, folder.Properties[PropertyIds.ObjectTypeId].PropertyType);

+            Assert.AreEqual(DefaultFolderType, folder.Properties[PropertyIds.ObjectTypeId].FirstValue as string);

+            Assert.NotNull(folder.Properties[PropertyIds.Name]);

+            Assert.AreEqual(PropertyType.String, folder.Properties[PropertyIds.Name].PropertyType);

+            Assert.AreEqual(name, folder.Properties[PropertyIds.Name].FirstValue as string);

 

             if (folderId != null)

             {