/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Threading; | |
using DotCMIS.Binding; | |
using DotCMIS.Binding.Services; | |
using DotCMIS.Data; | |
using DotCMIS.Data.Extensions; | |
using DotCMIS.Data.Impl; | |
using DotCMIS.Enums; | |
using DotCMIS.Exceptions; | |
namespace DotCMIS.Client.Impl | |
{ | |
/// <summary> | |
/// CMIS object base class. | |
/// </summary> | |
public abstract class AbstractCmisObject : ICmisObject | |
{ | |
protected ISession Session { get; private set; } | |
protected string RepositoryId { get { return Session.RepositoryInfo.Id; } } | |
protected ICmisBinding Binding { get { return Session.Binding; } } | |
private IObjectType objectType; | |
public IObjectType ObjectType | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return objectType; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
protected string ObjectId | |
{ | |
get | |
{ | |
string objectId = Id; | |
if (objectId == null) | |
{ | |
throw new CmisRuntimeException("Object Id is unknown!"); | |
} | |
return objectId; | |
} | |
} | |
protected IOperationContext CreationContext { get; private set; } | |
private IDictionary<string, IProperty> properties; | |
private IAllowableActions allowableActions; | |
private IList<IRendition> renditions; | |
private IAcl acl; | |
private IList<IPolicy> policies; | |
private IList<IRelationship> relationships; | |
private IDictionary<ExtensionLevel, IList<ICmisExtensionElement>> extensions; | |
private object objectLock = new object(); | |
protected void Initialize(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context) | |
{ | |
if (session == null) | |
{ | |
throw new ArgumentNullException("session"); | |
} | |
if (objectType == null) | |
{ | |
throw new ArgumentNullException("objectType"); | |
} | |
if (objectType.PropertyDefinitions == null || objectType.PropertyDefinitions.Count < 9) | |
{ | |
// there must be at least the 9 standard properties that all objects have | |
throw new ArgumentException("Object type must have property defintions!"); | |
} | |
this.Session = session; | |
this.objectType = objectType; | |
this.extensions = new Dictionary<ExtensionLevel, IList<ICmisExtensionElement>>(); | |
this.CreationContext = new OperationContext(context); | |
this.RefreshTimestamp = DateTime.UtcNow; | |
IObjectFactory of = Session.ObjectFactory; | |
if (objectData != null) | |
{ | |
// handle properties | |
if (objectData.Properties != null) | |
{ | |
properties = of.ConvertProperties(objectType, objectData.Properties); | |
extensions[ExtensionLevel.Properties] = objectData.Properties.Extensions; | |
} | |
// handle allowable actions | |
if (objectData.AllowableActions != null) | |
{ | |
allowableActions = objectData.AllowableActions; | |
extensions[ExtensionLevel.AllowableActions] = objectData.AllowableActions.Extensions; | |
} | |
// handle renditions | |
if (objectData.Renditions != null) | |
{ | |
renditions = new List<IRendition>(); | |
foreach (IRenditionData rd in objectData.Renditions) | |
{ | |
renditions.Add(of.ConvertRendition(Id, rd)); | |
} | |
} | |
// handle ACL | |
if (objectData.Acl != null) | |
{ | |
acl = objectData.Acl; | |
extensions[ExtensionLevel.Acl] = objectData.Acl.Extensions; | |
} | |
// handle policies | |
if (objectData.PolicyIds != null && objectData.PolicyIds.PolicyIds != null) | |
{ | |
policies = new List<IPolicy>(); | |
foreach (string pid in objectData.PolicyIds.PolicyIds) | |
{ | |
IPolicy policy = Session.GetObject(Session.CreateObjectId(pid)) as IPolicy; | |
if (policy != null) | |
{ | |
policies.Add(policy); | |
} | |
} | |
extensions[ExtensionLevel.Policies] = objectData.PolicyIds.Extensions; | |
} | |
// handle relationships | |
if (objectData.Relationships != null) | |
{ | |
relationships = new List<IRelationship>(); | |
foreach (IObjectData rod in objectData.Relationships) | |
{ | |
IRelationship relationship = of.ConvertObject(rod, CreationContext) as IRelationship; | |
if (relationship != null) | |
{ | |
relationships.Add(relationship); | |
} | |
} | |
} | |
extensions[ExtensionLevel.Object] = objectData.Extensions; | |
} | |
} | |
protected string GetPropertyQueryName(string propertyId) | |
{ | |
Lock(); | |
try | |
{ | |
IPropertyDefinition propDef = objectType[propertyId]; | |
if (propDef == null) | |
{ | |
return null; | |
} | |
return propDef.QueryName; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
// --- object --- | |
public void Delete(bool allVersions) | |
{ | |
Lock(); | |
try | |
{ | |
Binding.GetObjectService().DeleteObject(RepositoryId, ObjectId, allVersions, null); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
public ICmisObject UpdateProperties(IDictionary<string, object> properties) | |
{ | |
IObjectId objectId = UpdateProperties(properties, true); | |
if (objectId == null) | |
{ | |
return null; | |
} | |
if (ObjectId != objectId.Id) | |
{ | |
return Session.GetObject(objectId, CreationContext); | |
} | |
return this; | |
} | |
public IObjectId UpdateProperties(IDictionary<String, object> properties, bool refresh) | |
{ | |
if (properties == null || properties.Count == 0) | |
{ | |
throw new ArgumentException("Properties must not be empty!"); | |
} | |
string newObjectId = null; | |
Lock(); | |
try | |
{ | |
string objectId = ObjectId; | |
string changeToken = ChangeToken; | |
HashSet<Updatability> updatebility = new HashSet<Updatability>(); | |
updatebility.Add(Updatability.ReadWrite); | |
// check if checked out | |
bool? isCheckedOut = GetPropertyValue(PropertyIds.IsVersionSeriesCheckedOut) as bool?; | |
if (isCheckedOut.HasValue && isCheckedOut.Value) | |
{ | |
updatebility.Add(Updatability.WhenCheckedOut); | |
} | |
// it's time to update | |
Binding.GetObjectService().UpdateProperties(RepositoryId, ref objectId, ref changeToken, | |
Session.ObjectFactory.ConvertProperties(properties, this.objectType, updatebility), null); | |
newObjectId = objectId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
if (refresh) | |
{ | |
Refresh(); | |
} | |
if (newObjectId == null) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(newObjectId); | |
} | |
// --- properties --- | |
public IObjectType BaseType { get { return Session.GetTypeDefinition(GetPropertyValue(PropertyIds.BaseTypeId) as string); } } | |
public BaseTypeId BaseTypeId | |
{ | |
get | |
{ | |
string baseType = GetPropertyValue(PropertyIds.BaseTypeId) as string; | |
if (baseType == null) { throw new CmisRuntimeException("Base type not set!"); } | |
return baseType.GetCmisEnum<BaseTypeId>(); | |
} | |
} | |
public string Id { get { return GetPropertyValue(PropertyIds.ObjectId) as string; } } | |
public string Name { get { return GetPropertyValue(PropertyIds.Name) as string; } } | |
public string CreatedBy { get { return GetPropertyValue(PropertyIds.CreatedBy) as string; } } | |
public DateTime? CreationDate { get { return GetPropertyValue(PropertyIds.CreationDate) as DateTime?; } } | |
public string LastModifiedBy { get { return GetPropertyValue(PropertyIds.LastModifiedBy) as string; } } | |
public DateTime? LastModificationDate { get { return GetPropertyValue(PropertyIds.LastModificationDate) as DateTime?; } } | |
public string ChangeToken { get { return GetPropertyValue(PropertyIds.ChangeToken) as string; } } | |
public IList<IProperty> Properties | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return new List<IProperty>(properties.Values); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
public IProperty this[string propertyId] | |
{ | |
get | |
{ | |
if (propertyId == null) | |
{ | |
throw new ArgumentNullException("propertyId"); | |
} | |
Lock(); | |
try | |
{ | |
IProperty property; | |
if (properties.TryGetValue(propertyId, out property)) | |
{ | |
return property; | |
} | |
return null; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
public object GetPropertyValue(string propertyId) | |
{ | |
IProperty property = this[propertyId]; | |
if (property == null) { return null; } | |
return property.Value; | |
} | |
// --- allowable actions --- | |
public IAllowableActions AllowableActions | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return allowableActions; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
// --- renditions --- | |
public IList<IRendition> Renditions | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return renditions; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
// --- ACL --- | |
public IAcl getAcl(bool onlyBasicPermissions) | |
{ | |
return Binding.GetAclService().GetAcl(RepositoryId, ObjectId, onlyBasicPermissions, null); | |
} | |
public IAcl ApplyAcl(IList<IAce> addAces, IList<IAce> removeAces, AclPropagation? aclPropagation) | |
{ | |
IAcl result = Session.ApplyAcl(this, addAces, removeAces, aclPropagation); | |
Refresh(); | |
return result; | |
} | |
public IAcl AddAcl(IList<IAce> addAces, AclPropagation? aclPropagation) | |
{ | |
return ApplyAcl(addAces, null, aclPropagation); | |
} | |
public IAcl RemoveAcl(IList<IAce> removeAces, AclPropagation? aclPropagation) | |
{ | |
return ApplyAcl(null, removeAces, aclPropagation); | |
} | |
public IAcl Acl | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return acl; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
// --- policies --- | |
public void ApplyPolicy(params IObjectId[] policyId) | |
{ | |
Lock(); | |
try | |
{ | |
Session.ApplyPolicy(this, policyId); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
Refresh(); | |
} | |
public void RemovePolicy(params IObjectId[] policyId) | |
{ | |
Lock(); | |
try | |
{ | |
Session.RemovePolicy(this, policyId); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
Refresh(); | |
} | |
public IList<IPolicy> Policies | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return policies; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
// --- relationships --- | |
public IList<IRelationship> Relationships | |
{ | |
get | |
{ | |
Lock(); | |
try | |
{ | |
return relationships; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
} | |
// --- extensions --- | |
public IList<ICmisExtensionElement> GetExtensions(ExtensionLevel level) | |
{ | |
IList<ICmisExtensionElement> ext; | |
if (extensions.TryGetValue(level, out ext)) | |
{ | |
return ext; | |
} | |
return null; | |
} | |
// --- other --- | |
public DateTime RefreshTimestamp { get; private set; } | |
public void Refresh() | |
{ | |
Lock(); | |
try | |
{ | |
IOperationContext oc = CreationContext; | |
// get the latest data from the repository | |
IObjectData objectData = Binding.GetObjectService().GetObject(RepositoryId, ObjectId, oc.FilterString, oc.IncludeAllowableActions, | |
oc.IncludeRelationships, oc.RenditionFilterString, oc.IncludePolicies, oc.IncludeAcls, null); | |
// reset this object | |
Initialize(Session, ObjectType, objectData, CreationContext); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
public void RefreshIfOld(long durationInMillis) | |
{ | |
Lock(); | |
try | |
{ | |
if (((DateTime.UtcNow - RefreshTimestamp).Ticks / 10000) > durationInMillis) | |
{ | |
Refresh(); | |
} | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
protected void Lock() | |
{ | |
Monitor.Enter(objectLock); | |
} | |
protected void Unlock() | |
{ | |
Monitor.Exit(objectLock); | |
} | |
} | |
/// <summary> | |
/// Fileable object base class. | |
/// </summary> | |
public abstract class AbstractFileableCmisObject : AbstractCmisObject, IFileableCmisObject | |
{ | |
public IFileableCmisObject Move(IObjectId sourceFolderId, IObjectId targetFolderId) | |
{ | |
string objectId = ObjectId; | |
if (sourceFolderId == null || sourceFolderId.Id == null) | |
{ | |
throw new ArgumentException("Source folder id must be set!"); | |
} | |
if (targetFolderId == null || targetFolderId.Id == null) | |
{ | |
throw new ArgumentException("Target folder id must be set!"); | |
} | |
Binding.GetObjectService().MoveObject(RepositoryId, ref objectId, targetFolderId.Id, sourceFolderId.Id, null); | |
if (objectId == null) | |
{ | |
return null; | |
} | |
IFileableCmisObject movedObject = Session.GetObject(Session.CreateObjectId(objectId)) as IFileableCmisObject; | |
if (movedObject == null) | |
{ | |
throw new CmisRuntimeException("Moved object is invalid!"); | |
} | |
return movedObject; | |
} | |
public virtual IList<IFolder> Parents | |
{ | |
get | |
{ | |
// get object ids of the parent folders | |
IList<IObjectParentData> bindingParents = Binding.GetNavigationService().GetObjectParents(RepositoryId, ObjectId, | |
GetPropertyQueryName(PropertyIds.ObjectId), false, IncludeRelationshipsFlag.None, null, false, null); | |
IList<IFolder> parents = new List<IFolder>(); | |
foreach (IObjectParentData p in bindingParents) | |
{ | |
if (p == null || p.Object == null || p.Object.Properties == null) | |
{ | |
// should not happen... | |
throw new CmisRuntimeException("Repository sent invalid data!"); | |
} | |
// get id property | |
IPropertyData idProperty = p.Object.Properties[PropertyIds.ObjectId]; | |
if (idProperty == null || idProperty.PropertyType != PropertyType.Id) | |
{ | |
// the repository sent an object without a valid object id... | |
throw new CmisRuntimeException("Repository sent invalid data! No object id!"); | |
} | |
// fetch the object and make sure it is a folder | |
IObjectId parentId = Session.CreateObjectId(idProperty.FirstValue as string); | |
IFolder parentFolder = Session.GetObject(parentId) as IFolder; | |
if (parentFolder == null) | |
{ | |
// the repository sent an object that is not a folder... | |
throw new CmisRuntimeException("Repository sent invalid data! Object is not a folder!"); | |
} | |
parents.Add(parentFolder); | |
} | |
return parents; | |
} | |
} | |
public virtual IList<string> Paths | |
{ | |
get | |
{ | |
// get object paths of the parent folders | |
IList<IObjectParentData> parents = Binding.GetNavigationService().GetObjectParents( | |
RepositoryId, ObjectId, GetPropertyQueryName(PropertyIds.Path), false, IncludeRelationshipsFlag.None, | |
null, true, null); | |
IList<string> paths = new List<string>(); | |
foreach (IObjectParentData p in parents) | |
{ | |
if (p == null || p.Object == null || p.Object.Properties == null) | |
{ | |
// should not happen... | |
throw new CmisRuntimeException("Repository sent invalid data!"); | |
} | |
// get path property | |
IPropertyData pathProperty = p.Object.Properties[PropertyIds.Path]; | |
if (pathProperty == null || pathProperty.PropertyType != PropertyType.String) | |
{ | |
// the repository sent a folder without a valid path... | |
throw new CmisRuntimeException("Repository sent invalid data! No path property!"); | |
} | |
if (p.RelativePathSegment == null) | |
{ | |
// the repository didn't send a relative path segment | |
throw new CmisRuntimeException("Repository sent invalid data! No relative path segement!"); | |
} | |
string folderPath = pathProperty.FirstValue as string; | |
paths.Add(folderPath + (folderPath.EndsWith("/") ? "" : "/") + p.RelativePathSegment); | |
} | |
return paths; | |
} | |
} | |
public void AddToFolder(IObjectId folderId, bool allVersions) | |
{ | |
if (folderId == null || folderId.Id == null) | |
{ | |
throw new ArgumentException("Folder Id must be set!"); | |
} | |
Binding.GetMultiFilingService().AddObjectToFolder(RepositoryId, ObjectId, folderId.Id, allVersions, null); | |
} | |
public void RemoveFromFolder(IObjectId folderId) | |
{ | |
if (folderId == null || folderId.Id == null) | |
{ | |
throw new ArgumentException("Folder Id must be set!"); | |
} | |
Binding.GetMultiFilingService().RemoveObjectFromFolder(RepositoryId, ObjectId, folderId.Id, null); | |
} | |
} | |
/// <summary> | |
/// Document implemetation. | |
/// </summary> | |
public class Document : AbstractFileableCmisObject, IDocument | |
{ | |
public Document(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context) | |
{ | |
Initialize(session, objectType, objectData, context); | |
} | |
// properties | |
public bool? IsImmutable { get { return GetPropertyValue(PropertyIds.IsImmutable) as bool?; } } | |
public bool? IsLatestVersion { get { return GetPropertyValue(PropertyIds.IsLatestVersion) as bool?; } } | |
public bool? IsMajorVersion { get { return GetPropertyValue(PropertyIds.IsMajorVersion) as bool?; } } | |
public bool? IsLatestMajorVersion { get { return GetPropertyValue(PropertyIds.IsLatestMajorVersion) as bool?; } } | |
public string VersionLabel { get { return GetPropertyValue(PropertyIds.VersionLabel) as string; } } | |
public string VersionSeriesId { get { return GetPropertyValue(PropertyIds.VersionSeriesId) as string; } } | |
public bool? IsVersionSeriesCheckedOut { get { return GetPropertyValue(PropertyIds.IsVersionSeriesCheckedOut) as bool?; } } | |
public string VersionSeriesCheckedOutBy { get { return GetPropertyValue(PropertyIds.VersionSeriesCheckedOutBy) as string; } } | |
public string VersionSeriesCheckedOutId { get { return GetPropertyValue(PropertyIds.VersionSeriesCheckedOutId) as string; } } | |
public string CheckinComment { get { return GetPropertyValue(PropertyIds.CheckinComment) as string; } } | |
public long? ContentStreamLength { get { return GetPropertyValue(PropertyIds.ContentStreamLength) as long?; } } | |
public string ContentStreamMimeType { get { return GetPropertyValue(PropertyIds.ContentStreamMimeType) as string; } } | |
public string ContentStreamFileName { get { return GetPropertyValue(PropertyIds.ContentStreamFileName) as string; } } | |
public string ContentStreamId { get { return GetPropertyValue(PropertyIds.ContentStreamId) as string; } } | |
// operations | |
public IDocument Copy(IObjectId targetFolderId, IDictionary<string, object> properties, VersioningState? versioningState, | |
IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context) | |
{ | |
IObjectId newId = Session.CreateDocumentFromSource(this, properties, targetFolderId, versioningState, policies, addAces, removeAces); | |
// if no context is provided the object will not be fetched | |
if (context == null || newId == null) | |
{ | |
return null; | |
} | |
// get the new object | |
IDocument newDoc = Session.GetObject(newId, context) as IDocument; | |
if (newDoc == null) | |
{ | |
throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId); | |
} | |
return newDoc; | |
} | |
public IDocument Copy(IObjectId targetFolderId) | |
{ | |
return Copy(targetFolderId, null, null, null, null, null, Session.DefaultContext); | |
} | |
public void DeleteAllVersions() | |
{ | |
Delete(true); | |
} | |
// versioning | |
public IObjectId CheckOut() | |
{ | |
string newObjectId = null; | |
Lock(); | |
try | |
{ | |
string objectId = ObjectId; | |
bool? contentCopied; | |
Binding.GetVersioningService().CheckOut(RepositoryId, ref objectId, null, out contentCopied); | |
newObjectId = objectId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
if (newObjectId == null) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(newObjectId); | |
} | |
public void CancelCheckOut() | |
{ | |
Binding.GetVersioningService().CancelCheckOut(RepositoryId, ObjectId, null); | |
} | |
public IObjectId CheckIn(bool major, IDictionary<string, object> properties, IContentStream contentStream, | |
string checkinComment, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces) | |
{ | |
String newObjectId = null; | |
Lock(); | |
try | |
{ | |
string objectId = ObjectId; | |
IObjectFactory of = Session.ObjectFactory; | |
HashSet<Updatability> updatebility = new HashSet<Updatability>(); | |
updatebility.Add(Updatability.ReadWrite); | |
updatebility.Add(Updatability.WhenCheckedOut); | |
Binding.GetVersioningService().CheckIn(RepositoryId, ref objectId, major, of.ConvertProperties(properties, ObjectType, updatebility), | |
contentStream, checkinComment, of.ConvertPolicies(policies), of.ConvertAces(addAces), of.ConvertAces(removeAces), null); | |
newObjectId = objectId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
if (newObjectId == null) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(newObjectId); | |
} | |
public IList<IDocument> GetAllVersions() | |
{ | |
return GetAllVersions(Session.DefaultContext); | |
} | |
public IList<IDocument> GetAllVersions(IOperationContext context) | |
{ | |
string objectId; | |
string versionSeriesId; | |
Lock(); | |
try | |
{ | |
objectId = ObjectId; | |
versionSeriesId = VersionSeriesId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
IList<IObjectData> versions = Binding.GetVersioningService().GetAllVersions(RepositoryId, objectId, versionSeriesId, | |
context.FilterString, context.IncludeAllowableActions, null); | |
IObjectFactory of = Session.ObjectFactory; | |
IList<IDocument> result = new List<IDocument>(); | |
if (versions != null) | |
{ | |
foreach (IObjectData objectData in versions) | |
{ | |
IDocument doc = of.ConvertObject(objectData, context) as IDocument; | |
if (doc == null) | |
{ | |
// should not happen... | |
continue; | |
} | |
result.Add(doc); | |
} | |
} | |
return result; | |
} | |
public IDocument GetObjectOfLatestVersion(bool major) | |
{ | |
return GetObjectOfLatestVersion(major, Session.DefaultContext); | |
} | |
public IDocument GetObjectOfLatestVersion(bool major, IOperationContext context) | |
{ | |
string objectId; | |
string versionSeriesId; | |
Lock(); | |
try | |
{ | |
objectId = ObjectId; | |
versionSeriesId = VersionSeriesId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
if (versionSeriesId == null) | |
{ | |
throw new CmisRuntimeException("Version series id is unknown!"); | |
} | |
IObjectData objectData = Binding.GetVersioningService().GetObjectOfLatestVersion(RepositoryId, objectId, versionSeriesId, major, | |
context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, | |
context.IncludePolicies, context.IncludeAcls, null); | |
IDocument result = Session.ObjectFactory.ConvertObject(objectData, context) as IDocument; | |
if (result == null) | |
{ | |
throw new CmisRuntimeException("Latest version is not a document!"); | |
} | |
return result; | |
} | |
// content operations | |
public IContentStream GetContentStream() | |
{ | |
return GetContentStream(null); | |
} | |
public IContentStream GetContentStream(String streamId) | |
{ | |
IContentStream contentStream; | |
try | |
{ | |
contentStream = Binding.GetObjectService().GetContentStream(RepositoryId, ObjectId, streamId, null, null, null); | |
} | |
catch (CmisConstraintException) | |
{ | |
// no content stream | |
return null; | |
} | |
// the AtomPub binding doesn't return a file name | |
// -> get the file name from properties, if present | |
if (contentStream.FileName == null && ContentStreamFileName != null) | |
{ | |
ContentStream newContentStream = new ContentStream(); | |
newContentStream.FileName = ContentStreamFileName; | |
newContentStream.Length = contentStream.Length; | |
newContentStream.MimeType = contentStream.MimeType; | |
newContentStream.Stream = contentStream.Stream; | |
newContentStream.Extensions = contentStream.Extensions; | |
contentStream = newContentStream; | |
} | |
return contentStream; | |
} | |
public IDocument SetContentStream(IContentStream contentStream, bool overwrite) | |
{ | |
IObjectId objectId = SetContentStream(contentStream, overwrite, true); | |
if (objectId == null) | |
{ | |
return null; | |
} | |
if (ObjectId != objectId.Id) | |
{ | |
return (IDocument)Session.GetObject(objectId, CreationContext); | |
} | |
return this; | |
} | |
public IObjectId SetContentStream(IContentStream contentStream, bool overwrite, bool refresh) | |
{ | |
string newObjectId = null; | |
Lock(); | |
try | |
{ | |
string objectId = ObjectId; | |
string changeToken = ChangeToken; | |
Binding.GetObjectService().SetContentStream(RepositoryId, ref objectId, overwrite, ref changeToken, contentStream, null); | |
newObjectId = objectId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
if (refresh) | |
{ | |
Refresh(); | |
} | |
if (newObjectId == null) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(newObjectId); | |
} | |
public IDocument DeleteContentStream() | |
{ | |
IObjectId objectId = DeleteContentStream(true); | |
if (objectId == null) | |
{ | |
return null; | |
} | |
if (ObjectId != objectId.Id) | |
{ | |
return (IDocument)Session.GetObject(objectId, CreationContext); | |
} | |
return this; | |
} | |
public IObjectId DeleteContentStream(bool refresh) | |
{ | |
string newObjectId = null; | |
Lock(); | |
try | |
{ | |
string objectId = ObjectId; | |
string changeToken = ChangeToken; | |
Binding.GetObjectService().DeleteContentStream(RepositoryId, ref objectId, ref changeToken, null); | |
newObjectId = objectId; | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
if (refresh) | |
{ | |
Refresh(); | |
} | |
if (newObjectId == null) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(newObjectId); | |
} | |
public IObjectId CheckIn(bool major, IDictionary<String, object> properties, IContentStream contentStream, string checkinComment) | |
{ | |
return this.CheckIn(major, properties, contentStream, checkinComment, null, null, null); | |
} | |
} | |
/// <summary> | |
/// Folder implemetation. | |
/// </summary> | |
public class Folder : AbstractFileableCmisObject, IFolder | |
{ | |
public Folder(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context) | |
{ | |
Initialize(session, objectType, objectData, context); | |
} | |
public IDocument CreateDocument(IDictionary<string, object> properties, IContentStream contentStream, VersioningState? versioningState, | |
IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context) | |
{ | |
IObjectId newId = Session.CreateDocument(properties, this, contentStream, versioningState, policies, addAces, removeAces); | |
// if no context is provided the object will not be fetched | |
if (context == null || newId == null) | |
{ | |
return null; | |
} | |
// get the new object | |
IDocument newDoc = Session.GetObject(newId, context) as IDocument; | |
if (newDoc == null) | |
{ | |
throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId); | |
} | |
return newDoc; | |
} | |
public IDocument CreateDocumentFromSource(IObjectId source, IDictionary<string, object> properties, VersioningState? versioningState, | |
IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context) | |
{ | |
IObjectId newId = Session.CreateDocumentFromSource(source, properties, this, versioningState, policies, addAces, removeAces); | |
// if no context is provided the object will not be fetched | |
if (context == null || newId == null) | |
{ | |
return null; | |
} | |
// get the new object | |
IDocument newDoc = Session.GetObject(newId, context) as IDocument; | |
if (newDoc == null) | |
{ | |
throw new CmisRuntimeException("Newly created object is not a document! New id: " + newId); | |
} | |
return newDoc; | |
} | |
public IFolder CreateFolder(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context) | |
{ | |
IObjectId newId = Session.CreateFolder(properties, this, policies, addAces, removeAces); | |
// if no context is provided the object will not be fetched | |
if (context == null || newId == null) | |
{ | |
return null; | |
} | |
// get the new object | |
IFolder newFolder = Session.GetObject(newId, context) as IFolder; | |
if (newFolder == null) | |
{ | |
throw new CmisRuntimeException("Newly created object is not a folder! New id: " + newId); | |
} | |
return newFolder; | |
} | |
public IPolicy CreatePolicy(IDictionary<string, object> properties, IList<IPolicy> policies, IList<IAce> addAces, IList<IAce> removeAces, IOperationContext context) | |
{ | |
IObjectId newId = Session.CreatePolicy(properties, this, policies, addAces, removeAces); | |
// if no context is provided the object will not be fetched | |
if (context == null || newId == null) | |
{ | |
return null; | |
} | |
// get the new object | |
IPolicy newPolicy = Session.GetObject(newId, context) as IPolicy; | |
if (newPolicy == null) | |
{ | |
throw new CmisRuntimeException("Newly created object is not a policy! New id: " + newId); | |
} | |
return newPolicy; | |
} | |
public IList<string> DeleteTree(bool allVersions, UnfileObject? unfile, bool continueOnFailure) | |
{ | |
IFailedToDeleteData failed = Binding.GetObjectService().DeleteTree(RepositoryId, ObjectId, allVersions, unfile, continueOnFailure, null); | |
return failed.Ids; | |
} | |
public string ParentId { get { return GetPropertyValue(PropertyIds.ParentId) as string; } } | |
public IList<IObjectType> AllowedChildObjectTypes | |
{ | |
get | |
{ | |
IList<IObjectType> result = new List<IObjectType>(); | |
Lock(); | |
try | |
{ | |
IList<string> otids = GetPropertyValue(PropertyIds.AllowedChildObjectTypeIds) as IList<string>; | |
if (otids == null) | |
{ | |
return result; | |
} | |
foreach (string otid in otids) | |
{ | |
result.Add(Session.GetTypeDefinition(otid)); | |
} | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
return result; | |
} | |
} | |
public IItemEnumerable<IDocument> GetCheckedOutDocs() | |
{ | |
return GetCheckedOutDocs(Session.DefaultContext); | |
} | |
public IItemEnumerable<IDocument> GetCheckedOutDocs(IOperationContext context) | |
{ | |
string objectId = ObjectId; | |
INavigationService service = Binding.GetNavigationService(); | |
IObjectFactory of = Session.ObjectFactory; | |
IOperationContext ctxt = new OperationContext(context); | |
PageFetcher<IDocument>.FetchPage fetchPageDelegate = delegate(long maxNumItems, long skipCount) | |
{ | |
// get checked out documents for this folder | |
IObjectList checkedOutDocs = service.GetCheckedOutDocs(RepositoryId, objectId, ctxt.FilterString, ctxt.OrderBy, ctxt.IncludeAllowableActions, | |
ctxt.IncludeRelationships, ctxt.RenditionFilterString, maxNumItems, skipCount, null); | |
IList<IDocument> page = new List<IDocument>(); | |
if (checkedOutDocs.Objects != null) | |
{ | |
foreach (IObjectData objectData in checkedOutDocs.Objects) | |
{ | |
IDocument doc = of.ConvertObject(objectData, ctxt) as IDocument; | |
if (doc == null) | |
{ | |
// should not happen... | |
continue; | |
} | |
page.Add(doc); | |
} | |
} | |
return new PageFetcher<IDocument>.Page<IDocument>(page, checkedOutDocs.NumItems, checkedOutDocs.HasMoreItems); | |
}; | |
return new CollectionEnumerable<IDocument>(new PageFetcher<IDocument>(ctxt.MaxItemsPerPage, fetchPageDelegate)); | |
} | |
public IItemEnumerable<ICmisObject> GetChildren() | |
{ | |
return GetChildren(Session.DefaultContext); | |
} | |
public IItemEnumerable<ICmisObject> GetChildren(IOperationContext context) | |
{ | |
string objectId = ObjectId; | |
INavigationService service = Binding.GetNavigationService(); | |
IObjectFactory of = Session.ObjectFactory; | |
IOperationContext ctxt = new OperationContext(context); | |
PageFetcher<ICmisObject>.FetchPage fetchPageDelegate = delegate(long maxNumItems, long skipCount) | |
{ | |
// get the children | |
IObjectInFolderList children = service.GetChildren(RepositoryId, objectId, ctxt.FilterString, ctxt.OrderBy, ctxt.IncludeAllowableActions, | |
ctxt.IncludeRelationships, ctxt.RenditionFilterString, ctxt.IncludePathSegments, maxNumItems, skipCount, null); | |
// convert objects | |
IList<ICmisObject> page = new List<ICmisObject>(); | |
if (children.Objects != null) | |
{ | |
foreach (IObjectInFolderData objectData in children.Objects) | |
{ | |
if (objectData.Object != null) | |
{ | |
page.Add(of.ConvertObject(objectData.Object, ctxt)); | |
} | |
} | |
} | |
return new PageFetcher<ICmisObject>.Page<ICmisObject>(page, children.NumItems, children.HasMoreItems); | |
}; | |
return new CollectionEnumerable<ICmisObject>(new PageFetcher<ICmisObject>(ctxt.MaxItemsPerPage, fetchPageDelegate)); | |
} | |
public IList<ITree<IFileableCmisObject>> GetDescendants(int depth) | |
{ | |
return GetDescendants(depth, Session.DefaultContext); | |
} | |
public IList<ITree<IFileableCmisObject>> GetDescendants(int depth, IOperationContext context) | |
{ | |
IList<IObjectInFolderContainer> bindingContainerList = Binding.GetNavigationService().GetDescendants(RepositoryId, ObjectId, depth, | |
context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, | |
context.IncludePathSegments, null); | |
return ConvertProviderContainer(bindingContainerList, context); | |
} | |
public IList<ITree<IFileableCmisObject>> GetFolderTree(int depth) | |
{ | |
return GetFolderTree(depth, Session.DefaultContext); | |
} | |
public IList<ITree<IFileableCmisObject>> GetFolderTree(int depth, IOperationContext context) | |
{ | |
IList<IObjectInFolderContainer> bindingContainerList = Binding.GetNavigationService().GetFolderTree(RepositoryId, ObjectId, depth, | |
context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, | |
context.IncludePathSegments, null); | |
return ConvertProviderContainer(bindingContainerList, context); | |
} | |
private IList<ITree<IFileableCmisObject>> ConvertProviderContainer(IList<IObjectInFolderContainer> bindingContainerList, IOperationContext context) | |
{ | |
if (bindingContainerList == null || bindingContainerList.Count == 0) | |
{ | |
return null; | |
} | |
IList<ITree<IFileableCmisObject>> result = new List<ITree<IFileableCmisObject>>(); | |
foreach (IObjectInFolderContainer oifc in bindingContainerList) | |
{ | |
if (oifc.Object == null || oifc.Object.Object == null) | |
{ | |
// shouldn't happen ... | |
continue; | |
} | |
// convert the object | |
IFileableCmisObject cmisObject = Session.ObjectFactory.ConvertObject(oifc.Object.Object, context) as IFileableCmisObject; | |
if (cmisObject == null) | |
{ | |
// the repository must not return objects that are not fileable, but you never know... | |
continue; | |
} | |
// convert the children | |
IList<ITree<IFileableCmisObject>> children = ConvertProviderContainer(oifc.Children, context); | |
// add both to current container | |
Tree<IFileableCmisObject> tree = new Tree<IFileableCmisObject>(); | |
tree.Item = cmisObject; | |
tree.Children = children; | |
result.Add(tree); | |
} | |
return result; | |
} | |
public bool IsRootFolder { get { return ObjectId == Session.RepositoryInfo.RootFolderId; } } | |
public IFolder FolderParent | |
{ | |
get | |
{ | |
if (IsRootFolder) | |
{ | |
return null; | |
} | |
IList<IFolder> parents = Parents; | |
if (parents == null || parents.Count == 0) | |
{ | |
return null; | |
} | |
return parents[0]; | |
} | |
} | |
public string Path | |
{ | |
get | |
{ | |
string path; | |
Lock(); | |
try | |
{ | |
// get the path property | |
path = GetPropertyValue(PropertyIds.Path) as string; | |
// if the path property isn't set, get it | |
if (path == null) | |
{ | |
IObjectData objectData = Binding.GetObjectService().GetObject(RepositoryId, ObjectId, | |
GetPropertyQueryName(PropertyIds.Path), false, IncludeRelationshipsFlag.None, "cmis:none", false, | |
false, null); | |
if (objectData.Properties != null) | |
{ | |
IPropertyData pathProperty = objectData.Properties[PropertyIds.Path]; | |
if (pathProperty != null && pathProperty.PropertyType == PropertyType.String) | |
{ | |
path = pathProperty.FirstValue as string; | |
} | |
} | |
} | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
// we still don't know the path ... it's not a CMIS compliant repository | |
if (path == null) | |
{ | |
throw new CmisRuntimeException("Repository didn't return " + PropertyIds.Path + "!"); | |
} | |
return path; | |
} | |
} | |
public override IList<string> Paths | |
{ | |
get | |
{ | |
IList<string> result = new List<string>(); | |
result.Add(Path); | |
return result; | |
} | |
} | |
public IDocument CreateDocument(IDictionary<string, object> properties, IContentStream contentStream, VersioningState? versioningState) | |
{ | |
return CreateDocument(properties, contentStream, versioningState, null, null, null, Session.DefaultContext); | |
} | |
public IDocument CreateDocumentFromSource(IObjectId source, IDictionary<string, object> properties, VersioningState? versioningState) | |
{ | |
return CreateDocumentFromSource(source, properties, versioningState, null, null, null, Session.DefaultContext); | |
} | |
public IFolder CreateFolder(IDictionary<string, object> properties) | |
{ | |
return CreateFolder(properties, null, null, null, Session.DefaultContext); | |
} | |
public IPolicy CreatePolicy(IDictionary<string, object> properties) | |
{ | |
return CreatePolicy(properties, null, null, null, Session.DefaultContext); | |
} | |
} | |
/// <summary> | |
/// Policy implemetation. | |
/// </summary> | |
public class Policy : AbstractFileableCmisObject, IPolicy | |
{ | |
public Policy(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context) | |
{ | |
Initialize(session, objectType, objectData, context); | |
} | |
public string PolicyText { get { return GetPropertyValue(PropertyIds.PolicyText) as string; } } | |
} | |
/// <summary> | |
/// Relationship implemetation. | |
/// </summary> | |
public class Relationship : AbstractCmisObject, IRelationship | |
{ | |
public Relationship(ISession session, IObjectType objectType, IObjectData objectData, IOperationContext context) | |
{ | |
Initialize(session, objectType, objectData, context); | |
} | |
public ICmisObject GetSource() | |
{ | |
return GetSource(Session.DefaultContext); | |
} | |
public ICmisObject GetSource(IOperationContext context) | |
{ | |
Lock(); | |
try | |
{ | |
IObjectId sourceId = SourceId; | |
if (sourceId == null) | |
{ | |
return null; | |
} | |
return Session.GetObject(sourceId, context); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
public IObjectId SourceId | |
{ | |
get | |
{ | |
string sourceId = GetPropertyValue(PropertyIds.SourceId) as string; | |
if (sourceId == null || sourceId.Length == 0) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(sourceId); | |
} | |
} | |
public ICmisObject GetTarget() | |
{ | |
return GetTarget(Session.DefaultContext); | |
} | |
public ICmisObject GetTarget(IOperationContext context) | |
{ | |
Lock(); | |
try | |
{ | |
IObjectId targetId = TargetId; | |
if (targetId == null) | |
{ | |
return null; | |
} | |
return Session.GetObject(targetId, context); | |
} | |
finally | |
{ | |
Unlock(); | |
} | |
} | |
public IObjectId TargetId | |
{ | |
get | |
{ | |
string targetId = GetPropertyValue(PropertyIds.TargetId) as string; | |
if (targetId == null || targetId.Length == 0) | |
{ | |
return null; | |
} | |
return Session.CreateObjectId(targetId); | |
} | |
} | |
} | |
public class Property : IProperty | |
{ | |
public Property(IPropertyDefinition propertyDefinition, IList<object> values) | |
{ | |
PropertyDefinition = propertyDefinition; | |
Values = values; | |
} | |
public string Id { get { return PropertyDefinition.Id; } } | |
public string LocalName { get { return PropertyDefinition.LocalName; } } | |
public string DisplayName { get { return PropertyDefinition.DisplayName; } } | |
public string QueryName { get { return PropertyDefinition.QueryName; } } | |
public bool IsMultiValued { get { return PropertyDefinition.Cardinality == Cardinality.Multi; } } | |
public PropertyType? PropertyType { get { return PropertyDefinition.PropertyType; } } | |
public IPropertyDefinition PropertyDefinition { get; protected set; } | |
public object Value | |
{ | |
get | |
{ | |
if (PropertyDefinition.Cardinality == Cardinality.Single) | |
{ | |
return Values == null || Values.Count == 0 ? null : Values[0]; | |
} | |
else | |
{ | |
return Values; | |
} | |
} | |
} | |
public IList<object> Values { get; protected set; } | |
public object FirstValue { get { return Values == null || Values.Count == 0 ? null : Values[0]; } } | |
public string ValueAsString { get { return FormatValue(FirstValue); } } | |
public string ValuesAsString | |
{ | |
get | |
{ | |
StringBuilder result = new StringBuilder(); | |
foreach (object value in Values) | |
{ | |
if (result.Length > 0) | |
{ | |
result.Append(", "); | |
} | |
result.Append(FormatValue(value)); | |
} | |
return "[" + result.ToString() + "]"; | |
} | |
} | |
private string FormatValue(object value) | |
{ | |
if (value == null) | |
{ | |
return null; | |
} | |
// for future formating | |
return value.ToString(); | |
} | |
} | |
public class Rendition : RenditionData, IRendition | |
{ | |
private ISession session; | |
private string objectId; | |
public Rendition(ISession session, string objectId, string streamId, string mimeType, long? length, string kind, | |
string title, long? height, long? width, string renditionDocumentId) | |
{ | |
this.session = session; | |
this.objectId = objectId; | |
StreamId = streamId; | |
MimeType = mimeType; | |
Length = length; | |
Kind = kind; | |
Title = title; | |
Height = height; | |
Width = width; | |
RenditionDocumentId = renditionDocumentId; | |
} | |
public IDocument GetRenditionDocument() | |
{ | |
return GetRenditionDocument(session.DefaultContext); | |
} | |
public IDocument GetRenditionDocument(IOperationContext context) | |
{ | |
if (RenditionDocumentId == null) | |
{ | |
return null; | |
} | |
return session.GetObject(session.CreateObjectId(RenditionDocumentId), context) as IDocument; | |
} | |
public IContentStream GetContentStream() | |
{ | |
if (objectId == null || StreamId == null) | |
{ | |
return null; | |
} | |
return session.Binding.GetObjectService().GetContentStream(session.RepositoryInfo.Id, objectId, StreamId, null, null, null); | |
} | |
} | |
public class QueryResult : IQueryResult | |
{ | |
private IDictionary<string, IPropertyData> propertiesById; | |
private IDictionary<string, IPropertyData> propertiesByQueryName; | |
public QueryResult(ISession session, IObjectData objectData) | |
{ | |
if (objectData != null) | |
{ | |
IObjectFactory of = session.ObjectFactory; | |
// handle properties | |
if (objectData.Properties != null) | |
{ | |
Properties = new List<IPropertyData>(); | |
propertiesById = new Dictionary<string, IPropertyData>(); | |
propertiesByQueryName = new Dictionary<string, IPropertyData>(); | |
IList<IPropertyData> queryProperties = of.ConvertQueryProperties(objectData.Properties); | |
foreach (IPropertyData property in queryProperties) | |
{ | |
Properties.Add(property); | |
if (property.Id != null) | |
{ | |
propertiesById[property.Id] = property; | |
} | |
if (property.QueryName != null) | |
{ | |
propertiesByQueryName[property.QueryName] = property; | |
} | |
} | |
} | |
// handle allowable actions | |
AllowableActions = objectData.AllowableActions; | |
// handle relationships | |
if (objectData.Relationships != null) | |
{ | |
Relationships = new List<IRelationship>(); | |
foreach (IObjectData rod in objectData.Relationships) | |
{ | |
IRelationship relationship = of.ConvertObject(rod, session.DefaultContext) as IRelationship; | |
if (relationship != null) | |
{ | |
Relationships.Add(relationship); | |
} | |
} | |
} | |
// handle renditions | |
if (objectData.Renditions != null) | |
{ | |
Renditions = new List<IRendition>(); | |
foreach (IRenditionData rd in objectData.Renditions) | |
{ | |
Renditions.Add(of.ConvertRendition(null, rd)); | |
} | |
} | |
} | |
} | |
public IPropertyData this[string queryName] | |
{ | |
get | |
{ | |
if (queryName == null) | |
{ | |
return null; | |
} | |
IPropertyData result; | |
if (propertiesByQueryName.TryGetValue(queryName, out result)) | |
{ | |
return result; | |
} | |
return null; | |
} | |
} | |
public IList<IPropertyData> Properties { get; protected set; } | |
public IPropertyData GetPropertyById(string propertyId) | |
{ | |
if (propertyId == null) | |
{ | |
return null; | |
} | |
IPropertyData result; | |
if (propertiesById.TryGetValue(propertyId, out result)) | |
{ | |
return result; | |
} | |
return null; | |
} | |
public object GetPropertyValueByQueryName(string queryName) | |
{ | |
IPropertyData property = this[queryName]; | |
if (property == null) | |
{ | |
return null; | |
} | |
return property.FirstValue; | |
} | |
public object GetPropertyValueById(string propertyId) | |
{ | |
IPropertyData property = GetPropertyById(propertyId); | |
if (property == null) | |
{ | |
return null; | |
} | |
return property.FirstValue; | |
} | |
public IList<object> GetPropertyMultivalueByQueryName(string queryName) | |
{ | |
IPropertyData property = this[queryName]; | |
if (property == null) | |
{ | |
return null; | |
} | |
return property.Values; | |
} | |
public IList<object> GetPropertyMultivalueById(string propertyId) | |
{ | |
IPropertyData property = GetPropertyById(propertyId); | |
if (property == null) | |
{ | |
return null; | |
} | |
return property.Values; | |
} | |
public IAllowableActions AllowableActions { get; protected set; } | |
public IList<IRelationship> Relationships { get; protected set; } | |
public IList<IRendition> Renditions { get; protected set; } | |
} | |
public class ChangeEvent : ChangeEventInfo, IChangeEvent | |
{ | |
public string ObjectId { get; set; } | |
public IDictionary<string, IList<object>> Properties { get; set; } | |
public IList<string> PolicyIds { get; set; } | |
public IAcl Acl { get; set; } | |
} | |
public class ChangeEvents : IChangeEvents | |
{ | |
public string LatestChangeLogToken { get; set; } | |
public IList<IChangeEvent> ChangeEventList { get; set; } | |
public bool? HasMoreItems { get; set; } | |
public long? TotalNumItems { get; set; } | |
} | |
} |