PortCMIS: ported a few features from OpenCMIS

git-svn-id: https://svn.apache.org/repos/asf/chemistry/portcmis/trunk@1789499 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/PortCMIS/binding/atompub/AtomPubBinding.cs b/PortCMIS/binding/atompub/AtomPubBinding.cs
index c812773..41f6de8 100644
--- a/PortCMIS/binding/atompub/AtomPubBinding.cs
+++ b/PortCMIS/binding/atompub/AtomPubBinding.cs
@@ -3129,6 +3129,30 @@
         {

             ReturnVersion returnVersion = (major == true ? ReturnVersion.LatestMajor : ReturnVersion.Latest);

 

+            // workaround for SharePoint - use the version series ID instead of the object ID

+            if (Session.GetValue(SessionParameter.LatestVersionWithVersionSeriesId, false))

+            {

+                if (versionSeriesId != null)

+                {

+                    objectId = versionSeriesId;

+                }

+                else

+                {

+                    IObjectData obj = GetObjectInternal(repositoryId, IdentifierType.ID, objectId, null,

+                            PropertyIds.ObjectId + "," + PropertyIds.VersionSeriesId, false,

+                            IncludeRelationships.None, "cmis:none", false, false, extension);

+

+                    if (obj.Properties != null)

+                    {

+                        IPropertyData versionSeriesProp = obj.Properties[PropertyIds.VersionSeriesId];

+                        if (versionSeriesProp != null && versionSeriesProp.FirstValue is string)

+                        {

+                            objectId = (string)versionSeriesProp.FirstValue;

+                        }

+                    }

+                }

+            }

+

             return GetObjectInternal(repositoryId, IdentifierType.ID, objectId, returnVersion, filter,

                     includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);

         }

diff --git a/PortCMIS/client/ClientIntf.cs b/PortCMIS/client/ClientIntf.cs
index 8fea575..4ab089a 100644
--- a/PortCMIS/client/ClientIntf.cs
+++ b/PortCMIS/client/ClientIntf.cs
@@ -1661,11 +1661,18 @@
         void RemovePolicy(params IObjectId[] policyId);

 

         /// <summary>

-        /// Gets a list of policies applied to this object.

+        /// Returns the applied policies if they have been fetched for this object.

+        /// This method fetches the policy objects from the repository when this method is called for the first time. Policy objects that don't exist are ignored.

         /// </summary>

         IList<IPolicy> Policies { get; }

 

         /// <summary>

+        /// Returns the applied policy IDs if they have been fetched for this object.

+        /// All applied policy IDs are returned, even IDs of policies that don't exist.

+        /// </summary>

+        IList<string> PolicyIds { get; }

+

+        /// <summary>

         /// Adds and removes ACEs to this object.

         /// </summary>

         /// <returns>the new ACL of this object</returns>

@@ -1773,6 +1780,11 @@
         bool? IsLatestMajorVersion { get; }

 

         /// <value>

+        /// Gets if this CMIS object is the PWC (CMIS property <c>cmis:isPrivateWorkingCopy</c>).

+        /// </value>

+        bool? IsPrivateWorkingCopy { get; }

+

+        /// <value>

         /// Gets the version label (CMIS property <c>cmis:versionLabel</c>).

         /// </value>

         string VersionLabel { get; }

@@ -1826,6 +1838,11 @@
         /// Gets the content stream hashes or <c>null</c> if the document has no content or the repository hasn't provided content hashes (CMIS property <c>cmis:contentStreamHash</c>).

         /// </value>

         IList<IContentStreamHash> ContentStreamHashes { get; }

+

+        /// <value>

+        /// Gets the latest accessible state ID (CMIS property <c>cmis:latestAccessibleStateId</c>).

+        /// </value>

+        string LatestAccessibleStateId { get; }

     }

 

     /// <summary>

@@ -1834,6 +1851,22 @@
     public interface IDocument : IFileableCmisObject, IDocumentProperties

     {

         /// <summary>

+        /// Returns the object type as a document type.

+        /// </summary>

+        IDocumentType DocumentType { get; }

+

+        /// <summary>

+        /// Returns whether the document is versionable or not.

+        /// </summary>

+        bool IsVersionable { get; }

+

+        /// <summary>

+        /// Determines whether this document is the PWC in the version series or not.

+        /// </summary>

+        /// <returns> <c>true</c> if it is the PWC, <c>false</c> if it is not the PWC, or <c>null</c> if it can't be determined</returns>

+        bool? IsVersionSeriesPrivateWorkingCopy { get; }

+

+        /// <summary>

         /// Deletes all versions of this document.

         /// </summary>

         void DeleteAllVersions();

@@ -2006,6 +2039,11 @@
     public interface IFolder : IFileableCmisObject, IFolderProperties

     {

         /// <summary>

+        /// Returns the object type as a folder type.

+        /// </summary>

+        IFolderType FolderType { get; }

+

+        /// <summary>

         /// Creates a new document in this folder.

         /// </summary>

         /// <returns>the new document object</returns>

@@ -2184,6 +2222,10 @@
     /// </summary>

     public interface IPolicy : IFileableCmisObject, IPolicyProperties

     {

+        /// <summary>

+        /// Returns the object type as a policy type.

+        /// </summary>

+        IPolicyType PolicyType { get; }

     }

 

     /// <summary>

@@ -2208,6 +2250,11 @@
     public interface IRelationship : ICmisObject, IRelationshipProperties

     {

         /// <summary>

+        /// Returns the object type as a relationship type.

+        /// </summary>

+        IRelationshipType RelationshipType { get; }

+

+        /// <summary>

         /// Gets the relationship source object.

         /// </summary>

         /// <remarks>

@@ -2252,6 +2299,10 @@
     /// </summary>

     public interface IItem : IFileableCmisObject, ItemProperties

     {

+        /// <summary>

+        /// Returns the object type as an item type.

+        /// </summary>

+        IItemType ItemType { get; }

     }

 

     /// <summary>

diff --git a/PortCMIS/client/ClientObjects.cs b/PortCMIS/client/ClientObjects.cs
index 7c42c53..cc5ba4c 100644
--- a/PortCMIS/client/ClientObjects.cs
+++ b/PortCMIS/client/ClientObjects.cs
@@ -101,6 +101,7 @@
         private IAllowableActions allowableActions;

         private IList<IRendition> renditions;

         private IAcl acl;

+        private IList<string> policyIds;

         private IList<IPolicy> policies;

         private IList<IRelationship> relationships;

         private IDictionary<ExtensionLevel, IList<ICmisExtensionElement>> extensions;

@@ -231,22 +232,22 @@
                 }

 

                 // handle policies

+                policies = null;

                 if (objectData.PolicyIds != null && objectData.PolicyIds.PolicyIds != null)

                 {

-                    policies = new List<IPolicy>();

-                    foreach (string pid in objectData.PolicyIds.PolicyIds)

+                    if (objectData.PolicyIds.PolicyIds.Count == 0)

                     {

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

-                        if (policy != null)

-                        {

-                            policies.Add(policy);

-                        }

+                        policyIds = null;

+                    }

+                    else

+                    {

+                        policyIds = objectData.PolicyIds.PolicyIds;

                     }

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

                 }

                 else

                 {

-                    policies = null;

+                    policyIds = null;

                 }

 

                 // handle relationships

@@ -644,11 +645,47 @@
             {

                 lock (objectLock)

                 {

+                    if (policies != null || policyIds == null)

+                    {

+                        return policies;

+                    }

+

+                    policies = new List<IPolicy>();

+                    foreach (string pid in policyIds)

+                    {

+                        try

+                        {

+                            ICmisObject policy = Session.GetObject(pid);

+

+                            if (policy is IPolicy)

+                            {

+                                policies.Add((IPolicy)policy);

+                            }

+                        }

+                        catch (CmisObjectNotFoundException)

+                        {

+                            // ignore

+                        }

+                    }

+

                     return policies;

                 }

             }

         }

 

+        /// <inheritdoc/>

+        public virtual IList<string> PolicyIds

+        {

+            get

+            {

+                lock (objectLock)

+                {

+                    return policyIds;

+                }

+            }

+        }

+

+

         // --- relationships ---

 

         /// <inheritdoc/>

@@ -886,6 +923,64 @@
             Initialize(session, objectType, objectData, context);

         }

 

+        /// <inheritdoc/>

+        public virtual IDocumentType DocumentType

+        {

+            get

+            {

+                if (ObjectType is IDocumentType)

+                {

+                    return (IDocumentType)ObjectType;

+                }

+                else

+                {

+                    throw new InvalidCastException("Object type is not a document type.");

+                }

+            }

+        }

+

+        /// <inheritdoc/>

+        public virtual bool IsVersionable

+        {

+            get

+            {

+                return DocumentType.IsVersionable == true;

+            }

+        }

+

+        /// <inheritdoc/>

+        public virtual bool? IsVersionSeriesPrivateWorkingCopy

+        {

+            get

+            {

+                if (DocumentType.IsVersionable == false)

+                {

+                    return false;

+                }

+

+                if (IsVersionSeriesCheckedOut == false)

+                {

+                    return false;

+                }

+

+                bool? isPWC = IsPrivateWorkingCopy;

+                if (isPWC != null)

+                {

+                    return isPWC;

+                }

+

+                string vsCoId = VersionSeriesCheckedOutId;

+                if (vsCoId == null)

+                {

+                    // we don't know ...

+                    return null;

+                }

+

+                return vsCoId == Id;

+            }

+        }

+

+

         // properties

 

         /// <inheritdoc/>

@@ -901,6 +996,9 @@
         public virtual bool? IsLatestMajorVersion { get { return GetPropertyAsBoolValue(PropertyIds.IsLatestMajorVersion); } }

 

         /// <inheritdoc/>

+        public virtual bool? IsPrivateWorkingCopy { get { return GetPropertyAsBoolValue(PropertyIds.IsPrivateWorkingCopy); } }

+

+        /// <inheritdoc/>

         public virtual string VersionLabel { get { return GetPropertyAsStringValue(PropertyIds.VersionLabel); } }

 

         /// <inheritdoc/>

@@ -931,6 +1029,9 @@
         public virtual string ContentStreamId { get { return GetPropertyAsStringValue(PropertyIds.ContentStreamId); } }

 

         /// <inheritdoc/>

+        public virtual string LatestAccessibleStateId { get { return GetPropertyAsStringValue(PropertyIds.LatestAccessibleStateId); } }

+

+        /// <inheritdoc/>

         public virtual IList<IContentStreamHash> ContentStreamHashes

         {

             get

@@ -1364,6 +1465,22 @@
         }

 

         /// <inheritdoc/>

+        public virtual IFolderType FolderType

+        {

+            get

+            {

+                if (ObjectType is IFolderType)

+                {

+                    return (IFolderType)ObjectType;

+                }

+                else

+                {

+                    throw new InvalidCastException("Object type is not a folder type.");

+                }

+            }

+        }

+

+        /// <inheritdoc/>

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

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

         {

@@ -1518,7 +1635,7 @@
             IObjectFactory of = Session.ObjectFactory;

             IOperationContext ctxt = new OperationContext(context);

 

-            PageFetcher<IDocument>.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount)

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

             {

                 // get checked out documents for this folder

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

@@ -1561,7 +1678,7 @@
             IObjectFactory of = Session.ObjectFactory;

             IOperationContext ctxt = new OperationContext(context);

 

-            PageFetcher<ICmisObject>.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount)

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

             {

                 // get the children

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

@@ -1780,6 +1897,22 @@
         }

 

         /// <inheritdoc/>

+        public virtual IPolicyType PolicyType

+        {

+            get

+            {

+                if (ObjectType is IPolicyType)

+                {

+                    return (IPolicyType)ObjectType;

+                }

+                else

+                {

+                    throw new InvalidCastException("Object type is not a policy type.");

+                }

+            }

+        }

+

+        /// <inheritdoc/>

         public virtual string PolicyText { get { return GetPropertyAsStringValue(PropertyIds.PolicyText); } }

     }

 

@@ -1801,6 +1934,22 @@
         }

 

         /// <inheritdoc/>

+        public virtual IRelationshipType RelationshipType

+        {

+            get

+            {

+                if (ObjectType is IRelationshipType)

+                {

+                    return (IRelationshipType)ObjectType;

+                }

+                else

+                {

+                    throw new InvalidCastException("Object type is not a relationship type.");

+                }

+            }

+        }

+

+        /// <inheritdoc/>

         public virtual ICmisObject GetSource()

         {

             return GetSource(Session.DefaultContext);

@@ -1889,6 +2038,22 @@
         {

             Initialize(session, objectType, objectData, context);

         }

+

+        /// <inheritdoc/>

+        public virtual IItemType ItemType

+        {

+            get

+            {

+                if (ObjectType is IItemType)

+                {

+                    return (IItemType)ObjectType;

+                }

+                else

+                {

+                    throw new InvalidCastException("Object type is not an item type.");

+                }

+            }

+        }

     }

 

     /// <summary>

diff --git a/PortCMIS/client/SessionParameter.cs b/PortCMIS/client/SessionParameter.cs
index cc5e303..06fbb52 100644
--- a/PortCMIS/client/SessionParameter.cs
+++ b/PortCMIS/client/SessionParameter.cs
@@ -144,5 +144,9 @@
         /// <summary>Defines if the document name should be added to the properties on check in if no properties are updated

         /// (Workaround for SharePoint 2010 and SharePoint 2013)</summary>

         public const string AddNameOnCheckIn = "org.apache.chemistry.portcmis.workaround.addNameOnCheckIn";

+

+        /// <summary>Defines if getObjectOfLatestVersion should use the version series ID instead of the object ID

+        /// (Workaround for SharePoint 2010 and SharePoint 2013)</summary>

+        public const string LatestVersionWithVersionSeriesId = "org.apache.chemistry.portcmis.workaround.getLatestVersionWithVersionSeriesId";

     }

 }
\ No newline at end of file
diff --git a/PortCMISTests/SimpleCmisTest.cs b/PortCMISTests/SimpleCmisTest.cs
index a631f43..fa43b59 100644
--- a/PortCMISTests/SimpleCmisTest.cs
+++ b/PortCMISTests/SimpleCmisTest.cs
@@ -332,6 +332,7 @@
 

                 IObjectId pwcId = doc.CheckOut();

                 IDocument pwc = (IDocument)Session.GetObject(pwcId, noCacheOC);

+                Assert.AreEqual(true, pwc.IsPrivateWorkingCopy);

 

                 pwc.Rename(name2);