PortCMIS: more stuff

git-svn-id: https://svn.apache.org/repos/asf/chemistry/portcmis/trunk@1742546 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/PortCMIS/binding/HttpPortable.cs b/PortCMIS/binding/HttpPortable.cs
index ef44fe5..44d10af 100644
--- a/PortCMIS/binding/HttpPortable.cs
+++ b/PortCMIS/binding/HttpPortable.cs
@@ -140,7 +140,7 @@
             {

                 foreach (KeyValuePair<string, string> header in headers)

                 {

-                    request.Headers.Add(header.Key, header.Value);

+                    request.Headers.TryAddWithoutValidation(header.Key, header.Value);

                 }

             }

 

diff --git a/PortCMIS/binding/IOUtils.cs b/PortCMIS/binding/IOUtils.cs
index b07f416..bfd37b8 100644
--- a/PortCMIS/binding/IOUtils.cs
+++ b/PortCMIS/binding/IOUtils.cs
@@ -17,14 +17,9 @@
 * under the License.

 */

 

-using System;

-using System.Collections.Generic;

 using System.IO;

-using System.Linq;

-using System.Text;

-using System.Threading.Tasks;

 

-namespace PortCMIS.binding

+namespace PortCMIS.Binding

 {

     class IOUtils

     {

diff --git a/PortCMIS/binding/atompub/AtomPubBinding.cs b/PortCMIS/binding/atompub/AtomPubBinding.cs
index d94febe..61a824b 100644
--- a/PortCMIS/binding/atompub/AtomPubBinding.cs
+++ b/PortCMIS/binding/atompub/AtomPubBinding.cs
@@ -17,7 +17,7 @@
 * under the License.

 */

 

-using PortCMIS.binding;

+using PortCMIS.Binding;

 using PortCMIS.Binding.Http;

 using PortCMIS.Binding.Impl;

 using PortCMIS.Binding.Services;

diff --git a/PortCMIS/binding/atompub/AtomPubUtils.cs b/PortCMIS/binding/atompub/AtomPubUtils.cs
index 05510b2..3114df5 100644
--- a/PortCMIS/binding/atompub/AtomPubUtils.cs
+++ b/PortCMIS/binding/atompub/AtomPubUtils.cs
@@ -17,7 +17,7 @@
 * under the License.

 */

 

-using PortCMIS.binding;

+using PortCMIS.Binding;

 using PortCMIS.Binding.Impl;

 using PortCMIS.Client;

 using PortCMIS.Data;

diff --git a/PortCMIS/binding/browser/BrowserBinding.cs b/PortCMIS/binding/browser/BrowserBinding.cs
index dc196fc..c746b55 100644
--- a/PortCMIS/binding/browser/BrowserBinding.cs
+++ b/PortCMIS/binding/browser/BrowserBinding.cs
@@ -17,7 +17,7 @@
 * under the License.

 */

 

-using PortCMIS.binding;

+using PortCMIS.Binding;

 using PortCMIS.Binding.Browser.Json;

 using PortCMIS.Binding.Http;

 using PortCMIS.Binding.Impl;

@@ -295,7 +295,7 @@
             if (Stream.Stream != null)

             {

                 StreamContent streamContent = new StreamContent(Stream.Stream);

-                streamContent.Headers.ContentType = new MediaTypeHeaderValue(Stream.MimeType ?? "application/octet-stream");

+                streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(Stream.MimeType ?? "application/octet-stream");

 

                 content.Add(streamContent, "content", Stream.FileName ?? "content");

             }

diff --git a/PortCMIS/client/ClientImpl.cs b/PortCMIS/client/ClientImpl.cs
index 93108c0..59d18b7 100644
--- a/PortCMIS/client/ClientImpl.cs
+++ b/PortCMIS/client/ClientImpl.cs
@@ -223,21 +223,52 @@
             CreateAndCheckoutUpdatability.Add(Updatability.WhenCheckedOut);

         }

 

+        /// <summary>

+        /// Initial default operation context.

+        /// </summary>

         protected static IOperationContext FallbackContext = new OperationContext(null, false, true, false, IncludeRelationships.None, null, true, null, true, 100);

 

+        /// <summary>

+        /// Session parameters

+        /// </summary>

         protected IDictionary<string, string> parameters;

         private object sessionLock = new object();

 

+        /// <value>

+        /// Gets the low-level binding.

+        /// </value>

         public ICmisBinding Binding { get; protected set; }

+

+        /// <value>

+        /// Gets the repository info.

+        /// </value>

         public IRepositoryInfo RepositoryInfo { get; protected set; }

+

+        /// <value>

+        /// Gets the repository ID.

+        /// </value>

         public string RepositoryId { get { return RepositoryInfo.Id; } }

 

         public IObjectFactory ObjectFactory { get; protected set; }

+

+        /// <summary>

+        /// Authentication provider.

+        /// </summary>

         protected IAuthenticationProvider AuthenticationProvider { get; set; }

+

+        /// <summary>

+        /// Object and path cache.

+        /// </summary>

         protected ICache Cache { get; set; }

+

+        /// <summary>

+        /// Indicating if the path cache should be used.

+        /// </summary>

         protected bool cachePathOmit;

 

         private IOperationContext context = FallbackContext;

+

+        /// <inheritdoc/>

         public IOperationContext DefaultContext

         {

             get

@@ -256,6 +287,13 @@
             }

         }

 

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="parameters">the session parameters</param>

+        /// <param name="objectFactory">an object factory, if available</param>

+        /// <param name="authenticationProvider">an authentication provider, if available</param>

+        /// <param name="cache">a cache, if available</param>

         public Session(IDictionary<string, string> parameters, IObjectFactory objectFactory, IAuthenticationProvider authenticationProvider, ICache cache)

         {

             if (parameters == null)

@@ -299,6 +337,10 @@
             }

         }

 

+        /// <summary>

+        /// Create the cache.

+        /// </summary>

+        /// <returns>the cache object</returns>

         protected ICache CreateCache()

         {

             try

@@ -331,6 +373,10 @@
             }

         }

 

+        /// <summary>

+        /// Creates the object factory.

+        /// </summary>

+        /// <returns>the object factory</returns>

         protected IObjectFactory CreateObjectFactory()

         {

             try

diff --git a/PortCMIS/client/ClientIntf.cs b/PortCMIS/client/ClientIntf.cs
index 2e54ba3..714c0b8 100644
--- a/PortCMIS/client/ClientIntf.cs
+++ b/PortCMIS/client/ClientIntf.cs
@@ -135,7 +135,7 @@
         ICmisBinding Binding { get; }

 

         /// <value>

-        /// Gets the default operation context.

+        /// Gets and sets the default operation context.

         /// </value>

         IOperationContext DefaultContext { get; set; }

 

diff --git a/PortCMIS/client/ClientObjects.cs b/PortCMIS/client/ClientObjects.cs
index d5bca43..0a2afcf 100644
--- a/PortCMIS/client/ClientObjects.cs
+++ b/PortCMIS/client/ClientObjects.cs
@@ -847,6 +847,13 @@
     /// </summary>

     public class Document : AbstractFileableCmisObject, IDocument

     {

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="session">the session object</param>

+        /// <param name="objectType">the object type</param>

+        /// <param name="objectData">the low-level data object</param>

+        /// <param name="context">the operation context used to fetch this object</param>

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

         {

             Initialize(session, objectType, objectData, context);

@@ -1255,6 +1262,13 @@
     /// </summary>

     public class Folder : AbstractFileableCmisObject, IFolder

     {

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="session">the session object</param>

+        /// <param name="objectType">the object type</param>

+        /// <param name="objectData">the low-level data object</param>

+        /// <param name="context">the operation context used to fetch this object</param>

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

         {

             Initialize(session, objectType, objectData, context);

@@ -1664,6 +1678,13 @@
     /// </summary>

     public class Policy : AbstractFileableCmisObject, IPolicy

     {

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="session">the session object</param>

+        /// <param name="objectType">the object type</param>

+        /// <param name="objectData">the low-level data object</param>

+        /// <param name="context">the operation context used to fetch this object</param>

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

         {

             Initialize(session, objectType, objectData, context);

@@ -1678,7 +1699,13 @@
     /// </summary>

     public class Relationship : AbstractCmisObject, IRelationship

     {

-

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="session">the session object</param>

+        /// <param name="objectType">the object type</param>

+        /// <param name="objectData">the low-level data object</param>

+        /// <param name="context">the operation context used to fetch this object</param>

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

         {

             Initialize(session, objectType, objectData, context);

@@ -1762,6 +1789,13 @@
     /// </summary>

     public class Item : AbstractFileableCmisObject, IItem

     {

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="session">the session object</param>

+        /// <param name="objectType">the object type</param>

+        /// <param name="objectData">the low-level data object</param>

+        /// <param name="context">the operation context used to fetch this object</param>

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

         {

             Initialize(session, objectType, objectData, context);

@@ -1773,6 +1807,11 @@
     /// </summary>

     public class Property : IProperty

     {

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="propertyDefinition">the property definition</param>

+        /// <param name="values">the property values</param>

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

         {

             PropertyDefinition = propertyDefinition;

@@ -1873,6 +1912,19 @@
         private ISession session;

         private string objectId;

 

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="session">the session objec</param>

+        /// <param name="objectId">the object ID</param>

+        /// <param name="streamId">the stream ID</param>

+        /// <param name="mimeType">the MIME type</param>

+        /// <param name="length">the length in bytes, if known</param>

+        /// <param name="kind">the kind</param>

+        /// <param name="title">the title</param>

+        /// <param name="height">the thumbnail height</param>

+        /// <param name="width">the thumbnail width</param>

+        /// <param name="renditionDocumentId">the ID of the stand-alone rendition document, if it exists</param>

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

             string title, BigInteger? height, BigInteger? width, string renditionDocumentId)

         {

@@ -1923,6 +1975,27 @@
     /// </summary>

     public class ContentStreamHash : IContentStreamHash

     {

+        /// <summary>Algorithm MD5</summary>

+        public const string AlgorithmMD5 = "md5";

+

+        /// <summary>Algorithm sha-1</summary>

+        public const string AlgorithmSHA1 = "sha-1";

+

+        /// <summary>Algorithm sha-224</summary>

+        public const string AlgorithmSHA224 = "sha-224";

+

+        /// <summary>Algorithm sha-256</summary>

+        public const string AlgorithmSHA256 = "sha-256";

+

+        /// <summary>Algorithm sha-384</summary>

+        public const string AlgorithmSHA384 = "sha-384";

+

+        /// <summary>Algorithm sha-512</summary>

+        public const string AlgorithmSHA512 = "sha-512";

+

+        /// <summary>Algorithm sha-3</summary>

+        public const string AlgorithmSHA3 = "sha-3";

+

         /// <inheritdoc/>

         public string PropertyValue { get; protected set; }

 

@@ -1932,6 +2005,10 @@
         /// <inheritdoc/>

         public string Hash { get; protected set; }

 

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="propertyValue">a property value</param>

         public ContentStreamHash(string propertyValue)

         {

             PropertyValue = propertyValue;

@@ -1952,6 +2029,11 @@
             Hash = pv.Substring(algEnd + 1).Replace(" ", "").ToLowerInvariant();

         }

 

+        /// <summary>

+        /// Constructor.

+        /// </summary>

+        /// <param name="algorithm">the algorithm</param>

+        /// <param name="hashStr">the hash string</param>

         public ContentStreamHash(string algorithm, string hashStr)

         {

             if (algorithm == null || algorithm.Trim().Length == 0)

diff --git a/PortCMIS/client/ClientUtils.cs b/PortCMIS/client/ClientUtils.cs
index 7cd11db..03af80d 100644
--- a/PortCMIS/client/ClientUtils.cs
+++ b/PortCMIS/client/ClientUtils.cs
@@ -17,10 +17,12 @@
 * under the License.

 */

 

+using PortCMIS.Data;

 using PortCMIS.Enums;

 using System;

 using System.Collections;

 using System.Collections.Generic;

+using System.IO;

 using System.Numerics;

 using System.Text;

 

@@ -928,6 +930,139 @@
         }

     }

 

+    /// <summary>

+    /// Content Stream helpers.

+    /// </summary>

+    public class ContentStreamUtils

+    {

+        /// <summary>Octet Stream MIME type.</summary>

+        private const string OctetStream = "application/octet-stream";

+

+        private ContentStreamUtils()

+        {

+        }

+

+        /// <summary>

+        /// Creates a content stream object.

+        /// </summary>

+        /// <param name="filename">the filename</param>

+        /// <param name="length">the length</param>

+        /// <param name="mimetype">the MIME type</param>

+        /// <param name="stream">the stream</param>

+        /// <returns>the content stream</returns>

+        public static IContentStream CreateContentStream(string filename, BigInteger? length, string mimetype, Stream stream)

+        {

+            return new ContentStream()

+            {

+                FileName = CheckFilename(filename),

+                Length = length,

+                MimeType = CheckMimeType(mimetype),

+                Stream = stream

+            };

+        }

+

+        // --- byte arrays ---

+

+        /// <summary>

+        /// Creates a content stream object from a byte array.

+        /// </summary>

+        /// <param name="filename">the filename</param>

+        /// <param name="contentBytes">the byte array</param>

+        /// <param name="mimetype">the MIME type</param>

+        /// <returns>the content stream</returns>

+        public static IContentStream CreateByteArrayContentStream(string filename, byte[] contentBytes, string mimetype)

+        {

+            if (contentBytes == null)

+            {

+                return CreateContentStream(filename, null, mimetype, null);

+            }

+

+            return CreateByteArrayContentStream(filename, contentBytes, 0, contentBytes.Length, mimetype);

+        }

+

+        /// <summary>

+        /// Creates a content stream object from a byte array.

+        /// </summary>

+        /// <param name="filename">the filename</param>

+        /// <param name="contentBytes">the byte array</param>

+        /// <param name="index">the begin of the stream in the byte array</param>

+        /// <param name="count">the length of the stream</param>

+        /// <param name="mimetype">the MIME type</param>

+        /// <returns>the content stream</returns>

+        public static IContentStream CreateByteArrayContentStream(string filename, byte[] contentBytes, int index, int count, string mimetype)

+        {

+            if (contentBytes == null)

+            {

+                return CreateContentStream(filename, null, mimetype, null);

+            }

+

+            if (index < 0 || index > contentBytes.Length)

+            {

+                throw new ArgumentOutOfRangeException("index");

+            }

+            else if (count < 0 || (index + count) > contentBytes.Length || (index + count) < 0)

+            {

+                throw new ArgumentOutOfRangeException("count");

+            }

+

+            return CreateContentStream(filename, count, mimetype, new MemoryStream(contentBytes, index, count));

+        }

+

+        // --- strings ---

+

+        /// <summary>

+        /// Creates a content stream object from a string.

+        /// </summary>

+        /// <param name="filename">the filename</param>

+        /// <param name="content">the content</param>

+        /// <returns>the content stream</returns>

+        public static IContentStream CreateTextContentStream(string filename, string content)

+        {

+            return CreateTextContentStream(filename, content, "text/plain; charset=UTF-8");

+        }

+

+        /// <summary>

+        /// Creates a content stream object from a string.

+        /// </summary>

+        /// <param name="filename">the filename</param>

+        /// <param name="content">the content</param>

+        /// <param name="mimetype">the MIME type</param>

+        /// <returns>the content stream</returns>

+        public static IContentStream CreateTextContentStream(string filename, string content, string mimetype)

+        {

+            byte[] contentBytes = Encoding.UTF8.GetBytes(content);

+            return CreateByteArrayContentStream(filename, contentBytes, CheckMimeType(mimetype));

+        }

+

+        // ---

+

+        private static string CheckFilename(string filename)

+        {

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

+            {

+                return "content";

+            }

+

+            return filename;

+        }

+

+        private static string CheckMimeType(string mimetype)

+        {

+            if (mimetype == null)

+            {

+                return OctetStream;

+            }

+

+            string result = mimetype.Trim();

+            if (result.Length < 3)

+            {

+                return OctetStream;

+            }

+

+            return result;

+        }

+    }

+

     internal class StringListBuilder

     {

         private string seperator;

diff --git a/PortCMIS/const/BindingType.cs b/PortCMIS/const/BindingType.cs
index 2559e41..ce13562 100644
--- a/PortCMIS/const/BindingType.cs
+++ b/PortCMIS/const/BindingType.cs
@@ -19,6 +19,9 @@
 

 namespace PortCMIS

 {

+    /// <summary>

+    /// Binding type.

+    /// </summary>

     public static class BindingType

     {

         /// <summary>Binding type AtomPub</summary>

diff --git a/PortCMIS/const/ExtensionFeatures.cs b/PortCMIS/const/ExtensionFeatures.cs
index c65e82a..651ec3d 100644
--- a/PortCMIS/const/ExtensionFeatures.cs
+++ b/PortCMIS/const/ExtensionFeatures.cs
@@ -54,5 +54,18 @@
             VersionLabel = "1.0",

             Description = "Adds the property cmis:contentStreamHash, which represents the hash of the document content."

         };

+

+        /// <summary>

+        /// Latest Accessible State extension.

+        /// </summary>

+        public readonly static IExtensionFeature LatestAccessibleState = new ExtensionFeature()

+        {

+            Id = "http://docs.oasis-open.org/ns/cmis/extension/latestAccessibleState/1.1",

+            Url = "https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=cmis",

+            CommonName = "Latest Accessible State",

+            VersionLabel = "1.1",

+            Description = "This extension provides for an identifier of each cmis:document that retrieves "

+                    + "the latest accessible state of the document whether the document is versioned or not."

+        };

     }

 }

diff --git a/PortCMIS/const/PermissionMappingKeys.cs b/PortCMIS/const/PermissionMappingKeys.cs
index 202bcbd..b45f631 100644
--- a/PortCMIS/const/PermissionMappingKeys.cs
+++ b/PortCMIS/const/PermissionMappingKeys.cs
@@ -19,6 +19,9 @@
 

 namespace PortCMIS

 {

+    /// <summary>

+    /// Keys for permission mappings.

+    /// </summary>

     public static class PermissionMappingKeys

     {

         public const string CanGetDescendentsFolder = "canGetDescendents.Folder";

diff --git a/PortCMIS/data/DataImpl.cs b/PortCMIS/data/DataImpl.cs
index 06da0b5..1e67cfc 100644
--- a/PortCMIS/data/DataImpl.cs
+++ b/PortCMIS/data/DataImpl.cs
@@ -389,7 +389,11 @@
         /// <inheritdoc/>

         public ITypeMutability TypeMutability { get; set; }

 

-        public void Initialize(ITypeDefinition typeDefinition)

+        /// <summary>

+        /// Initializes the type definition object.

+        /// </summary>

+        /// <param name="typeDefinition">the type definition</param>

+        protected void Initialize(ITypeDefinition typeDefinition)

         {

             Id = typeDefinition.Id;

             LocalName = typeDefinition.LocalName;

@@ -414,6 +418,11 @@
                 }

             }

         }

+

+        /// <summary>

+        /// Adds a property type definition.

+        /// </summary>

+        /// <param name="propertyDefinition">the property type definition</param>

         public void AddPropertyDefinition(IPropertyDefinition propertyDefinition)

         {

             if (propertyDefinition == null || propertyDefinition.Id == null)

@@ -424,6 +433,7 @@
             propertyDefintionDict[propertyDefinition.Id] = propertyDefinition;

         }

 

+        /// <inheritdoc/>

         public override string ToString()

         {

             return "TypeDefinition: " + BaseTypeId + " (" + Id + ")";

@@ -572,6 +582,9 @@
         public bool? IsOpenChoice { get; set; }

     }

 

+    /// <summary>

+    /// Choice implementation.

+    /// </summary>

     public class Choice<T> : IChoice<T>

     {

         /// <inheritdoc/>

@@ -584,6 +597,9 @@
         public IList<IChoice<T>> Choices { get; set; }

     }

 

+    /// <summary>

+    /// Boolean property definition implementation.

+    /// </summary>

     public class PropertyBooleanDefinition : PropertyDefinition, IPropertyBooleanDefinition

     {

         /// <inheritdoc/>

@@ -593,6 +609,9 @@
         public IList<IChoice<bool?>> Choices { get; set; }

     }

 

+    /// <summary>

+    /// DataTime property definition implementation.

+    /// </summary>

     public class PropertyDateTimeDefinition : PropertyDefinition, IPropertyDateTimeDefinition

     {

         /// <inheritdoc/>

@@ -605,6 +624,9 @@
         public DateTimeResolution? DateTimeResolution { get; set; }

     }

 

+    /// <summary>

+    /// Decimal property definition implementation.

+    /// </summary>

     public class PropertyDecimalDefinition : PropertyDefinition, IPropertyDecimalDefinition

     {

         /// <inheritdoc/>

@@ -623,6 +645,9 @@
         public DecimalPrecision? Precision { get; set; }

     }

 

+    /// <summary>

+    /// HTML property definition implementation.

+    /// </summary>

     public class PropertyHtmlDefinition : PropertyDefinition, IPropertyHtmlDefinition

     {

         /// <inheritdoc/>

@@ -632,6 +657,9 @@
         public IList<IChoice<string>> Choices { get; set; }

     }

 

+    /// <summary>

+    /// ID property definition implementation.

+    /// </summary>

     public class PropertyIdDefinition : PropertyDefinition, IPropertyIdDefinition

     {

         /// <inheritdoc/>

@@ -641,6 +669,9 @@
         public IList<IChoice<string>> Choices { get; set; }

     }

 

+    /// <summary>

+    /// Integer property definition implementation.

+    /// </summary>

     public class PropertyIntegerDefinition : PropertyDefinition, IPropertyIntegerDefinition

     {

         /// <inheritdoc/>

@@ -656,6 +687,9 @@
         public BigInteger? MaxValue { get; set; }

     }

 

+    /// <summary>

+    /// String property definition implementation.

+    /// </summary>

     public class PropertyStringDefinition : PropertyDefinition, IPropertyStringDefinition

     {

         /// <inheritdoc/>

@@ -668,6 +702,9 @@
         public BigInteger? MaxLength { get; set; }

     }

 

+    /// <summary>

+    /// URI property definition implementation.

+    /// </summary>

     public class PropertyUriDefinition : PropertyDefinition, IPropertyUriDefinition

     {

         /// <inheritdoc/>

diff --git a/PortCMIS/data/DataIntf.cs b/PortCMIS/data/DataIntf.cs
index 2accd2a..9aaea10 100644
--- a/PortCMIS/data/DataIntf.cs
+++ b/PortCMIS/data/DataIntf.cs
@@ -32,166 +32,361 @@
     public interface IRepositoryInfo : IExtensionsData

     {

         /// <value>

-        /// Repository ID.

+        /// Gets the repository ID.

         /// </value>

         string Id { get; }

 

         /// <value>

-        /// Repository Name.

+        /// Gets the repository Name.

         /// </value>

         string Name { get; }

 

         /// <value>

-        /// Repository description.

+        /// Gets the repository description.

         /// </value>

         string Description { get; }

 

         /// <value>

-        /// Repository vendor.

+        /// Gets the repository vendor.

         /// </value>

         string VendorName { get; }

 

         /// <value>

-        /// Repository product name.

+        /// Gets the repository product name.

         /// </value>

         string ProductName { get; }

 

         /// <value>

-        /// Repository product version.

+        /// Gets the repository product version.

         /// </value>

         string ProductVersion { get; }

 

         /// <value>

-        /// Root folder ID.

+        /// Gets the root folder ID.

         /// </value>

         string RootFolderId { get; }

 

         /// <value>

-        /// Repository capabilities.

+        /// Gets the repository capabilities.

         /// </value>

         IRepositoryCapabilities Capabilities { get; }

 

         /// <value>

-        /// Repository ACL capabilities.

+        /// Gets the repository ACL capabilities.

         /// </value>

         IAclCapabilities AclCapabilities { get; }

 

         /// <value>

-        /// Latest change log token.

+        /// Gets the latest change log token.

         /// </value>

         string LatestChangeLogToken { get; }

 

         /// <value>

-        /// CMIS version (string).

+        /// Gets the CMIS version as string.

         /// </value>

         string CmisVersionSupported { get; }

 

         /// <value>

-        /// CMIS version (enum).

+        /// Gets the CMIS version as enum.

         /// </value>

         CmisVersion CmisVersion { get; }

 

         /// <value>

-        /// Repository thin client URI.

+        /// Gets the repository thin client URI.

         /// </value>

         string ThinClientUri { get; }

 

         /// <value>

-        /// Changes incomplete flag.

+        /// Gets the changes incomplete flag.

         /// </value>

         bool? ChangesIncomplete { get; }

 

         /// <value>

-        /// List of changable base types.

+        /// Gets the list of changable base types.

         /// </value>

         IList<BaseTypeId?> ChangesOnType { get; }

 

         /// <value>

-        /// Principal ID of an anonymous user, if supported.

+        /// Gets the principal ID of an anonymous user, if supported.

         /// </value>

         string PrincipalIdAnonymous { get; }

 

         /// <value>

-        /// Principal ID of an unauthenticated user, if supported.

+        /// Gets the principal ID of an unauthenticated user, if supported.

         /// </value>

         string PrincipalIdAnyone { get; }

 

         /// <value>

-        /// List of extension features.

+        /// Gets the list of extension features.

         /// </value>

         IList<IExtensionFeature> ExtensionFeatures { get; }

     }

 

+    /// <summary>

+    /// Repository Capabilities.

+    /// </summary>

     public interface IRepositoryCapabilities : IExtensionsData

     {

+        /// <value>

+        /// Gets the content Stream Updates capability.

+        /// </value>

         CapabilityContentStreamUpdates? ContentStreamUpdatesCapability { get; }

+

+        /// <value>

+        /// Gets the change log capability.

+        /// </value>

         CapabilityChanges? ChangesCapability { get; }

+

+        /// <value>

+        /// Gets the rendition capability.

+        /// </value>

         CapabilityRenditions? RenditionsCapability { get; }

+

+        /// <value>

+        /// Gets whether getDescendants is supported or not.

+        /// </value>

         bool? IsGetDescendantsSupported { get; }

+

+        /// <value>

+        /// Gets whether getFolderTree is supported or not.

+        /// </value>

         bool? IsGetFolderTreeSupported { get; }

+

+        /// <value>

+        /// Gets the OREDER BY capability.

+        /// </value>

         CapabilityOrderBy? OrderByCapability { get; }

+

+        /// <value>

+        /// Gets whether multi-filing is supported or not.

+        /// </value>

         bool? IsMultifilingSupported { get; }

+

+        /// <value>

+        /// Gets whether unfiling is supported or not.

+        /// </value>

         bool? IsUnfilingSupported { get; }

+

+        /// <value>

+        /// Gets whether version specific filing is supported or not.

+        /// </value>

         bool? IsVersionSpecificFilingSupported { get; }

+

+        /// <value>

+        /// Gets whether the PWC is searchable or not.

+        /// </value>

         bool? IsPwcSearchableSupported { get; }

+

+        /// <value>

+        /// Gets whether PWC is updapatable or not.

+        /// </value>

         bool? IsPwcUpdatableSupported { get; }

+

+        /// <value>

+        /// Gets whether query for all versions is supported or not.

+        /// </value>

         bool? IsAllVersionsSearchableSupported { get; }

+

+        /// <value>

+        /// Gets the query capability.

+        /// </value>

         CapabilityQuery? QueryCapability { get; }

+

+        /// <value>

+        /// Gets the Join capability.

+        /// </value>

         CapabilityJoin? JoinCapability { get; }

+

+        /// <value>

+        /// Gets the ACL capability.

+        /// </value>

         CapabilityAcl? AclCapability { get; }

+

+        /// <value>

+        /// Gets which property types are supported for new types.

+        /// </value>

         ICreatablePropertyTypes CreatablePropertyTypes { get; }

+

+        /// <value>

+        /// Gets which attributes can be set on a new type.

+        /// </value>

         INewTypeSettableAttributes NewTypeSettableAttributes { get; }

     }

 

+    /// <summary>

+    /// Property Type that are supported for new types.

+    /// </summary>

     public interface ICreatablePropertyTypes : IExtensionsData

     {

+        /// <value>

+        /// Gets the set of property types that are supported for new types. 

+        /// </value>

         ISet<PropertyType> CanCreate { get; }

     }

 

+    /// <summary>

+    /// Attributes that can be set on new types.

+    /// </summary>

     public interface INewTypeSettableAttributes : IExtensionsData

     {

+        /// <value>

+        /// Gets whether the type ID can be set or not.

+        /// </value>

         bool? CanSetId { get; }

+

+        /// <value>

+        /// Gets whether the local name can be set or not.

+        /// </value>

         bool? CanSetLocalName { get; }

+

+        /// <value>

+        /// Gets whether the local namespace can be set or not.

+        /// </value>

         bool? CanSetLocalNamespace { get; }

+

+        /// <value>

+        /// Gets whether the display name can be set or not.

+        /// </value>

         bool? CanSetDisplayName { get; }

+

+        /// <value>

+        /// Gets whether the query name can be set or not.

+        /// </value>

         bool? CanSetQueryName { get; }

+

+        /// <value>

+        /// Gets whether the description can be set or not.

+        /// </value>

         bool? CanSetDescription { get; }

+

+        /// <value>

+        /// Gets whether the creatable flag can be set or not.

+        /// </value>

         bool? CanSetCreatable { get; }

+

+        /// <value>

+        /// Gets whether the filable flag can be set or not.

+        /// </value>

         bool? CanSetFileable { get; }

+

+        /// <value>

+        /// Gets whether the queryable flag can be set or not.

+        /// </value>

         bool? CanSetQueryable { get; }

+

+        /// <value>

+        /// Gets whether the fulltext flag can be set or not.

+        /// </value>

         bool? CanSetFulltextIndexed { get; }

+

+        /// <value>

+        /// Gets whether the IncludedInSupertype flag can be set or not.

+        /// </value>

         bool? CanSetIncludedInSupertypeQuery { get; }

+

+        /// <value>

+        /// Gets whether the policy control can be set or not.

+        /// </value>

         bool? CanSetControllablePolicy { get; }

+

+        /// <value>

+        /// Gets whether the ACL control can be set or not.

+        /// </value>

         bool? CanSetControllableAcl { get; }

     }

 

+    /// <summary>

+    /// ACL capabilities.

+    /// </summary>

     public interface IAclCapabilities : IExtensionsData

     {

+        /// <value>

+        /// Gets which permission set is supported.

+        /// </value>

         SupportedPermissions? SupportedPermissions { get; }

+

+        /// <value>

+        /// Gets which ACL propagation is supported.

+        /// </value>

         AclPropagation? AclPropagation { get; }

+

+        /// <value>

+        /// Gets permission definitions.

+        /// </value>

         IList<IPermissionDefinition> Permissions { get; }

+

+        /// <value>

+        /// Gets permission mapping.

+        /// </value>

         IDictionary<string, IPermissionMapping> PermissionMapping { get; }

     }

 

+    /// <summary>

+    /// Permission definition.

+    /// </summary>

     public interface IPermissionDefinition : IExtensionsData

     {

+        /// <value>

+        /// Gets the permission ID.

+        /// </value>

         string Id { get; }

+

+        /// <value>

+        /// Gets the description of the permission.

+        /// </value>

         string Description { get; }

     }

 

+    /// <summary>

+    /// Permission mapping.

+    /// </summary>

     public interface IPermissionMapping : IExtensionsData

     {

+        /// <value>

+        /// Gets the permission key.

+        /// </value>

+        /// <seealso cref="PortCMIS.PermissionMappingKeys"/>

         string Key { get; }

+

+        /// <value>

+        /// Gets the required permissions.

+        /// </value>

         IList<string> Permissions { get; }

     }

 

+    /// <summary>

+    /// Extension feature.

+    /// </summary>

     public interface IExtensionFeature : IExtensionsData

     {

+        /// <value>

+        /// Gets the ID of the feature.

+        /// </value>

         string Id { get; }

+

+        /// <value>

+        /// Gets the URL of the feature.

+        /// </value>

         string Url { get; }

+

+        /// <value>

+        /// Gets the name of the feature.

+        /// </value>

         string CommonName { get; }

+

+        /// <value>

+        /// Gets the version label of the feature.

+        /// </value>

         string VersionLabel { get; }

+

+        /// <value>

+        /// Gets the description of the feature.

+        /// </value>

         string Description { get; }

+

+        /// <value>

+        /// Gets a feature specific set of data.

+        /// </value>

         IDictionary<string, string> FeatureData { get; }

     }

 

@@ -736,33 +931,88 @@
     /// </summary>

     public interface IObjectList : IExtensionsData

     {

+        /// <value>

+        /// Gets the list of objects.

+        /// </value>

         IList<IObjectData> Objects { get; }

+

+        /// <value>

+        /// Gets whether there are more objects, if known.

+        /// </value>

         bool? HasMoreItems { get; }

+

+        /// <value>

+        /// Gets total number of objects in the list, if known.

+        /// </value>

         BigInteger? NumItems { get; }

     }

 

+    /// <summary>

+    /// Object in a folder.

+    /// </summary>

     public interface IObjectInFolderData : IExtensionsData

     {

+        /// <value>

+        /// Gets the object.

+        /// </value>

         IObjectData Object { get; }

+

+        /// <value>

+        /// Get the path segment of the object in the folder.

+        /// </value>

         string PathSegment { get; }

     }

 

+    /// <summary>

+    /// List of objects in a folder.

+    /// </summary>

     public interface IObjectInFolderList : IExtensionsData

     {

+        /// <value>

+        /// Gets the list of objects.

+        /// </value>

         IList<IObjectInFolderData> Objects { get; }

+

+        /// <value>

+        /// Gets whether there are more objects, if known.

+        /// </value>

         bool? HasMoreItems { get; }

+

+        /// <value>

+        /// Gets total number of objects in the list, if known.

+        /// </value>

         BigInteger? NumItems { get; }

     }

 

+    /// <summary>

+    /// Tree node of objects in a folder.

+    /// </summary>

     public interface IObjectInFolderContainer : IExtensionsData

     {

+        /// <value>

+        /// Gets the object.

+        /// </value>

         IObjectInFolderData Object { get; }

+

+        /// <value>

+        /// Gets the children of the object, if any.

+        /// </value>

         IList<IObjectInFolderContainer> Children { get; }

     }

 

+    /// <summary>

+    /// Object parent.

+    /// </summary>

     public interface IObjectParentData : IExtensionsData

     {

+        /// <value>

+        /// Gets the parent object.

+        /// </value>

         IObjectData Object { get; }

+

+        /// <value>

+        /// Gets the relative path segment of the object in the parent folder.

+        /// </value>

         string RelativePathSegment { get; }

     }

 

diff --git a/PortCMISTests/SimpleCmisTest.cs b/PortCMISTests/SimpleCmisTest.cs
index 3481314..11568af 100644
--- a/PortCMISTests/SimpleCmisTest.cs
+++ b/PortCMISTests/SimpleCmisTest.cs
@@ -111,26 +111,14 @@
             }

 

             // create folder

-            IDictionary<string, object> props = new Dictionary<string, object>();

-            props[PropertyIds.Name] = "porttest";

-            props[PropertyIds.ObjectTypeId] = "cmis:folder";

-

             IFolder root = Session.GetRootFolder();

-            IFolder newFolder = root.CreateFolder(props);

+            IFolder newFolder = CreateFolder(root, "porttest");

+

             Assert.IsNotNull(newFolder);

 

             // create document

-            props = new Dictionary<string, object>();

-            props[PropertyIds.Name] = "test.txt";

-            props[PropertyIds.ObjectTypeId] = "cmis:document";

-

-            byte[] contentBytes = Encoding.UTF8.GetBytes("Hello World");

-

-            ContentStream content = new ContentStream();

-            content.MimeType = "text/plain";

-            content.Stream = new MemoryStream(contentBytes);

-

-            IDocument newDoc = newFolder.CreateDocument(props, content, VersioningState.None);

+            string contentString = "Hello World";

+            IDocument newDoc = CreateTextDocument(newFolder, "test.txt", contentString);

             Assert.IsNotNull(newDoc);

 

             // get content

@@ -138,16 +126,9 @@
             Assert.IsNotNull(newContent);

             Assert.IsNotNull(newContent.Stream);

 

-            MemoryStream memStream = new MemoryStream();

-            newContent.Stream.CopyTo(memStream);

-            byte[] newContentBytes = memStream.ToArray();

+            Assert.AreEqual(contentString, ConvertStreamToString(newContent.Stream));

 

-            Assert.AreEqual(contentBytes.Length, newContentBytes.Length);

-            for (int i = 0; i < contentBytes.Length; i++)

-            {

-                Assert.AreEqual(contentBytes[i], newContentBytes[i]);

-            }

-

+            // fetch it again to get the updated content stream length property

             IOperationContext ctxt = Session.CreateOperationContext();

             ctxt.FilterString = "*";

             ICmisObject newObj = Session.GetObject(newDoc, ctxt);

@@ -156,7 +137,7 @@
             IDocument newDoc2 = (IDocument)newObj;

 

             Assert.AreEqual(newDoc.Name, newDoc2.Name);

-            Assert.AreEqual(contentBytes.Length, newDoc2.ContentStreamLength);

+            Assert.AreEqual(Encoding.UTF8.GetBytes(contentString).Length, newDoc2.ContentStreamLength);

 

             // delete document

             newDoc.Delete();

@@ -200,12 +181,8 @@
             try

             {

                 // create folder

-                IDictionary<string, object> props = new Dictionary<string, object>();

-                props[PropertyIds.Name] = name1;

-                props[PropertyIds.ObjectTypeId] = "cmis:folder";

-

                 IFolder root = Session.GetRootFolder();

-                newFolder = root.CreateFolder(props);

+                newFolder = CreateFolder(root, name1);

                 Assert.IsNotNull(newFolder);

 

                 IFolder newFolder2 = (IFolder)Session.GetObject(newFolder, oc);

@@ -237,6 +214,45 @@
         }

 

         [TestMethod]

+        public void TestUpdateContent()

+        {

+            IDocument doc = null;

+            try

+            {

+                // create document

+                string contentString1 = "11111";

+                doc = CreateTextDocument(Session.GetRootFolder(), "test.txt", contentString1);

+                Assert.IsNotNull(doc);

+

+                // get content

+                IContentStream content1 = doc.GetContentStream();

+                Assert.IsNotNull(content1);

+                Assert.IsNotNull(content1.Stream);

+

+                Assert.AreEqual(contentString1, ConvertStreamToString(content1.Stream));

+

+                // update content

+                string contentString2 = "22222";

+                doc.SetContentStream(ContentStreamUtils.CreateTextContentStream("test2.txt", contentString2), true);

+

+                // get content again

+                IContentStream content2 = doc.GetContentStream();

+                Assert.IsNotNull(content2);

+                Assert.IsNotNull(content2.Stream);

+

+                Assert.AreEqual(contentString2, ConvertStreamToString(content2.Stream));

+            }

+            finally

+            {

+                if (doc != null)

+                {

+                    doc.Delete();

+                }

+            }

+        }

+

+

+        [TestMethod]

         public void TestQuery()

         {

             if (Session.RepositoryInfo.Capabilities.QueryCapability == CapabilityQuery.None)

diff --git a/PortCMISTests/framework/TestFramework.cs b/PortCMISTests/framework/TestFramework.cs
index c2e429c..3970878 100644
--- a/PortCMISTests/framework/TestFramework.cs
+++ b/PortCMISTests/framework/TestFramework.cs
@@ -18,11 +18,15 @@
 */

 

 using Microsoft.VisualStudio.TestTools.UnitTesting;

+using PortCMIS;

 using PortCMIS.Client;

 using PortCMIS.Client.Impl;

+using PortCMIS.Data;

+using PortCMIS.Enums;

 using PortCMIS.Exceptions;

 using System;

 using System.Collections.Generic;

+using System.IO;

 using System.Linq;

 using System.Text;

 using System.Threading.Tasks;

@@ -87,5 +91,48 @@
 

             return session;

         }

+

+        public IFolder CreateFolder(IFolder parent, string name)

+        {

+            IDictionary<string, object> props = new Dictionary<string, object>();

+            props[PropertyIds.Name] = name;

+            props[PropertyIds.ObjectTypeId] = "cmis:folder";

+

+            return parent.CreateFolder(props);

+        }

+

+        public IDocument CreateTextDocument(IFolder parent, string name, string content)

+        {

+            IDictionary<string, object> props = new Dictionary<string, object>();

+            props[PropertyIds.Name] = name;

+            props[PropertyIds.ObjectTypeId] = "cmis:document";

+

+            IContentStream contentStream = ContentStreamUtils.CreateTextContentStream(name, content);

+

+            return parent.CreateDocument(props, contentStream, VersioningState.None);

+        }

+

+        public byte[] ConvertStreamToByteArray(Stream stream)

+        {

+            MemoryStream memStream = new MemoryStream();

+            stream.CopyTo(memStream);

+            return memStream.ToArray();

+        }

+

+        public string ConvertStreamToString(Stream stream)

+        {

+            return Encoding.UTF8.GetString(ConvertStreamToByteArray(stream));

+        }

+

+        // --- asserts ---

+

+        public void AreEqual(byte[] ba1, byte[] ba2)

+        {

+            Assert.AreEqual(ba1.Length, ba2.Length);

+            for (int i = 0; i < ba1.Length; i++)

+            {

+                Assert.AreEqual(ba1[i], ba2[i]);

+            }

+        }

     }

 }