You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2016/04/27 18:23:31 UTC
svn commit: r1741287 - in /chemistry/portcmis/trunk/PortCMIS:
binding/atompub/AtomPubBinding.cs binding/atompub/AtomPubUtils.cs
binding/atompub/XmlConverter.cs data/DataImpl.cs
Author: fmui
Date: Wed Apr 27 16:23:31 2016
New Revision: 1741287
URL: http://svn.apache.org/viewvc?rev=1741287&view=rev
Log:
PortCMIS: more (untested) AtomPub code
Modified:
chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubBinding.cs
chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubUtils.cs
chemistry/portcmis/trunk/PortCMIS/binding/atompub/XmlConverter.cs
chemistry/portcmis/trunk/PortCMIS/data/DataImpl.cs
Modified: chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubBinding.cs
URL: http://svn.apache.org/viewvc/chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubBinding.cs?rev=1741287&r1=1741286&r2=1741287&view=diff
==============================================================================
--- chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubBinding.cs (original)
+++ chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubBinding.cs Wed Apr 27 16:23:31 2016
@@ -250,7 +250,7 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets a link from the cache if it is there or loads it into the cache if
+ /// Gets a link from the cache if it is there or Loads it into the cache if
/// it is not there.
/// </summary>
public string LoadLink(string repositoryId, string id, string rel, string type)
@@ -267,7 +267,7 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets the content link from the cache if it is there or loads it into the
+ /// Gets the content link from the cache if it is there or Loads it into the
/// cache if it is not there.
/// </summary>
@@ -277,7 +277,7 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets a rendition content link from the cache if it is there or loads it
+ /// Gets a rendition content link from the cache if it is there or Loads it
/// into the cache if it is not there.
/// </summary>
@@ -377,10 +377,10 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets a link from the cache if it is there or loads it into the cache if
+ /// Gets a link from the cache if it is there or Loads it into the cache if
/// it is not there.
/// </summary>
- protected string loadTypeLink(string repositoryId, string typeId, string rel, string type)
+ protected string LoadTypeLink(string repositoryId, string typeId, string rel, string type)
{
string link = GetTypeLink(repositoryId, typeId, rel, type);
if (link == null)
@@ -441,10 +441,10 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets a collection from the cache if it is there or loads it into the
+ /// Gets a collection from the cache if it is there or Loads it into the
/// cache if it is not there.
/// </summary>
- protected string loadCollection(string repositoryId, string collection)
+ protected string LoadCollection(string repositoryId, string collection)
{
string link = GetCollection(repositoryId, collection);
if (link == null)
@@ -474,7 +474,7 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets a repository link from the cache if it is there or loads it into the
+ /// Gets a repository link from the cache if it is there or Loads it into the
/// cache if it is not there.
/// </summary>
protected string LoadRepositoryLink(string repositoryId, string rel)
@@ -515,7 +515,7 @@ namespace PortCMIS.Binding.AtomPub
}
/// <summary>
- /// Gets a template link from the cache if it is there or loads it into the
+ /// Gets a template link from the cache if it is there or Loads it into the
/// cache if it is not there.
/// </summary>
protected string LoadTemplateLink(string repositoryId, string type, Dictionary<string, object> parameters)
@@ -651,7 +651,7 @@ namespace PortCMIS.Binding.AtomPub
protected bool isStr(string name, AtomElement element)
{
- return Matches(name, element) && (element.Object is String);
+ return Matches(name, element) && (element.Object is string);
}
protected bool isInt(string name, AtomElement element)
@@ -667,7 +667,7 @@ namespace PortCMIS.Binding.AtomPub
/// <summary>
/// Creates a CMIS object with properties and policy IDs.
/// </summary>
- protected ObjectData CreateObject(IProperties properties, string changeToken, List<string> policies)
+ protected ObjectData CreateObject(IProperties properties, string changeToken, IList<string> policies)
{
ObjectData obj = new ObjectData();
@@ -829,7 +829,7 @@ namespace PortCMIS.Binding.AtomPub
/// Performs a PUT on an URL, checks the response code and returns the
/// result.
/// </summary>
- protected IResponse Put(UrlBuilder url, Dictionary<string, string> headers, HttpContent content)
+ protected IResponse Put(UrlBuilder url, IDictionary<string, string> headers, HttpContent content)
{
// make the call
IResponse resp = Session.GetHttpInvoker().InvokePUT(url, headers, content, session);
@@ -1190,9 +1190,8 @@ namespace PortCMIS.Binding.AtomPub
/// <summary>
/// Updates the ACL of an object.
/// </summary>
- protected AtomAcl UpdateAcl(string repositoryId, string objectId, IAcl acl, AclPropagation aclPropagation)
+ protected AtomAcl UpdateAcl(string repositoryId, string objectId, IAcl acl, AclPropagation? aclPropagation)
{
-
// find the link
string link = LoadLink(repositoryId, objectId, BindingConstants.RelAcl, BindingConstants.MediaTypeAcl);
@@ -1220,7 +1219,6 @@ namespace PortCMIS.Binding.AtomPub
// parse new entry
return Parse<AtomAcl>(resp.Stream);
}
-
}
internal class RepositoryService : AbstractAtomPubService, IRepositoryService
@@ -1270,11 +1268,11 @@ namespace PortCMIS.Binding.AtomPub
string link = null;
if (typeId == null)
{
- link = loadCollection(repositoryId, BindingConstants.CollectionTypes);
+ link = LoadCollection(repositoryId, BindingConstants.CollectionTypes);
}
else
{
- link = loadTypeLink(repositoryId, typeId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ link = LoadTypeLink(repositoryId, typeId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
}
if (link == null)
@@ -1360,7 +1358,7 @@ namespace PortCMIS.Binding.AtomPub
}
else
{
- link = loadTypeLink(repositoryId, typeId, BindingConstants.RelDown, BindingConstants.MediaTypeDecendants);
+ link = LoadTypeLink(repositoryId, typeId, BindingConstants.RelDown, BindingConstants.MediaTypeDecendants);
}
if (link == null)
@@ -1450,7 +1448,7 @@ namespace PortCMIS.Binding.AtomPub
}
// find the link
- string link = loadTypeLink(repositoryId, parentId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ string link = LoadTypeLink(repositoryId, parentId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
if (link == null)
{
@@ -1692,177 +1690,1222 @@ namespace PortCMIS.Binding.AtomPub
bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
bool? includePathSegment, IExtensionsData extension)
{
- return null;
+ IList<IObjectInFolderContainer> result = new List<IObjectInFolderContainer>();
+
+ // find the link
+ string link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeDecendants);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeEntry);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamDepth, depth);
+ url.AddParameter(BindingConstants.ParamFilter, filter);
+ url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions);
+ url.AddParameter(BindingConstants.ParamRelationships, includeRelationships);
+ url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter);
+ url.AddParameter(BindingConstants.ParamPathSegment, includePathSegment);
+
+ // read and parse
+ IResponse resp = Read(url);
+ AtomFeed feed = Parse<AtomFeed>(resp.Stream);
+
+ // process tree
+ AddDescendantsLevel(repositoryId, feed, result);
+
+ return result;
}
public IList<IObjectInFolderContainer> GetFolderTree(string repositoryId, string folderId, BigInteger? depth, string filter,
bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
bool? includePathSegment, IExtensionsData extension)
{
- return null;
- }
+ IList<IObjectInFolderContainer> result = new List<IObjectInFolderContainer>();
- public IList<IObjectParentData> GetObjectParents(string repositoryId, string objectId, string filter,
- bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
- bool? includeRelativePathSegment, IExtensionsData extension)
- {
- return null;
- }
+ // find the link
+ string link = LoadLink(repositoryId, folderId, BindingConstants.RelFolderTree, BindingConstants.MediaTypeDecendants);
- public IObjectData GetFolderParent(string repositoryId, string folderId, string filter, ExtensionsData extension)
- {
- return null;
- }
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelFolderTree, BindingConstants.MediaTypeEntry);
+ }
- public IObjectList GetCheckedOutDocs(string repositoryId, string folderId, string filter, string orderBy,
- bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
- BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension)
- {
- return null;
- }
- }
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamDepth, depth);
+ url.AddParameter(BindingConstants.ParamFilter, filter);
+ url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions);
+ url.AddParameter(BindingConstants.ParamRelationships, includeRelationships);
+ url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter);
+ url.AddParameter(BindingConstants.ParamPathSegment, includePathSegment);
- internal class ObjectService : AbstractAtomPubService, IObjectService
- {
- public ObjectService(BindingSession session)
- {
- Session = session;
- }
+ // read and parse
+ IResponse resp = Read(url);
+ AtomFeed feed = Parse<AtomFeed>(resp.Stream);
- public string CreateDocument(string repositoryId, IProperties properties, string folderId, IContentStream contentStream,
- VersioningState? versioningState, IList<string> policies, IAcl addAces, IAcl removeAces, IExtensionsData extension)
- {
- return null;
- }
+ // process tree
+ AddDescendantsLevel(repositoryId, feed, result);
- public string CreateDocumentFromSource(string repositoryId, string sourceId, IProperties properties, string folderId,
- VersioningState? versioningState, IList<string> policies, IAcl addAces, IAcl removeAces, IExtensionsData extension)
- {
- throw new CmisNotSupportedException("createDocumentFromSource is not supported by the AtomPub binding!");
+ return result;
}
- public string CreateFolder(string repositoryId, IProperties properties, string folderId, IList<string> policies,
- IAcl addAces, IAcl removeAces, IExtensionsData extension)
+ /// <summary>
+ /// Adds descendants level recursively.
+ /// </summary>
+ private void AddDescendantsLevel(string repositoryId, AtomFeed feed, IList<IObjectInFolderContainer> containerList)
{
- return null;
- }
+ if (feed == null || feed.Entries.Count == 0)
+ {
+ return;
+ }
- public string CreateRelationship(string repositoryId, IProperties properties, IList<string> policies, IAcl addAces,
- IAcl removeAces, IExtensionsData extension)
- {
- return null;
- }
+ // walk through the feed
+ foreach (AtomEntry entry in feed.Entries)
+ {
+ ObjectInFolderData objectInFolder = null;
+ string pathSegment = null;
+ IList<IObjectInFolderContainer> childContainerList = new List<IObjectInFolderContainer>();
- public string CreatePolicy(string repositoryId, IProperties properties, string folderId, IList<string> policies,
- IAcl addAces, IAcl removeAces, IExtensionsData extension)
- {
- return null;
- }
+ LockLinks();
+ try
+ {
+ // clean up cache
+ RemoveLinks(repositoryId, entry.Id);
- public string CreateItem(string repositoryId, IProperties properties, string folderId, IList<string> policies,
- IAcl addAces, IAcl removeAces, IExtensionsData extension)
- {
- return null;
- }
+ // walk through the entry
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ AddLink(repositoryId, entry.Id, (AtomLink)element.Object);
+ }
+ else if (element.Object is IObjectData)
+ {
+ objectInFolder = new ObjectInFolderData() { Object = (IObjectData)element.Object };
+ }
+ else if (isStr(NAME_PATH_SEGMENT, element))
+ {
+ pathSegment = (string)element.Object;
+ }
+ else if (element.Object is AtomFeed)
+ {
+ AddDescendantsLevel(repositoryId, (AtomFeed)element.Object, childContainerList);
+ }
+ }
+ }
+ finally
+ {
+ UnlockLinks();
+ }
- public IAllowableActions GetAllowableActions(string repositoryId, string objectId, IExtensionsData extension)
- {
- return null;
+ if (objectInFolder != null)
+ {
+ objectInFolder.PathSegment = pathSegment;
+ ObjectInFolderContainer childContainer = new ObjectInFolderContainer() { Object = objectInFolder };
+ childContainer.Children = childContainerList;
+ containerList.Add(childContainer);
+ }
+ }
}
- public IProperties GetProperties(string repositoryId, string objectId, string filter, IExtensionsData extension)
+ public IList<IObjectParentData> GetObjectParents(string repositoryId, string objectId, string filter,
+ bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
+ bool? includeRelativePathSegment, IExtensionsData extension)
{
- IObjectData objectData = GetObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.This, filter,
- false, IncludeRelationships.None, "cmis:none", false, false, extension);
+ IList<IObjectParentData> result = new List<IObjectParentData>();
- return objectData.Properties;
- }
-
- public IList<IRenditionData> GetRenditions(string repositoryId, string objectId, string renditionFilter,
- BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension)
- {
- return null;
- }
+ // find the link
+ string link = LoadLink(repositoryId, objectId, BindingConstants.RelUp, BindingConstants.MediaTypeFeed);
- public IObjectData GetObject(string repositoryId, string objectId, string filter, bool? includeAllowableActions,
- IncludeRelationships? includeRelationships, string renditionFilter, bool? includePolicyIds,
- bool? includeAcl, IExtensionsData extension)
- {
- return GetObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.This, filter,
- includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
- }
+ if (link == null)
+ {
+ // root and unfiled objects have no UP link
+ return result;
+ }
- public IObjectData GetObjectByPath(string repositoryId, string path, string filter, bool? includeAllowableActions,
- IncludeRelationships? includeRelationships, string renditionFilter, bool? includePolicyIds, bool? includeAcl,
- IExtensionsData extension)
- {
- return GetObjectInternal(repositoryId, IdentifierType.PATH, path, ReturnVersion.This, filter,
- includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
- }
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamFilter, filter);
+ url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions);
+ url.AddParameter(BindingConstants.ParamRelationships, includeRelationships);
+ url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter);
+ url.AddParameter(BindingConstants.ParamRelativePathSegment, includeRelativePathSegment);
- public IContentStream GetContentStream(string repositoryId, string objectId, string streamId, BigInteger? offset, BigInteger? length,
- IExtensionsData extension)
- {
- return null;
- }
+ // read and parse
+ IResponse resp = Read(url);
- public void UpdateProperties(string repositoryId, ref string objectId, ref string changeToken, IProperties properties,
- IExtensionsData extension)
- {
+ AtomBase atomBase = Parse<AtomBase>(resp.Stream);
- }
+ if (atomBase is AtomFeed)
+ {
+ // it's a feed
+ AtomFeed feed = (AtomFeed)atomBase;
- public IList<IBulkUpdateObjectIdAndChangeToken> BulkUpdateProperties(string repositoryId,
- IList<IBulkUpdateObjectIdAndChangeToken> objectIdAndChangeToken, IProperties properties,
- IList<string> addSecondaryTypeIds, IList<string> removeSecondaryTypeIds, IExtensionsData extension)
- {
- return null;
- }
+ // walk through the feed
+ foreach (AtomEntry entry in feed.Entries)
+ {
+ IObjectParentData objectParent = ProcessParentEntry(entry, repositoryId);
- public void MoveObject(string repositoryId, ref string objectId, string targetFolderId, string sourceFolderId,
- IExtensionsData extension)
- {
+ if (objectParent != null)
+ {
+ result.Add(objectParent);
+ }
+ }
+ }
+ else if (atomBase is AtomEntry)
+ {
+ // it's an entry
+ AtomEntry entry = (AtomEntry)atomBase;
- }
+ IObjectParentData objectParent = ProcessParentEntry(entry, repositoryId);
- public void DeleteObject(string repositoryId, string objectId, bool? allVersions, IExtensionsData extension)
- {
+ if (objectParent != null)
+ {
+ result.Add(objectParent);
+ }
+ }
+ return result;
}
- public IFailedToDeleteData DeleteTree(string repositoryId, string folderId, bool? allVersions, UnfileObject? unfileObjects,
- bool? continueOnFailure, ExtensionsData extension)
+ private ObjectParentData ProcessParentEntry(AtomEntry entry, string repositoryId)
{
- return null;
- }
+ ObjectParentData result = null;
+ string relativePathSegment = null;
- public void SetContentStream(string repositoryId, ref string objectId, bool? overwriteFlag, ref string changeToken,
- IContentStream contentStream, IExtensionsData extension)
- {
+ LockLinks();
+ try
+ {
+ // clean up cache
+ RemoveLinks(repositoryId, entry.Id);
- }
+ // walk through the entry
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ AddLink(repositoryId, entry.Id, (AtomLink)element.Object);
+ }
+ else if (element.Object is ObjectData)
+ {
+ result = new ObjectParentData() { Object = (ObjectData)element.Object };
+ }
+ else if (isStr(NAME_RELATIVE_PATH_SEGMENT, element))
+ {
+ relativePathSegment = (string)element.Object;
+ }
+ }
+ }
+ finally
+ {
+ UnlockLinks();
+ }
- public void DeleteContentStream(string repositoryId, ref string objectId, ref string changeToken, IExtensionsData extension)
- {
+ if (result != null)
+ {
+ result.RelativePathSegment = relativePathSegment;
+ }
+ return result;
}
- public void AppendContentStream(string repositoryId, ref string objectId, bool? isLastChunk, ref string changeToken,
- IContentStream contentStream, IExtensionsData extension)
+ public IObjectData GetFolderParent(string repositoryId, string folderId, string filter, ExtensionsData extension)
{
+ IObjectData result = null;
- }
- }
+ // find the link
+ string link = LoadLink(repositoryId, folderId, BindingConstants.RelUp, BindingConstants.MediaTypeEntry);
- internal class VersioningService : AbstractAtomPubService, IVersioningService
- {
- public VersioningService(BindingSession session)
- {
- Session = session;
- }
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelUp, BindingConstants.MediaTypeEntry);
+ }
- public void CheckOut(string repositoryId, ref string objectId, IExtensionsData extension, out bool? contentCopied)
- {
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamFilter, filter);
+
+ // read
+ IResponse resp = Read(url);
+
+ AtomBase atomBase = Parse<AtomBase>(resp.Stream);
+
+ // get the entry
+ AtomEntry entry = null;
+ if (atomBase is AtomFeed)
+ {
+ AtomFeed feed = (AtomFeed)atomBase;
+ if (feed.Entries.Count == 0)
+ {
+ throw new CmisRuntimeException("Parent feed is empty!");
+ }
+ entry = feed.Entries[0];
+ }
+ else if (atomBase is AtomEntry)
+ {
+ entry = (AtomEntry)atomBase;
+ }
+ else
+ {
+ throw new CmisRuntimeException("Unexpected document!");
+ }
+
+ LockLinks();
+ try
+ {
+ // clean up cache
+ RemoveLinks(repositoryId, entry.Id);
+
+ // walk through the entry
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ AddLink(repositoryId, entry.Id, (AtomLink)element.Object);
+ }
+ else if (element.Object is IObjectData)
+ {
+ result = (IObjectData)element.Object;
+ }
+ }
+ }
+ finally
+ {
+ UnlockLinks();
+ }
+
+ return result;
+ }
+
+ public IObjectList GetCheckedOutDocs(string repositoryId, string folderId, string filter, string orderBy,
+ bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
+ BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension)
+ {
+ ObjectList result = new ObjectList();
+
+ // find the link
+ string link = LoadCollection(repositoryId, BindingConstants.CollectionCheckedout);
+
+ if (link == null)
+ {
+ throw new CmisObjectNotFoundException("Unknown repository or checkedout collection not supported!");
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamFolderId, folderId);
+ url.AddParameter(BindingConstants.ParamFilter, filter);
+ url.AddParameter(BindingConstants.ParamOrderBy, orderBy);
+ url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions);
+ url.AddParameter(BindingConstants.ParamRelationships, includeRelationships);
+ url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter);
+ url.AddParameter(BindingConstants.ParamMaxItems, maxItems);
+ url.AddParameter(BindingConstants.ParamSkipCount, skipCount);
+
+ // read and parse
+ IResponse resp = Read(url);
+ AtomFeed feed = Parse<AtomFeed>(resp.Stream);
+
+ // handle top level
+ foreach (AtomElement element in feed.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ if (isNextLink(element))
+ {
+ result.HasMoreItems = true;
+ }
+ }
+ else if (isInt(NAME_NUM_ITEMS, element))
+ {
+ result.NumItems = (BigInteger)element.Object;
+ }
+ }
+
+ // get the documents
+ if (feed.Entries.Count > 0)
+ {
+ result.Objects = new List<IObjectData>(feed.Entries.Count);
+
+ foreach (AtomEntry entry in feed.Entries)
+ {
+ IObjectData child = null;
+
+ LockLinks();
+ try
+ {
+ // clean up cache
+ RemoveLinks(repositoryId, entry.Id);
+
+ // walk through the entry
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ AddLink(repositoryId, entry.Id, (AtomLink)element.Object);
+ }
+ else if (element.Object is IObjectData)
+ {
+ child = (IObjectData)element.Object;
+ }
+ }
+ }
+ finally
+ {
+ UnlockLinks();
+ }
+
+ if (child != null)
+ {
+ result.Objects.Add(child);
+ }
+ }
+ }
+
+ return result;
+
+ }
+ }
+
+ internal class ObjectService : AbstractAtomPubService, IObjectService
+ {
+ public ObjectService(BindingSession session)
+ {
+ Session = session;
+ }
+
+ public string CreateDocument(string repositoryId, IProperties properties, string folderId, IContentStream contentStream,
+ VersioningState? versioningState, IList<string> policies, IAcl addAces, IAcl removeAces, IExtensionsData extension)
+ {
+ CheckCreateProperties(properties);
+
+ // find the link
+ string link = null;
+
+ if (folderId == null)
+ {
+ // Creation of unfiled objects via AtomPub is not defined in the
+ // CMIS 1.0 specification. This implementation follow the CMIS
+ // 1.1 draft and POSTs the document to the Unfiled collection.
+ link = LoadCollection(repositoryId, BindingConstants.CollectionUnfiled);
+
+ if (link == null)
+ {
+ throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
+ }
+ }
+ else
+ {
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ }
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamVersioningState, versioningState);
+
+ // set up writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(CreateObject(properties, null, policies), GetCmisVersion(repositoryId), contentStream);
+
+ // post the new document object
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ // parse the response
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ // handle ACL modifications
+ HandleAclModifications(repositoryId, entry, addAces, removeAces);
+
+ return entry.Id;
+ }
+
+ public string CreateDocumentFromSource(string repositoryId, string sourceId, IProperties properties, string folderId,
+ VersioningState? versioningState, IList<string> policies, IAcl addAces, IAcl removeAces, IExtensionsData extension)
+ {
+ throw new CmisNotSupportedException("createDocumentFromSource is not supported by the AtomPub binding!");
+ }
+
+ public string CreateFolder(string repositoryId, IProperties properties, string folderId, IList<string> policies,
+ IAcl addAces, IAcl removeAces, IExtensionsData extension)
+ {
+ CheckCreateProperties(properties);
+
+ // find the link
+ string link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+
+ // set up writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(CreateObject(properties, null, policies), GetCmisVersion(repositoryId));
+
+ // post the new folder object
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ // Parse the response
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ // handle ACL modifications
+ HandleAclModifications(repositoryId, entry, addAces, removeAces);
+
+ return entry.Id;
+ }
+
+ public string CreateRelationship(string repositoryId, IProperties properties, IList<string> policies, IAcl addAces,
+ IAcl removeAces, IExtensionsData extension)
+ {
+ CheckCreateProperties(properties);
+
+ // find source id
+ IPropertyData sourceIdProperty = properties[PropertyIds.SourceId];
+ if (sourceIdProperty == null)
+ {
+ throw new CmisInvalidArgumentException("Source Id is not set!");
+ }
+
+ string sourceId = sourceIdProperty.FirstValue as string;
+ if (sourceId == null)
+ {
+ throw new CmisInvalidArgumentException("Source Id is not set!");
+ }
+
+ // find the link
+ string link = LoadLink(repositoryId, sourceId, BindingConstants.RelRelationships, BindingConstants.MediaTypeFeed);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, sourceId, BindingConstants.RelRelationships, BindingConstants.MediaTypeFeed);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+
+ // set up writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(CreateObject(properties, null, policies), GetCmisVersion(repositoryId));
+
+ // post the new relationship object
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ // Parse the response
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ // handle ACL modifications
+ HandleAclModifications(repositoryId, entry, addAces, removeAces);
+
+ return entry.Id;
+ }
+
+ public string CreatePolicy(string repositoryId, IProperties properties, string folderId, IList<string> policies,
+ IAcl addAces, IAcl removeAces, IExtensionsData extension)
+ {
+ CheckCreateProperties(properties);
+
+ // find the link
+ string link = null;
+
+ if (folderId == null)
+ {
+ // Creation of unfiled objects via AtomPub is not defined in the
+ // CMIS 1.0 specification. This implementation follow the CMIS
+ // 1.1 draft and POSTs the policy to the Unfiled collection.
+ link = LoadCollection(repositoryId, BindingConstants.CollectionUnfiled);
+
+ if (link == null)
+ {
+ throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
+ }
+ }
+ else
+ {
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ }
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+
+ // set up writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(CreateObject(properties, null, policies), GetCmisVersion(repositoryId));
+
+ // post the new policy object
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ // parse the response
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ // handle ACL modifications
+ HandleAclModifications(repositoryId, entry, addAces, removeAces);
+
+ return entry.Id;
+ }
+
+ public string CreateItem(string repositoryId, IProperties properties, string folderId, IList<string> policies,
+ IAcl addAces, IAcl removeAces, IExtensionsData extension)
+ {
+ CheckCreateProperties(properties);
+
+ // find the link
+ string link = null;
+
+ if (folderId == null)
+ {
+ link = LoadCollection(repositoryId, BindingConstants.CollectionUnfiled);
+
+ if (link == null)
+ {
+ throw new CmisObjectNotFoundException("Unknown repository or unfiling not supported!");
+ }
+ }
+ else
+ {
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ }
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+
+ // set up writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(CreateObject(properties, null, policies), GetCmisVersion(repositoryId));
+
+ // post the new item object
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ // parse the response
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ // handle ACL modifications
+ HandleAclModifications(repositoryId, entry, addAces, removeAces);
+
+ return entry.Id;
+ }
+
+ private void CheckCreateProperties(IProperties properties)
+ {
+ if (properties == null)
+ {
+ throw new CmisInvalidArgumentException("Properties must be set!");
+ }
+
+ if (properties[PropertyIds.ObjectTypeId] == null)
+ {
+ throw new CmisInvalidArgumentException("Property " + PropertyIds.ObjectTypeId + " must be set!");
+ }
+
+ if (properties[PropertyIds.ObjectId] != null)
+ {
+ throw new CmisInvalidArgumentException("Property " + PropertyIds.ObjectId + " must not be set!");
+ }
+ }
+
+ private void HandleAclModifications(string repositoryId, AtomEntry entry, IAcl addAces, IAcl removeAces)
+ {
+ if (!IsAclMergeRequired(addAces, removeAces))
+ {
+ return;
+ }
+
+ IAcl originalAces = GetAclInternal(repositoryId, entry.Id, false, null);
+
+ if (originalAces != null)
+ {
+ // merge and update ACL
+ IAcl newACL = MergeAcls(originalAces, addAces, removeAces);
+ if (newACL != null)
+ {
+ UpdateAcl(repositoryId, entry.Id, newACL, null);
+ }
+ }
+ }
+
+ public IAllowableActions GetAllowableActions(string repositoryId, string objectId, IExtensionsData extension)
+ {
+ // find the link
+ string link = LoadLink(repositoryId, objectId, BindingConstants.RelAllowableActions, BindingConstants.MediaTypeAllowableAction);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, objectId, BindingConstants.RelAllowableActions, BindingConstants.MediaTypeAllowableAction);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+
+ // read and parse
+ IResponse resp = Read(url);
+ AtomAllowableActions allowableActions = Parse<AtomAllowableActions>(resp.Stream);
+
+ return allowableActions.AllowableActions;
+ }
+
+ public IProperties GetProperties(string repositoryId, string objectId, string filter, IExtensionsData extension)
+ {
+ IObjectData objectData = GetObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.This, filter,
+ false, IncludeRelationships.None, "cmis:none", false, false, extension);
+
+ return objectData.Properties;
+ }
+
+ public IList<IRenditionData> GetRenditions(string repositoryId, string objectId, string renditionFilter,
+ BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension)
+ {
+ IObjectData objectData = GetObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.This,
+ PropertyIds.ObjectId, false, IncludeRelationships.None, renditionFilter, false, false, extension);
+
+ IList<IRenditionData> result = objectData.Renditions;
+ if (result == null)
+ {
+ result = new List<IRenditionData>();
+ }
+
+ return result;
+ }
+
+ public IObjectData GetObject(string repositoryId, string objectId, string filter, bool? includeAllowableActions,
+ IncludeRelationships? includeRelationships, string renditionFilter, bool? includePolicyIds,
+ bool? includeAcl, IExtensionsData extension)
+ {
+ return GetObjectInternal(repositoryId, IdentifierType.ID, objectId, ReturnVersion.This, filter,
+ includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
+ }
+
+ public IObjectData GetObjectByPath(string repositoryId, string path, string filter, bool? includeAllowableActions,
+ IncludeRelationships? includeRelationships, string renditionFilter, bool? includePolicyIds, bool? includeAcl,
+ IExtensionsData extension)
+ {
+ return GetObjectInternal(repositoryId, IdentifierType.PATH, path, ReturnVersion.This, filter,
+ includeAllowableActions, includeRelationships, renditionFilter, includePolicyIds, includeAcl, extension);
+ }
+
+ public IContentStream GetContentStream(string repositoryId, string objectId, string streamId, BigInteger? offset, BigInteger? length,
+ IExtensionsData extension)
+ {
+ // find the link
+ string link = null;
+ if (streamId != null)
+ {
+ // use the alternate link per spec
+ link = LoadLink(repositoryId, objectId, BindingConstants.RelAlternate, streamId);
+ if (link != null)
+ {
+ streamId = null; // we have a full URL now
+ }
+ }
+ if (link == null)
+ {
+ link = LoadLink(repositoryId, objectId, AtomPubParser.LinkRelContent, null);
+ }
+
+ if (link == null)
+ {
+ throw new CmisConstraintException("No content stream");
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ // using the content URL and adding a streamId param is not
+ // spec-compliant
+ url.AddParameter(BindingConstants.ParamStreamId, streamId);
+
+ // get the content
+ IResponse resp = Session.GetHttpInvoker().InvokeGET(url, Session, (long?)offset, (long?)length);
+
+ // check response code
+ if (resp.StatusCode != 200 && resp.StatusCode != 206)
+ {
+ throw ConvertStatusCode(resp.StatusCode, resp.Message, resp.ErrorContent, null);
+ }
+
+ ContentStream result;
+ if (resp.StatusCode == 206)
+ {
+ result = new PartialContentStream();
+ }
+ else
+ {
+ result = new ContentStream();
+ }
+
+ result.Length = resp.ContentLength;
+ result.MimeType = resp.ContentType;
+ result.Stream = resp.Stream;
+
+ return result;
+ }
+
+ public void UpdateProperties(string repositoryId, ref string objectId, ref string changeToken, IProperties properties,
+ IExtensionsData extension)
+ {
+ // we need an object id
+ if (objectId == null || objectId.Length == 0)
+ {
+ throw new CmisInvalidArgumentException("Object ID must be set!");
+ }
+
+ // find the link
+ string link = LoadLink(repositoryId, objectId, BindingConstants.RelSelf, BindingConstants.MediaTypeEntry);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, objectId, BindingConstants.RelSelf, BindingConstants.MediaTypeEntry);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ if (changeToken != null)
+ {
+ if (Session.GetValue(SessionParameter.OmitChangeTokens, false))
+ {
+ changeToken = null;
+ }
+ else
+ {
+ // not required by the CMIS specification -> keep for backwards
+ // compatibility with older OpenCMIS servers
+ url.AddParameter(BindingConstants.ParamChangeToken, changeToken);
+ }
+ }
+
+ // set up writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(CreateObject(properties, changeToken, null), GetCmisVersion(repositoryId));
+
+ // update
+ IResponse resp = Put(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ // parse new entry
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ // we expect a CMIS entry
+ if (entry.Id == null)
+ {
+ throw new CmisConnectionException("Received Atom entry is not a CMIS entry!");
+ }
+
+ // set object id
+ objectId = entry.Id;
+
+ changeToken = null; // just in case
+
+ LockLinks();
+ try
+ {
+ // clean up cache
+ RemoveLinks(repositoryId, entry.Id);
+
+ // walk through the entry
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ AddLink(repositoryId, entry.Id, (AtomLink)element.Object);
+ }
+ else if (element.Object is IObjectData)
+ {
+ // extract new change toke
+ IObjectData objectData = (IObjectData)element.Object;
+
+ if (objectData.Properties != null)
+ {
+ IPropertyData changeTokenStr = objectData.Properties[PropertyIds.ChangeToken];
+ if (changeTokenStr != null)
+ {
+ changeToken = changeTokenStr.FirstValue as string;
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ UnlockLinks();
+ }
+ }
+
+ public IList<IBulkUpdateObjectIdAndChangeToken> BulkUpdateProperties(string repositoryId,
+ IList<IBulkUpdateObjectIdAndChangeToken> objectIdAndChangeToken, IProperties properties,
+ IList<string> addSecondaryTypeIds, IList<string> removeSecondaryTypeIds, IExtensionsData extension)
+ {
+ // find link
+ string link = LoadCollection(repositoryId, BindingConstants.CollectionBulkUpdate);
+
+ if (link == null)
+ {
+ throw new CmisObjectNotFoundException("Unknown repository or bulk update properties is not supported!");
+ }
+
+ // set up writer
+ BulkUpdate bulkUpdate = new BulkUpdate();
+ bulkUpdate.ObjectIdAndChangeToken = objectIdAndChangeToken;
+ bulkUpdate.Properties = properties;
+ bulkUpdate.AddSecondaryTypeIds = addSecondaryTypeIds;
+ bulkUpdate.RemoveSecondaryTypeIds = removeSecondaryTypeIds;
+
+ AtomEntryWriter entryWriter = new AtomEntryWriter(bulkUpdate);
+
+ // post update
+ IResponse resp = Post(new UrlBuilder(link), new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+ AtomFeed feed = Parse<AtomFeed>(resp.Stream);
+ List<IBulkUpdateObjectIdAndChangeToken> result = new List<IBulkUpdateObjectIdAndChangeToken>(feed.Entries.Count);
+
+ // get the results
+ if (feed.Entries.Count > 0)
+ {
+
+ foreach (AtomEntry entry in feed.Entries)
+ {
+ // walk through the entry
+ // we are not interested in the links this time because they
+ // could belong to a new document version
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is IObjectData)
+ {
+ IObjectData objectData = (IObjectData)element.Object;
+ string id = objectData.Id;
+ if (id != null)
+ {
+ string changeToken = null;
+ IPropertyData changeTokenStr = objectData.Properties[PropertyIds.ChangeToken];
+ if (changeTokenStr != null)
+ {
+ changeToken = changeTokenStr.FirstValue as string;
+ }
+
+ result.Add(new BulkUpdateObjectIdAndChangeToken() { Id = id, ChangeToken = changeToken });
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public void MoveObject(string repositoryId, ref string objectId, string targetFolderId, string sourceFolderId,
+ IExtensionsData extension)
+ {
+ if (objectId == null || objectId.Length == 0)
+ {
+ throw new CmisInvalidArgumentException("Object ID must be set!");
+ }
+
+ if (targetFolderId == null || targetFolderId.Length == 0 || sourceFolderId == null || sourceFolderId.Length == 0)
+ {
+ throw new CmisInvalidArgumentException("Source and target folder must be set!");
+ }
+
+ // find the link
+ string link = LoadLink(repositoryId, targetFolderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, targetFolderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamSourceFolderId, sourceFolderId);
+
+ // workaround for SharePoint 2010 - see CMIS-839
+ bool objectIdOnMove = Session.GetValue(SessionParameter.IncludeObjectIdUrlParamOnMove, false);
+ if (objectIdOnMove)
+ {
+ url.AddParameter("objectId", objectId);
+ url.AddParameter("targetFolderId", targetFolderId);
+ }
+
+ // set up object and writer
+ AtomEntryWriter entryWriter = new AtomEntryWriter(createIdObject(objectId), GetCmisVersion(repositoryId));
+
+ // post move request
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ entryWriter.Write(stream);
+ }));
+
+
+ // workaround for SharePoint 2010 - see CMIS-839
+ if (objectIdOnMove)
+ {
+ // SharePoint doesn't return a new object ID
+ // we assume that the object ID hasn't changed
+ return;
+ }
+
+ // parse the response
+ AtomEntry entry = Parse<AtomEntry>(resp.Stream);
+
+ objectId = entry.Id;
+ }
+
+ public void DeleteObject(string repositoryId, string objectId, bool? allVersions, IExtensionsData extension)
+ {
+ // find the link
+ string link = LoadLink(repositoryId, objectId, BindingConstants.RelSelf, BindingConstants.MediaTypeEntry);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, objectId, BindingConstants.RelSelf, BindingConstants.MediaTypeEntry);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamAllVersions, allVersions);
+
+ Delete(url);
+ }
+
+ public IFailedToDeleteData DeleteTree(string repositoryId, string folderId, bool? allVersions, UnfileObject? unfileObjects,
+ bool? continueOnFailure, ExtensionsData extension)
+ {
+ // find the down links
+ string link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, null);
+ string childrenLink = null;
+
+ if (link != null)
+ {
+ // found only a children link, but no descendants link
+ // -> try folder tree link
+ childrenLink = link;
+ link = null;
+ }
+ else
+ {
+ // found no or two down links
+ // -> get only the descendants link
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeDecendants);
+ }
+
+ if (link == null)
+ {
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelFolderTree, BindingConstants.MediaTypeDecendants);
+ }
+
+ if (link == null)
+ {
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelFolderTree, BindingConstants.MediaTypeFeed);
+ }
+
+ if (link == null)
+ {
+ link = childrenLink;
+ }
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeDecendants);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ url.AddParameter(BindingConstants.ParamAllVersions, allVersions);
+ url.AddParameter(BindingConstants.ParamUnfileObjects, unfileObjects);
+ url.AddParameter(BindingConstants.ParamContinueOnFailure, continueOnFailure);
+
+ // make the call
+ IResponse resp = Session.GetHttpInvoker().InvokeDELETE(url, Session);
+
+ // check response code
+ if (resp.StatusCode == 200 || resp.StatusCode == 202 || resp.StatusCode == 204)
+ {
+ return new FailedToDeleteData();
+ }
+
+ // If the server returned an internal server error, get the remaining
+ // children of the folder. We only retrieve the first level, since
+ // getDescendants() is not supported by all repositories.
+ if (resp.StatusCode == 500)
+ {
+ link = LoadLink(repositoryId, folderId, BindingConstants.RelDown, BindingConstants.MediaTypeChildren);
+
+ if (link != null)
+ {
+ url = new UrlBuilder(link);
+ // we only want the object ids
+ url.AddParameter(BindingConstants.ParamFilter, "cmis:objectId");
+ url.AddParameter(BindingConstants.ParamAllowableActions, false);
+ url.AddParameter(BindingConstants.ParamRelationships, IncludeRelationships.None);
+ url.AddParameter(BindingConstants.ParamRenditionfilter, "cmis:none");
+ url.AddParameter(BindingConstants.ParamPathSegment, false);
+ // 1000 children should be enough to indicate a problem
+ url.AddParameter(BindingConstants.ParamMaxItems, 1000);
+ url.AddParameter(BindingConstants.ParamSkipCount, 0);
+
+ // read and parse
+ resp = Read(url);
+ AtomFeed feed = Parse<AtomFeed>(resp.Stream);
+
+ // prepare result
+ FailedToDeleteData result = new FailedToDeleteData();
+ IList<string> ids = new List<string>();
+ result.Ids = ids;
+
+ // get the children ids
+ foreach (AtomEntry entry in feed.Entries)
+ {
+ ids.Add(entry.Id);
+ }
+
+ return result;
+ }
+ }
+
+ throw ConvertStatusCode(resp.StatusCode, resp.Message, resp.ErrorContent, null);
+ }
+
+ public void SetContentStream(string repositoryId, ref string objectId, bool? overwriteFlag, ref string changeToken,
+ IContentStream contentStream, IExtensionsData extension)
+ {
+ SetOrAppendContent(repositoryId, ref objectId, overwriteFlag, ref changeToken, contentStream, true, false, extension);
+ }
+
+ public void DeleteContentStream(string repositoryId, ref string objectId, ref string changeToken, IExtensionsData extension)
+ {
+ // we need an object id
+ if (objectId == null)
+ {
+ throw new CmisInvalidArgumentException("Object ID must be set!");
+ }
+
+ // find the link
+ string link = LoadLink(repositoryId, objectId, BindingConstants.RelEditMedia, null);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, objectId, BindingConstants.RelEditMedia, null);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ if (changeToken != null && !Session.GetValue(SessionParameter.OmitChangeTokens, false))
+ {
+ url.AddParameter(BindingConstants.ParamChangeToken, changeToken);
+ }
+
+ Delete(url);
+
+ objectId = null;
+ changeToken = null;
+ }
+
+ public void AppendContentStream(string repositoryId, ref string objectId, bool? isLastChunk, ref string changeToken,
+ IContentStream contentStream, IExtensionsData extension)
+ {
+ SetOrAppendContent(repositoryId, ref objectId, null, ref changeToken, contentStream, isLastChunk, true, extension);
+ }
+
+ /// <summary>
+ /// Sets or appends content.
+ /// </summary>
+ private void SetOrAppendContent(string repositoryId, ref string objectId, bool? overwriteFlag, ref string changeToken,
+ IContentStream contentStream, bool? isLastChunk, bool append, IExtensionsData extension)
+ {
+ // we need an object id
+ if (objectId == null)
+ {
+ throw new CmisInvalidArgumentException("Object ID must be set!");
+ }
+
+ // we need content
+ if (contentStream == null || contentStream.Stream == null || contentStream.MimeType == null)
+ {
+ throw new CmisInvalidArgumentException("Content must be set!");
+ }
+
+ // find the link
+ string link = LoadLink(repositoryId, objectId, BindingConstants.RelEditMedia, null);
+
+ if (link == null)
+ {
+ ThrowLinkException(repositoryId, objectId, BindingConstants.RelEditMedia, null);
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+ if (changeToken != null && !Session.GetValue(SessionParameter.OmitChangeTokens, false))
+ {
+ url.AddParameter(BindingConstants.ParamChangeToken, changeToken);
+ }
+
+ if (append)
+ {
+ url.AddParameter(BindingConstants.ParamAppend, true);
+ url.AddParameter(BindingConstants.ParamIsLastChunk, isLastChunk);
+ }
+ else
+ {
+ url.AddParameter(BindingConstants.ParamOverwriteFlag, overwriteFlag);
+ }
+
+ Stream content = contentStream.Stream;
+
+ // Content-Disposition header for the filename
+ IDictionary<string, string> headers = null;
+ if (contentStream.FileName != null)
+ {
+ headers = new Dictionary<string, string>();
+ headers.Add(MimeHelper.ContentDisposition,
+ MimeHelper.EncodeContentDisposition(MimeHelper.DispositionAttachment, contentStream.FileName));
+ }
+
+ // send content
+
+ IResponse resp = Put(url, headers, new AtomPubHttpContent(BindingConstants.MediaTypeEntry, (stream) =>
+ {
+ content.CopyTo(stream);
+ }));
+
+ // check response code further
+ if (resp.StatusCode != 200 && resp.StatusCode != 201 && resp.StatusCode != 204)
+ {
+ throw ConvertStatusCode(resp.StatusCode, resp.Message, resp.ErrorContent, null);
+ }
+
+ if (resp.StatusCode == 201)
+ {
+ // unset the object ID if a new resource has been created
+ // (if the resource has been updated (200 and 204), the object ID
+ // hasn't changed)
+ objectId = null;
+ }
+
+ changeToken = null;
+ }
+ }
+
+ internal class VersioningService : AbstractAtomPubService, IVersioningService
+ {
+ public VersioningService(BindingSession session)
+ {
+ Session = session;
+ }
+
+ public void CheckOut(string repositoryId, ref string objectId, IExtensionsData extension, out bool? contentCopied)
+ {
contentCopied = false;
}
@@ -1909,7 +2952,83 @@ namespace PortCMIS.Binding.AtomPub
bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter,
BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension)
{
- return null;
+ ObjectList result = new ObjectList();
+
+ // find the link
+ string link = LoadCollection(repositoryId, BindingConstants.CollectionQuery);
+
+ if (link == null)
+ {
+ throw new CmisObjectNotFoundException("Unknown repository or query not supported!");
+ }
+
+ UrlBuilder url = new UrlBuilder(link);
+
+ // compile query request
+ QueryType query = new QueryType();
+ query.Statement = statement;
+ query.SearchAllVersions = searchAllVersions;
+ query.IncludeAllowableActions = includeAllowableActions;
+ query.IncludeRelationships = includeRelationships;
+ query.RenditionFilter = renditionFilter;
+ query.MaxItems = maxItems;
+ query.SkipCount = skipCount;
+
+ CmisVersion cmisVersion = GetCmisVersion(repositoryId);
+
+ // post the query and parse results
+ IResponse resp = Post(url, new AtomPubHttpContent(BindingConstants.MediaTypeQuery, (stream) =>
+ {
+ XmlWriter writer = XmlUtils.createWriter(stream);
+ XmlUtils.StartXmlDocument(writer);
+ XmlConverter.writeQuery(writer, cmisVersion, query);
+ XmlUtils.EndXmlDocument(writer);
+ }));
+
+ AtomFeed feed = Parse<AtomFeed>(resp.Stream);
+
+ // handle top level
+ foreach (AtomElement element in feed.Elements)
+ {
+ if (element.Object is AtomLink)
+ {
+ if (isNextLink(element))
+ {
+ result.HasMoreItems = true;
+ }
+ }
+ else if (isInt(NAME_NUM_ITEMS, element))
+ {
+ result.NumItems = (BigInteger)element.Object;
+ }
+ }
+
+ // get the result set
+ if (feed.Entries.Count > 0)
+ {
+ result.Objects = new List<IObjectData>(feed.Entries.Count);
+
+ foreach (AtomEntry entry in feed.Entries)
+ {
+ IObjectData hit = null;
+
+ // walk through the entry
+ foreach (AtomElement element in entry.Elements)
+ {
+ if (element.Object is IObjectData)
+ {
+ hit = (IObjectData)element.Object;
+ }
+ }
+
+ if (hit != null)
+ {
+ result.Objects.Add(hit);
+ }
+ }
+ }
+
+ return result;
}
public IObjectList GetContentChanges(string repositoryId, ref string changeLogToken, bool? includeProperties,
Modified: chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubUtils.cs
URL: http://svn.apache.org/viewvc/chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubUtils.cs?rev=1741287&r1=1741286&r2=1741287&view=diff
==============================================================================
--- chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubUtils.cs (original)
+++ chemistry/portcmis/trunk/PortCMIS/binding/atompub/AtomPubUtils.cs Wed Apr 27 16:23:31 2016
@@ -1182,7 +1182,7 @@ namespace PortCMIS.Binding.AtomPub
/// <summary>
/// Constructor for objects.
/// </summary>
- public AtomEntryWriter(ObjectData objectData, CmisVersion cmisVersion)
+ public AtomEntryWriter(IObjectData objectData, CmisVersion cmisVersion)
: this(objectData, cmisVersion, null)
{
}
@@ -1190,7 +1190,7 @@ namespace PortCMIS.Binding.AtomPub
/// <summary>
/// Constructor for objects.
/// </summary>
- public AtomEntryWriter(ObjectData objectData, CmisVersion cmisVersion, ContentStream contentStream)
+ public AtomEntryWriter(IObjectData objectData, CmisVersion cmisVersion, IContentStream contentStream)
{
if (objectData == null || objectData.Properties == null)
{
@@ -1386,7 +1386,10 @@ namespace PortCMIS.Binding.AtomPub
public AtomPubHttpContent(string contentType, Action<Stream> writeAction)
: base()
{
- this.Headers.ContentType = new MediaTypeHeaderValue(contentType) { CharSet = Encoding.UTF8.WebName };
+ MediaTypeHeaderValue contentTypeHeader = MediaTypeHeaderValue.Parse(contentType);
+ contentTypeHeader.CharSet = Encoding.UTF8.WebName;
+
+ this.Headers.ContentType = contentTypeHeader;
this.writeAction = writeAction;
}
Modified: chemistry/portcmis/trunk/PortCMIS/binding/atompub/XmlConverter.cs
URL: http://svn.apache.org/viewvc/chemistry/portcmis/trunk/PortCMIS/binding/atompub/XmlConverter.cs?rev=1741287&r1=1741286&r2=1741287&view=diff
==============================================================================
--- chemistry/portcmis/trunk/PortCMIS/binding/atompub/XmlConverter.cs (original)
+++ chemistry/portcmis/trunk/PortCMIS/binding/atompub/XmlConverter.cs Wed Apr 27 16:23:31 2016
@@ -919,31 +919,31 @@ namespace PortCMIS.Binding.AtomPub
case PropertyType.Id:
case PropertyType.Html:
case PropertyType.Uri:
- foreach (string value in (IList<string>)source.Values)
+ foreach (string value in source.Values.Cast<string>())
{
XmlUtils.Write(writer, XmlConstants.PREFIX_CMIS, XmlConstants.NAMESPACE_CMIS, XmlConstants.TAG_PROPERTY_VALUE, value);
}
break;
case PropertyType.Integer:
- foreach (BigInteger value in (IList<BigInteger>)source.Values)
+ foreach (BigInteger value in source.Values.Cast<BigInteger>())
{
XmlUtils.Write(writer, XmlConstants.PREFIX_CMIS, XmlConstants.NAMESPACE_CMIS, XmlConstants.TAG_PROPERTY_VALUE, value);
}
break;
case PropertyType.Boolean:
- foreach (bool value in (IList<bool>)source.Values)
+ foreach (bool value in source.Values.Cast<bool>())
{
XmlUtils.Write(writer, XmlConstants.PREFIX_CMIS, XmlConstants.NAMESPACE_CMIS, XmlConstants.TAG_PROPERTY_VALUE, value);
}
break;
case PropertyType.DateTime:
- foreach (DateTime value in (IList<DateTime>)source.Values)
+ foreach (DateTime value in source.Values.Cast<DateTime>())
{
XmlUtils.Write(writer, XmlConstants.PREFIX_CMIS, XmlConstants.NAMESPACE_CMIS, XmlConstants.TAG_PROPERTY_VALUE, value);
}
break;
case PropertyType.Decimal:
- foreach (decimal value in (IList<decimal>)source.Values)
+ foreach (decimal value in source.Values.Cast<decimal>())
{
XmlUtils.Write(writer, XmlConstants.PREFIX_CMIS, XmlConstants.NAMESPACE_CMIS, XmlConstants.TAG_PROPERTY_VALUE, value);
}
@@ -1107,7 +1107,7 @@ namespace PortCMIS.Binding.AtomPub
if (bulkUpdate.Properties != null)
{
- Properties properties = bulkUpdate.Properties;
+ IProperties properties = bulkUpdate.Properties;
writer.WriteStartElement(XmlConstants.PREFIX_CMIS, XmlConstants.TAG_BULK_UPDATE_PROPERTIES, XmlConstants.NAMESPACE_CMIS);
if (properties.PropertyList != null)
Modified: chemistry/portcmis/trunk/PortCMIS/data/DataImpl.cs
URL: http://svn.apache.org/viewvc/chemistry/portcmis/trunk/PortCMIS/data/DataImpl.cs?rev=1741287&r1=1741286&r2=1741287&view=diff
==============================================================================
--- chemistry/portcmis/trunk/PortCMIS/data/DataImpl.cs (original)
+++ chemistry/portcmis/trunk/PortCMIS/data/DataImpl.cs Wed Apr 27 16:23:31 2016
@@ -1103,12 +1103,12 @@ namespace PortCMIS.Data
public class QueryType : ExtensionsData
{
public string Statement { get; set; }
- public bool SearchAllVersions { get; set; }
- public bool IncludeAllowableActions { get; set; }
- public IncludeRelationships IncludeRelationships { get; set; }
+ public bool? SearchAllVersions { get; set; }
+ public bool? IncludeAllowableActions { get; set; }
+ public IncludeRelationships? IncludeRelationships { get; set; }
public string RenditionFilter { get; set; }
- public BigInteger MaxItems { get; set; }
- public BigInteger SkipCount { get; set; }
+ public BigInteger? MaxItems { get; set; }
+ public BigInteger? SkipCount { get; set; }
}
public class BulkUpdateObjectIdAndChangeToken : ExtensionsData, IBulkUpdateObjectIdAndChangeToken
@@ -1126,7 +1126,7 @@ namespace PortCMIS.Data
internal class BulkUpdate : ExtensionsData
{
public IList<IBulkUpdateObjectIdAndChangeToken> ObjectIdAndChangeToken { get; set; }
- public Properties Properties { get; set; }
+ public IProperties Properties { get; set; }
public IList<string> AddSecondaryTypeIds { get; set; }
public IList<string> RemoveSecondaryTypeIds { get; set; }
}