/* * 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 PortCMIS.Binding; using PortCMIS.Binding.Services; using PortCMIS.Data; using PortCMIS.Enums; using PortCMIS.Exceptions; using System; using System.Collections.Generic; using System.Globalization; using System.Numerics; using System.Text; namespace PortCMIS.Client.Impl { /// /// Session factory implementation. /// public class SessionFactory : ISessionFactory { /// /// This is a factory. /// private SessionFactory() { } /// /// Creates a new factory object. /// /// a factory object public static SessionFactory NewInstance() { return new SessionFactory(); } /// public ISession CreateSession(IDictionary parameters) { return CreateSession(parameters, null, null, null); } /// public ISession CreateSession(IDictionary parameters, IObjectFactory objectFactory, IAuthenticationProvider authenticationProvider, ICache cache) { Session session = new Session(parameters, objectFactory, authenticationProvider, cache); session.Connect(); return session; } /// public IList GetRepositories(IDictionary parameters) { return GetRepositories(parameters, null, null, null); } /// /// Gets all repository available at the specified endpoint. /// /// the session parameters /// Object factory. /// Authentication provider. /// Client object cache. /// a list of all available repositories /// public IList GetRepositories(IDictionary parameters, IObjectFactory objectFactory, IAuthenticationProvider authenticationProvider, ICache cache) { ICmisBinding binding = CmisBindingHelper.CreateBinding(parameters); IList repositoryInfos = binding.GetRepositoryService().GetRepositoryInfos(null); IList result = new List(); foreach (IRepositoryInfo data in repositoryInfos) { result.Add(new Repository(data, parameters, this, objectFactory, binding.GetAuthenticationProvider(), cache)); } return result; } } /// /// Binding helper class. /// internal class CmisBindingHelper { public static ICmisBinding CreateBinding(IDictionary parameters) { return CreateBinding(parameters, null); } public static ICmisBinding CreateBinding(IDictionary parameters, IAuthenticationProvider authenticationProvider) { if (parameters == null) { throw new ArgumentNullException("parameters"); } if (!parameters.ContainsKey(SessionParameter.BindingType)) { parameters[SessionParameter.BindingType] = BindingType.Custom; } string bt = parameters[SessionParameter.BindingType]; switch (bt) { case BindingType.AtomPub: return CreateAtomPubBinding(parameters, authenticationProvider); case BindingType.WebServices: return CreateWebServiceBinding(parameters, authenticationProvider); case BindingType.Browser: return CreateBrowserBinding(parameters, authenticationProvider); case BindingType.Custom: return CreateCustomBinding(parameters, authenticationProvider); default: throw new CmisRuntimeException("Ambiguous session parameter: " + parameters); } } private static ICmisBinding CreateCustomBinding(IDictionary parameters, IAuthenticationProvider authenticationProvider) { CmisBindingFactory factory = CmisBindingFactory.NewInstance(); ICmisBinding binding = factory.CreateCmisBinding(parameters, authenticationProvider); return binding; } private static ICmisBinding CreateWebServiceBinding(IDictionary parameters, IAuthenticationProvider authenticationProvider) { CmisBindingFactory factory = CmisBindingFactory.NewInstance(); ICmisBinding binding = factory.CreateCmisWebServicesBinding(parameters, authenticationProvider); return binding; } private static ICmisBinding CreateAtomPubBinding(IDictionary parameters, IAuthenticationProvider authenticationProvider) { CmisBindingFactory factory = CmisBindingFactory.NewInstance(); ICmisBinding binding = factory.CreateCmisAtomPubBinding(parameters, authenticationProvider); return binding; } private static ICmisBinding CreateBrowserBinding(IDictionary parameters, IAuthenticationProvider authenticationProvider) { CmisBindingFactory factory = CmisBindingFactory.NewInstance(); ICmisBinding binding = factory.CreateCmisBrowserBinding(parameters, authenticationProvider); return binding; } } /// /// Repository implementation. /// public class Repository : RepositoryInfo, IRepository { private IDictionary parameters; private SessionFactory sessionFactory; private IObjectFactory objectFactory; private IAuthenticationProvider authenticationProvider; private ICache cache; /// /// Constructor. /// /// the low-level repository info object /// the session parameters /// the session factory /// the object factory (may be null) /// the authentication provider (may be null) /// the cache (may be null) public Repository(IRepositoryInfo info, IDictionary parameters, SessionFactory sessionFactory, IObjectFactory objectFactory, IAuthenticationProvider authenticationProvider, ICache cache) : base(info) { this.parameters = new Dictionary(parameters); this.parameters[SessionParameter.RepositoryId] = Id; this.sessionFactory = sessionFactory; this.objectFactory = objectFactory; this.authenticationProvider = authenticationProvider; this.cache = cache; } /// public ISession CreateSession() { return sessionFactory.CreateSession(parameters, objectFactory, authenticationProvider, cache); } } /// /// Session implementation. /// public class Session : ISession { private static HashSet CreateUpdatability = new HashSet(); private static HashSet CreateAndCheckoutUpdatability = new HashSet(); static Session() { CreateUpdatability.Add(Updatability.OnCreate); CreateUpdatability.Add(Updatability.ReadWrite); CreateAndCheckoutUpdatability.Add(Updatability.OnCreate); CreateAndCheckoutUpdatability.Add(Updatability.ReadWrite); CreateAndCheckoutUpdatability.Add(Updatability.WhenCheckedOut); } /// /// Initial default operation context. /// protected static IOperationContext FallbackContext = new OperationContext(null, false, true, false, IncludeRelationships.None, null, true, null, true, 100); /// /// Session parameters /// protected IDictionary parameters; private object sessionLock = new object(); /// /// Gets the low-level binding. /// public ICmisBinding Binding { get; protected set; } /// /// Gets the repository info. /// public IRepositoryInfo RepositoryInfo { get; protected set; } /// /// Gets the repository ID. /// public string RepositoryId { get { return RepositoryInfo.Id; } } /// public IObjectFactory ObjectFactory { get; protected set; } /// /// Authentication provider. /// protected IAuthenticationProvider AuthenticationProvider { get; set; } /// /// Object and path cache. /// protected ICache Cache { get; set; } /// /// Indicating if the path cache should be used. /// protected bool cachePathOmit; private IOperationContext context = FallbackContext; /// public IOperationContext DefaultContext { get { lock (sessionLock) { return context; } } set { lock (sessionLock) { context = (value == null ? FallbackContext : value); } } } /// /// Constructor. /// /// the session parameters /// an object factory, if available /// an authentication provider, if available /// a cache, if available public Session(IDictionary parameters, IObjectFactory objectFactory, IAuthenticationProvider authenticationProvider, ICache cache) { if (parameters == null) { throw new ArgumentNullException("parameters"); } this.parameters = parameters; ObjectFactory = (objectFactory == null ? CreateObjectFactory() : objectFactory); AuthenticationProvider = authenticationProvider; Cache = (cache == null ? CreateCache() : cache); string cachePathOmitStr; if (parameters.TryGetValue(SessionParameter.CachePathOmit, out cachePathOmitStr)) { cachePathOmit = cachePathOmitStr.ToLower() == "true"; } else { cachePathOmit = false; } } /// /// Connects to the repository and fetches the repository info. /// public void Connect() { lock (sessionLock) { Binding = CmisBindingHelper.CreateBinding(parameters, AuthenticationProvider); string repositoryId; if (!parameters.TryGetValue(SessionParameter.RepositoryId, out repositoryId)) { throw new ArgumentException("Repository Id is not set!"); } RepositoryInfo = Binding.GetRepositoryService().GetRepositoryInfo(repositoryId, null); } } /// /// Create the cache. /// /// the cache object protected ICache CreateCache() { try { string typeName; Type cacheType; if (parameters.TryGetValue(SessionParameter.CacheClass, out typeName)) { cacheType = Type.GetType(typeName); } else { cacheType = typeof(CmisObjectCache); } ICache cacheObject = Activator.CreateInstance(cacheType) as ICache; if (cacheObject == null) { throw new Exception("Class does not implement ICache!"); } cacheObject.Initialize(this, parameters); return cacheObject; } catch (Exception e) { throw new ArgumentException("Unable to create cache: " + e, e); } } /// /// Creates the object factory. /// /// the object factory protected IObjectFactory CreateObjectFactory() { try { string ofName; Type ofType; if (parameters.TryGetValue(SessionParameter.ObjectFactoryClass, out ofName)) { ofType = Type.GetType(ofName); } else { ofType = typeof(ObjectFactory); } IObjectFactory ofObject = Activator.CreateInstance(ofType) as IObjectFactory; if (ofObject == null) { throw new Exception("Class does not implement IObjectFactory!"); } ofObject.Initialize(this, parameters); return ofObject; } catch (Exception e) { throw new ArgumentException("Unable to create object factory: " + e, e); } } /// public void Clear() { lock (sessionLock) { Cache = CreateCache(); Binding.ClearAllCaches(); } } // session context /// public IOperationContext CreateOperationContext() { return new OperationContext(); } /// public IOperationContext CreateOperationContext(HashSet filter, bool includeAcls, bool includeAllowableActions, bool includePolicies, IncludeRelationships includeRelationships, HashSet renditionFilter, bool includePathSegments, string orderBy, bool cacheEnabled, int maxItemsPerPage) { return new OperationContext(filter, includeAcls, includeAllowableActions, includePolicies, includeRelationships, renditionFilter, includePathSegments, orderBy, cacheEnabled, maxItemsPerPage); } /// public IObjectId CreateObjectId(string id) { return new ObjectId(id); } // types /// public IObjectType GetTypeDefinition(string typeId) { ITypeDefinition typeDefinition = Binding.GetRepositoryService().GetTypeDefinition(RepositoryId, typeId, null); return ObjectFactory.ConvertTypeDefinition(typeDefinition); } /// public IItemEnumerable GetTypeChildren(string typeId, bool includePropertyDefinitions) { IRepositoryService service = Binding.GetRepositoryService(); PageFetcher.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount) { // fetch the data ITypeDefinitionList tdl = service.GetTypeChildren(RepositoryId, typeId, includePropertyDefinitions, maxNumItems, skipCount, null); // convert type definitions int count = (tdl != null && tdl.List != null ? tdl.List.Count : 0); IList page = new List(count); if (count > 0) { foreach (ITypeDefinition typeDefinition in tdl.List) { page.Add(ObjectFactory.ConvertTypeDefinition(typeDefinition)); } } return new PageFetcher.Page(page, tdl.NumItems, tdl.HasMoreItems); }; return new CollectionEnumerable(new PageFetcher(DefaultContext.MaxItemsPerPage, fetchPageDelegate)); } /// public IList> GetTypeDescendants(string typeId, int depth, bool includePropertyDefinitions) { IList descendants = Binding.GetRepositoryService().GetTypeDescendants( RepositoryId, typeId, depth, includePropertyDefinitions, null); return ConvertTypeDescendants(descendants); } private IList> ConvertTypeDescendants(IList descendantsList) { if (descendantsList == null || descendantsList.Count == 0) { return null; } IList> result = new List>(); foreach (ITypeDefinitionContainer container in descendantsList) { Tree tree = new Tree(); tree.Item = ObjectFactory.ConvertTypeDefinition(container.TypeDefinition); tree.Children = ConvertTypeDescendants(container.Children); result.Add(tree); } return result; } /// public IObjectType CreateType(ITypeDefinition type) { CheckCmisVersion(); ITypeDefinition newType = Binding.GetRepositoryService().CreateType(RepositoryId, type, null); return ObjectFactory.ConvertTypeDefinition(newType); } /// public IObjectType UpdateType(ITypeDefinition type) { CheckCmisVersion(); ITypeDefinition updatedType = Binding.GetRepositoryService().UpdateType(RepositoryId, type, null); return ObjectFactory.ConvertTypeDefinition(updatedType); } /// public void DeleteType(string typeId) { CheckCmisVersion(); Binding.GetRepositoryService().DeleteType(RepositoryId, typeId, null); } // navigation /// public IFolder GetRootFolder() { return GetRootFolder(DefaultContext); } /// public IFolder GetRootFolder(IOperationContext context) { IFolder rootFolder = GetObject(RepositoryInfo.RootFolderId, context) as IFolder; if (rootFolder == null) { throw new CmisRuntimeException("Root folder object is not a folder!"); } return rootFolder; } /// public IItemEnumerable GetCheckedOutDocs() { return GetCheckedOutDocs(DefaultContext); } /// public IItemEnumerable GetCheckedOutDocs(IOperationContext context) { INavigationService service = Binding.GetNavigationService(); IOperationContext ctxt = new OperationContext(context); PageFetcher.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount) { // get all checked out documents IObjectList checkedOutDocs = service.GetCheckedOutDocs(RepositoryId, null, ctxt.FilterString, ctxt.OrderBy, ctxt.IncludeAllowableActions, ctxt.IncludeRelationships, ctxt.RenditionFilterString, maxNumItems, skipCount, null); // convert objects IList page = new List(); if (checkedOutDocs.Objects != null) { foreach (IObjectData objectData in checkedOutDocs.Objects) { IDocument doc = ObjectFactory.ConvertObject(objectData, ctxt) as IDocument; if (doc == null) { // should not happen... continue; } page.Add(doc); } } return new PageFetcher.Page(page, checkedOutDocs.NumItems, checkedOutDocs.HasMoreItems); }; return new CollectionEnumerable(new PageFetcher(DefaultContext.MaxItemsPerPage, fetchPageDelegate)); } /// public ICmisObject GetObject(IObjectId objectId) { return GetObject(objectId, DefaultContext); } /// public ICmisObject GetObject(IObjectId objectId, IOperationContext context) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Object Id must be set!", "objectId"); } return GetObject(objectId.Id, context); } /// public ICmisObject GetObject(string objectId) { return GetObject(objectId, DefaultContext); } /// public ICmisObject GetObject(string objectId, IOperationContext context) { if (objectId == null) { throw new ArgumentException("Object Id must be set!", "objectId"); } if (context == null) { throw new ArgumentException("Operation context must be set!", "context"); } ICmisObject result = null; // ask the cache first if (context.CacheEnabled) { result = Cache.GetById(objectId, context.CacheKey); if (result != null) { return result; } } // get the object IObjectData objectData = Binding.GetObjectService().GetObject(RepositoryId, objectId, context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, context.IncludePolicies, context.IncludeAcls, null); result = ObjectFactory.ConvertObject(objectData, context); // put into cache if (context.CacheEnabled) { Cache.Put(result, context.CacheKey); } return result; } /// public ICmisObject GetObjectByPath(string path) { return GetObjectByPath(path, DefaultContext); } /// public ICmisObject GetObjectByPath(string path, IOperationContext context) { CheckPath(path); if (context == null) { throw new ArgumentNullException("context"); } ICmisObject result = null; // ask the cache first if (context.CacheEnabled && !cachePathOmit) { result = Cache.GetByPath(path, context.CacheKey); if (result != null) { return result; } } // get the object IObjectData objectData = Binding.GetObjectService().GetObjectByPath(RepositoryId, path, context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, context.IncludePolicies, context.IncludeAcls, null); result = ObjectFactory.ConvertObject(objectData, context); // put into cache if (context.CacheEnabled) { Cache.PutPath(path, result, context.CacheKey); } return result; } /// public ICmisObject GetObjectByPath(string parentPath, string name) { return GetObjectByPath(parentPath, name, DefaultContext); } /// public ICmisObject GetObjectByPath(string parentPath, string name, IOperationContext context) { if (parentPath == null || parentPath.Length < 1) { throw new ArgumentException("Parent path must be set!", "parentPath"); } if (parentPath[0] != '/') { throw new ArgumentException("Parent path must start with a '/'!", "parentPath"); } if (name == null || name.Length < 1) { throw new ArgumentException("Name must be set!", "name"); } StringBuilder path = new StringBuilder(); path.Append(parentPath); if (!parentPath.EndsWith("/")) { path.Append('/'); } path.Append(name); return GetObjectByPath(path.ToString(), context); } /// public IDocument GetLatestDocumentVersion(string objectId) { return GetLatestDocumentVersion(objectId, DefaultContext); } /// public IDocument GetLatestDocumentVersion(string objectId, IOperationContext context) { if (objectId == null) { throw new ArgumentNullException("objectId"); } return GetLatestDocumentVersion(CreateObjectId(objectId), false, context); } /// public IDocument GetLatestDocumentVersion(IObjectId objectId) { return GetLatestDocumentVersion(objectId, false, DefaultContext); } /// public IDocument GetLatestDocumentVersion(IObjectId objectId, IOperationContext context) { return GetLatestDocumentVersion(objectId, false, context); } /// public IDocument GetLatestDocumentVersion(IObjectId objectId, bool major, IOperationContext context) { if (objectId == null || objectId.Id == null) { throw new ArgumentNullException("objectId"); } if (context == null) { throw new ArgumentNullException("context"); } ICmisObject result = null; string versionSeriesId = null; // first attempt: if we got a Document object, try getting the version // series ID from it if (objectId is IDocument) { versionSeriesId = ((IDocument)objectId).VersionSeriesId; } // second attempt: if we have a Document object in the cache, retrieve // the version series ID form there if (versionSeriesId == null) { if (context.CacheEnabled) { ICmisObject sourceDoc = Cache.GetById(objectId.Id, context.CacheKey); if (sourceDoc is IDocument) { versionSeriesId = ((IDocument)sourceDoc).VersionSeriesId; } } } // third attempt (Web Services only): get the version series ID from the // repository // (the AtomPub and Browser binding don't need the version series ID -> // avoid roundtrip) if (versionSeriesId == null) { string bindingType = Binding.BindingType; if (bindingType == BindingType.WebServices || bindingType == BindingType.Custom) { // get the document to find the version series ID IObjectData sourceObjectData = Binding.GetObjectService().GetObject(RepositoryId, objectId.Id, PropertyIds.ObjectId + "," + PropertyIds.VersionSeriesId, false, IncludeRelationships.None, "cmis:none", false, false, null); if (sourceObjectData.Properties != null) { IPropertyData verionsSeriesIdProp = sourceObjectData.Properties[PropertyIds.VersionSeriesId]; if (verionsSeriesIdProp != null) { versionSeriesId = verionsSeriesIdProp.FirstValue as string; } } // the Web Services binding needs the version series ID -> fail if (versionSeriesId == null) { throw new ArgumentException("Object is not a document or not versionable!"); } } } // get the object IObjectData objectData = Binding.GetVersioningService().GetObjectOfLatestVersion(RepositoryId, objectId.Id, versionSeriesId, major, context.FilterString, context.IncludeAllowableActions, context.IncludeRelationships, context.RenditionFilterString, context.IncludePolicies, context.IncludeAcls, null); result = ObjectFactory.ConvertObject(objectData, context); // put into cache if (context.CacheEnabled) { Cache.Put(result, context.CacheKey); } // check result if (!(result is IDocument)) { throw new ArgumentException("Latest version is not a document!"); } return result as IDocument; } /// public bool Exists(IObjectId objectId) { if (objectId == null) { throw new ArgumentNullException("objectId"); } return Exists(objectId.Id); } /// public bool Exists(string objectId) { if (objectId == null) { throw new ArgumentNullException(objectId); } try { Binding.GetObjectService().GetObject(RepositoryId, objectId, "cmis:objectId", false, IncludeRelationships.None, "cmis:none", false, false, null); return true; } catch (CmisObjectNotFoundException) { RemoveObjectFromCache(objectId); return false; } } /// public bool ExistsPath(string path) { CheckPath(path); try { IObjectData obj = Binding.GetObjectService().GetObjectByPath(RepositoryId, path, "cmis:objectId", false, IncludeRelationships.None, "cmis:none", false, false, null); string cacheObjectId = Cache.GetObjectIdByPath(path); if (cacheObjectId != obj.Id) { Cache.RemovePath(path); } return true; } catch (CmisObjectNotFoundException) { Cache.RemovePath(path); return false; } } /// public bool ExistsPath(string parentPath, string name) { if (parentPath == null || parentPath.Length < 1) { throw new ArgumentException("Parent path must be set!", "parentPath"); } if (parentPath[0] != '/') { throw new ArgumentException("Parent path must start with a '/'!", "parentPath"); } if (name == null || name.Length < 1) { throw new ArgumentException("Name must be set!", "name"); } StringBuilder path = new StringBuilder(parentPath.Length + name.Length + 2); path.Append(parentPath); if (!parentPath.EndsWith("/")) { path.Append('/'); } path.Append(name); return ExistsPath(path.ToString()); } /// public void RemoveObjectFromCache(IObjectId objectId) { if (objectId == null || objectId.Id == null) { return; } RemoveObjectFromCache(objectId.Id); } /// public void RemoveObjectFromCache(string objectId) { Cache.Remove(objectId); } // discovery /// public IItemEnumerable Query(string statement, bool searchAllVersions) { return Query(statement, searchAllVersions, DefaultContext); } /// public IItemEnumerable Query(string statement, bool searchAllVersions, IOperationContext context) { IDiscoveryService service = Binding.GetDiscoveryService(); IOperationContext ctxt = new OperationContext(context); PageFetcher.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount) { // fetch the data IObjectList resultList = service.Query(RepositoryId, statement, searchAllVersions, ctxt.IncludeAllowableActions, ctxt.IncludeRelationships, ctxt.RenditionFilterString, maxNumItems, skipCount, null); // convert query results IList page = new List(); if (resultList.Objects != null) { foreach (IObjectData objectData in resultList.Objects) { if (objectData == null) { continue; } page.Add(ObjectFactory.ConvertQueryResult(objectData)); } } return new PageFetcher.Page(page, resultList.NumItems, resultList.HasMoreItems); }; return new CollectionEnumerable(new PageFetcher(DefaultContext.MaxItemsPerPage, fetchPageDelegate)); } /// public IItemEnumerable QueryObjects(string typeId, string where, bool searchAllVersions, IOperationContext context) { if (typeId == null || typeId.Trim().Length == 0) { throw new ArgumentException("Type ID must be set!", "typeId"); } if (context == null) { throw new ArgumentException("Operation context must be set!", "context"); } IDiscoveryService discoveryService = Binding.GetDiscoveryService(); IObjectFactory of = ObjectFactory; OperationContext ctxt = new OperationContext(context); StringBuilder statement = new StringBuilder("SELECT "); string select = ctxt.FilterString; if (select == null) { statement.Append('*'); } else { statement.Append(select); } IObjectType type = GetTypeDefinition(typeId); statement.Append(" FROM "); statement.Append(type.QueryName); if (where != null && where.Trim().Length > 0) { statement.Append(" WHERE "); statement.Append(where); } string orderBy = ctxt.OrderBy; if (orderBy != null && orderBy.Trim().Length > 0) { statement.Append(" ORDER BY "); statement.Append(orderBy); } PageFetcher.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount) { // fetch the data IObjectList resultList = discoveryService.Query(RepositoryId, statement.ToString(), searchAllVersions, ctxt.IncludeAllowableActions, ctxt.IncludeRelationships, ctxt.RenditionFilterString, maxNumItems, skipCount, null); // convert query results IList page = new List(); if (resultList.Objects != null) { foreach (IObjectData objectData in resultList.Objects) { if (objectData == null) { continue; } page.Add(of.ConvertObject(objectData, ctxt)); } } return new PageFetcher.Page(page, resultList.NumItems, resultList.HasMoreItems); }; return new CollectionEnumerable(new PageFetcher(DefaultContext.MaxItemsPerPage, fetchPageDelegate)); } /// public IQueryStatement CreateQueryStatement(string statement) { return new QueryStatement(this, statement); } /// public string GetLatestChangeLogToken() { return Binding.GetRepositoryService().GetRepositoryInfo(RepositoryId, null).LatestChangeLogToken; } /// public IChangeEvents GetContentChanges(string changeLogToken, bool includeProperties, long maxNumItems) { return GetContentChanges(changeLogToken, includeProperties, maxNumItems, DefaultContext); } /// public IChangeEvents GetContentChanges(string changeLogToken, bool includeProperties, long maxNumItems, IOperationContext context) { lock (sessionLock) { IObjectList objectList = Binding.GetDiscoveryService().GetContentChanges(RepositoryId, ref changeLogToken, includeProperties, context.FilterString, context.IncludePolicies, context.IncludeAcls, maxNumItems, null); return ObjectFactory.ConvertChangeEvents(changeLogToken, objectList); } } // create /// public IObjectId CreateDocument(IDictionary properties, IObjectId folderId, IContentStream contentStream, VersioningState? versioningState, IList policies, IList addAces, IList removeAces) { CheckProperties(properties); string newId = Binding.GetObjectService().CreateDocument(RepositoryId, ObjectFactory.ConvertProperties(properties, null, null, (versioningState == VersioningState.CheckedOut ? CreateAndCheckoutUpdatability : CreateUpdatability)), (folderId == null ? null : folderId.Id), contentStream, versioningState, ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); return newId == null ? null : CreateObjectId(newId); } /// public IObjectId CreateDocument(IDictionary properties, IObjectId folderId, IContentStream contentStream, VersioningState? versioningState) { return CreateDocument(properties, folderId, contentStream, versioningState, null, null, null); } /// public IObjectId CreateDocumentFromSource(IObjectId source, IDictionary properties, IObjectId folderId, VersioningState? versioningState, IList policies, IList addAces, IList removeAces) { if (source == null || source.Id == null) { throw new ArgumentException("Source must be set!"); } // get the type of the source document IObjectType type = null; IList secondaryTypes = null; if (source is ICmisObject) { type = ((ICmisObject)source).ObjectType; secondaryTypes = ((ICmisObject)source).SecondaryTypes; } else { ICmisObject sourceObj = GetObject(source); type = sourceObj.ObjectType; secondaryTypes = sourceObj.SecondaryTypes; } if (type.BaseTypeId != BaseTypeId.CmisDocument) { throw new ArgumentException("Source object must be a document!"); } string newId = Binding.GetObjectService().CreateDocumentFromSource(RepositoryId, source.Id, ObjectFactory.ConvertProperties(properties, type, secondaryTypes, (versioningState == VersioningState.CheckedOut ? CreateAndCheckoutUpdatability : CreateUpdatability)), (folderId == null ? null : folderId.Id), versioningState, ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); return newId == null ? null : CreateObjectId(newId); } /// public IObjectId CreateDocumentFromSource(IObjectId source, IDictionary properties, IObjectId folderId, VersioningState? versioningState) { return CreateDocumentFromSource(source, properties, folderId, versioningState, null, null, null); } /// public IObjectId CreateFolder(IDictionary properties, IObjectId folderId, IList policies, IList addAces, IList removeAces) { if (folderId == null || folderId.Id == null) { throw new ArgumentException("Folder ID must be set!"); } CheckProperties(properties); string newId = Binding.GetObjectService().CreateFolder(RepositoryId, ObjectFactory.ConvertProperties(properties, null, null, CreateUpdatability), (folderId == null ? null : folderId.Id), ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); return newId == null ? null : CreateObjectId(newId); } /// public IObjectId CreateFolder(IDictionary properties, IObjectId folderId) { return CreateFolder(properties, folderId, null, null, null); } /// public IObjectId CreatePolicy(IDictionary properties, IObjectId folderId, IList policies, IList addAces, IList removeAces) { CheckProperties(properties); string newId = Binding.GetObjectService().CreatePolicy(RepositoryId, ObjectFactory.ConvertProperties(properties, null, null, CreateUpdatability), (folderId == null ? null : folderId.Id), ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); return newId == null ? null : CreateObjectId(newId); } /// public IObjectId CreatePolicy(IDictionary properties, IObjectId folderId) { return CreatePolicy(properties, folderId, null, null, null); } /// public IObjectId CreateItem(IDictionary properties, IObjectId folderId, IList policies, IList addAces, IList removeAces) { CheckProperties(properties); string newId = Binding.GetObjectService().CreateItem(RepositoryId, ObjectFactory.ConvertProperties(properties, null, null, CreateUpdatability), (folderId == null ? null : folderId.Id), ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); return newId == null ? null : CreateObjectId(newId); } /// public IObjectId CreateItem(IDictionary properties, IObjectId folderId) { return CreateItem(properties, folderId, null, null, null); } /// public IObjectId CreateRelationship(IDictionary properties, IList policies, IList addAces, IList removeAces) { CheckProperties(properties); string newId = Binding.GetObjectService().CreateRelationship(RepositoryId, ObjectFactory.ConvertProperties(properties, null, null, CreateUpdatability), ObjectFactory.ConvertPolicies(policies), ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), null); return newId == null ? null : CreateObjectId(newId); } /// public IObjectId CreateRelationship(IDictionary properties) { return CreateRelationship(properties, null, null, null); } /// public IItemEnumerable GetRelationships(IObjectId objectId, bool includeSubRelationshipTypes, RelationshipDirection? relationshipDirection, IObjectType type, IOperationContext context) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Invalid object ID!"); } string id = objectId.Id; string typeId = (type == null ? null : type.Id); IRelationshipService service = Binding.GetRelationshipService(); IOperationContext ctxt = new OperationContext(context); PageFetcher.FetchPage fetchPageDelegate = delegate(BigInteger maxNumItems, BigInteger skipCount) { // fetch the relationships IObjectList relList = service.GetObjectRelationships(RepositoryId, id, includeSubRelationshipTypes, relationshipDirection, typeId, ctxt.FilterString, ctxt.IncludeAllowableActions, maxNumItems, skipCount, null); // convert relationship objects IList page = new List(); if (relList.Objects != null) { foreach (IObjectData rod in relList.Objects) { IRelationship relationship = GetObject(CreateObjectId(rod.Id), ctxt) as IRelationship; if (relationship == null) { throw new CmisRuntimeException("Repository returned an object that is not a relationship!"); } page.Add(relationship); } } return new PageFetcher.Page(page, relList.NumItems, relList.HasMoreItems); }; return new CollectionEnumerable(new PageFetcher(DefaultContext.MaxItemsPerPage, fetchPageDelegate)); } /// public IList BulkUpdateProperties(IList objects, IDictionary properties, IList addSecondaryTypeIds, IList removeSecondaryTypeIds) { CheckCmisVersion(); CheckProperties(properties); IObjectType objectType = null; IDictionary secondaryTypes = new Dictionary(); // gather secondary types if (addSecondaryTypeIds != null) { foreach (string stid in addSecondaryTypeIds) { IObjectType secondaryType = GetTypeDefinition(stid); if (!(secondaryType is ISecondaryType)) { throw new ArgumentException("Secondary types contains a type that is not a secondary type: " + secondaryType.Id, "addSecondaryTypeIds"); } secondaryTypes[secondaryType.Id] = (ISecondaryType)secondaryType; } } // gather IDs and change tokens IList objectIdsAndChangeTokens = new List(); foreach (ICmisObject obj in objects) { if (obj == null) { continue; } objectIdsAndChangeTokens.Add(new BulkUpdateObjectIdAndChangeToken() { Id = obj.Id, ChangeToken = obj.ChangeToken }); if (objectType == null) { objectType = obj.ObjectType; } if (obj.SecondaryTypes != null) { foreach (ISecondaryType secondaryType in obj.SecondaryTypes) { secondaryTypes[secondaryType.Id] = secondaryType; } } } ISet updatebility = new HashSet(); updatebility.Add(Updatability.ReadWrite); return Binding.GetObjectService().BulkUpdateProperties(RepositoryId, objectIdsAndChangeTokens, ObjectFactory.ConvertProperties(properties, objectType, secondaryTypes.Values, updatebility), addSecondaryTypeIds, removeSecondaryTypeIds, null); } // delete /// public void Delete(IObjectId objectId) { Delete(objectId, true); } /// public void Delete(IObjectId objectId, bool allVersions) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Invalid object ID!", "objectId"); } Binding.GetObjectService().DeleteObject(RepositoryId, objectId.Id, allVersions, null); RemoveObjectFromCache(objectId); } /// public IList DeleteTree(IObjectId folderId, bool allVersions, UnfileObject? unfile, bool continueOnFailure) { if (folderId == null || folderId.Id == null) { throw new ArgumentException("Invalid object ID!", "folderId"); } IFailedToDeleteData failed = Binding.GetObjectService().DeleteTree(RepositoryId, folderId.Id, allVersions, unfile, continueOnFailure, null); if (failed == null || failed.Ids == null || failed.Ids.Count == 0) { RemoveObjectFromCache(folderId); } return failed != null ? failed.Ids : null; } // content stream /// public IContentStream GetContentStream(IObjectId docId) { return GetContentStream(docId, null, null, null); } /// public IContentStream GetContentStream(IObjectId docId, string streamId, long? offset, long? length) { if (docId == null || docId.Id == null) { throw new ArgumentException("Invalid document ID!", "objectId"); } // get the content stream IContentStream contentStream = null; try { contentStream = Binding.GetObjectService().GetContentStream(RepositoryId, docId.Id, streamId, offset, length, null); } catch (CmisConstraintException) { // no content stream return null; } return contentStream; } // permissions /// public IAcl GetAcl(IObjectId objectId, bool onlyBasicPermissions) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Invalid object ID!", "objectId"); } return Binding.GetAclService().GetAcl(RepositoryId, objectId.Id, onlyBasicPermissions, null); } /// public IAcl ApplyAcl(IObjectId objectId, IList addAces, IList removeAces, AclPropagation? aclPropagation) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Invalid object ID!", "objectId"); } return Binding.GetAclService().ApplyAcl(RepositoryId, objectId.Id, ObjectFactory.ConvertAces(addAces), ObjectFactory.ConvertAces(removeAces), aclPropagation, null); } /// public void ApplyPolicy(IObjectId objectId, params IObjectId[] policyIds) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Invalid object ID!", "objectId"); } if (policyIds == null || (policyIds.Length == 0)) { throw new ArgumentException("No Policies provided!"); } string[] ids = new string[policyIds.Length]; for (int i = 0; i < policyIds.Length; i++) { if (policyIds[i] == null || policyIds[i].Id == null) { throw new ArgumentException("A Policy ID is not set!", "policyIds"); } ids[i] = policyIds[i].Id; } foreach (string id in ids) { Binding.GetPolicyService().ApplyPolicy(RepositoryId, id, objectId.Id, null); } } /// public void RemovePolicy(IObjectId objectId, params IObjectId[] policyIds) { if (objectId == null || objectId.Id == null) { throw new ArgumentException("Invalid object ID!", "objectId"); } if (policyIds == null || policyIds.Length == 0) { throw new ArgumentException("No Policies provided!", "policyIds"); } string[] ids = new string[policyIds.Length]; for (int i = 0; i < policyIds.Length; i++) { if (policyIds[i] == null || policyIds[i].Id == null) { throw new ArgumentException("A Policy Id is not set!"); } ids[i] = policyIds[i].Id; } foreach (string id in ids) { Binding.GetPolicyService().RemovePolicy(RepositoryId, id, objectId.Id, null); } } /// /// Checks if the given string is a valid path. /// protected void CheckPath(string path) { if (path == null || path.Length < 1) { throw new ArgumentException("Invalid path!"); } if (path[0] != '/') { throw new ArgumentException("Path must start with a '/'!"); } } /// /// Checks if the CMIS version of this repository is 1.1. /// protected void CheckCmisVersion() { if (RepositoryInfo.CmisVersion == CmisVersion.Cmis_1_0) { throw new CmisNotSupportedException("This method is not supported for CMIS 1.0 repositories."); } } /// /// Checks if properties are set. /// protected void CheckProperties(IDictionary properties) { if (properties == null || properties.Count == 0) { throw new ArgumentException("Properties must not be empty!"); } } } internal class QueryStatement : IQueryStatement { private ISession session; private string statement; private IDictionary parametersDict = new Dictionary(); public QueryStatement(Session session, string statement) { if (session == null) { throw new ArgumentNullException("session"); } if (statement == null) { throw new ArgumentNullException("statement"); } this.session = session; this.statement = statement.Trim(); } /// public void SetType(int parameterIndex, string typeId) { SetType(parameterIndex, session.GetTypeDefinition(typeId)); } /// public void SetType(int parameterIndex, IObjectType type) { if (type == null) { throw new ArgumentException("Type must be set!"); } if (type.QueryName == null) { throw new ArgumentException("Type has no query name!"); } parametersDict[parameterIndex] = type.QueryName; } /// public void SetProperty(int parameterIndex, string typeId, string propertyId) { IObjectType type = session.GetTypeDefinition(typeId); IPropertyDefinition propertyDefinition = type[propertyId]; if (propertyDefinition == null) { throw new ArgumentException("Property does not exist!"); } SetProperty(parameterIndex, propertyDefinition); } /// public void SetProperty(int parameterIndex, IPropertyDefinition propertyDefinition) { if (propertyDefinition == null) { throw new ArgumentException("Property must be set!"); } string queryName = propertyDefinition.QueryName; if (queryName == null) { throw new ArgumentException("Property has no query name!"); } parametersDict[parameterIndex] = queryName; } /// public void SetInteger(int parameterIndex, params BigInteger[] num) { if (num == null || num.Length == 0) { throw new ArgumentException("Number must be set!"); } StringListBuilder slb = new StringListBuilder(","); foreach (BigInteger n in num) { if (n == null) { throw new ArgumentException("Number is null!"); } slb.Add(n.ToString("#", CultureInfo.InvariantCulture)); } parametersDict[parameterIndex] = slb.ToString(); } /// public void SetDecimal(int parameterIndex, params decimal[] num) { if (num == null || num.Length == 0) { throw new ArgumentException("Number must be set!"); } StringListBuilder slb = new StringListBuilder(","); foreach (decimal n in num) { slb.Add(n.ToString("#", CultureInfo.InvariantCulture)); } parametersDict[parameterIndex] = slb.ToString(); } /// public void SetString(int parameterIndex, params string[] str) { if (str == null || str.Length == 0) { throw new ArgumentException("String must be set!"); } StringListBuilder slb = new StringListBuilder(","); foreach (string s in str) { if (s == null) { throw new ArgumentException("String is null!"); } slb.Add(Escape(s)); } parametersDict[parameterIndex] = slb.ToString(); } /// public void SetStringLike(int parameterIndex, string str) { if (str == null) { throw new ArgumentException("String must be set!"); } parametersDict[parameterIndex] = EscapeLike(str); } /// public void SetStringContains(int parameterIndex, string str) { if (str == null) { throw new ArgumentException("String must be set!"); } parametersDict[parameterIndex] = EscapeContains(str); } /// public void SetId(int parameterIndex, params IObjectId[] id) { if (id == null || id.Length == 0) { throw new ArgumentException("Id must be set!"); } StringListBuilder slb = new StringListBuilder(","); foreach (IObjectId oid in id) { if (oid == null || oid.Id == null) { throw new ArgumentException("Id is null!"); } slb.Add(Escape(oid.Id)); } parametersDict[parameterIndex] = slb.ToString(); } /// public void SetUri(int parameterIndex, params Uri[] uri) { if (uri == null || uri.Length == 0) { throw new ArgumentException("URI must be set!"); } StringListBuilder slb = new StringListBuilder(","); foreach (Uri u in uri) { if (u == null) { throw new ArgumentException("URI is null!"); } slb.Add(Escape(u.ToString())); } parametersDict[parameterIndex] = slb.ToString(); } /// public void SetBoolean(int parameterIndex, params bool[] boolean) { if (boolean == null || boolean.Length == 0) { throw new ArgumentException("Boolean must be set!"); } StringListBuilder slb = new StringListBuilder(","); foreach (bool b in boolean) { slb.Add(b ? "TRUE" : "FALSE"); } parametersDict[parameterIndex] = slb.ToString(); } /// public void SetDateTime(int parameterIndex, params DateTime[] dt) { SetDateTime(parameterIndex, false, dt); } /// public void SetDateTime(int parameterIndex, params long[] ms) { SetDateTime(parameterIndex, false, ms); } /// public void SetDateTimeTimestamp(int parameterIndex, params DateTime[] dt) { SetDateTime(parameterIndex, true, dt); } /// public void SetDateTimeTimestamp(int parameterIndex, params long[] ms) { SetDateTime(parameterIndex, true, ms); } /// protected void SetDateTime(int parameterIndex, bool prefix, params DateTime[] cal) { if (cal == null || cal.Length == 0) { throw new ArgumentException("DateTime must be set!"); } StringBuilder sb = new StringBuilder(); foreach (DateTime dt in cal) { if (dt == null) { throw new ArgumentException("DateTime is null!"); } if (sb.Length > 0) { sb.Append(','); } if (prefix) { sb.Append("TIMESTAMP "); } DateTime tmp = dt.ToUniversalTime(); sb.Append("'"); sb.Append(tmp.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture)); sb.Append("'"); } parametersDict[parameterIndex] = sb.ToString(); } /// protected void SetDateTime(int parameterIndex, bool prefix, params long[] ms) { if (ms == null || ms.Length == 0) { throw new ArgumentException("DateTime must be set!"); } StringBuilder sb = new StringBuilder(); foreach (long dt in ms) { if (sb.Length > 0) { sb.Append(','); } if (prefix) { sb.Append("TIMESTAMP "); } DateTime tmp = DateTimeHelper.ConvertMillisToDateTime(dt).ToUniversalTime(); sb.Append("'"); sb.Append(tmp.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture)); sb.Append("'"); } parametersDict[parameterIndex] = sb.ToString(); } /// public string ToQueryString() { bool inStr = false; int parameterIndex = 0; StringBuilder sb = new StringBuilder(); for (int i = 0; i < statement.Length; i++) { char c = statement[i]; if (c == '\'') { if (inStr && statement[i - 1] == '\\') { inStr = true; } else { inStr = !inStr; } sb.Append(c); } else if (c == '?' && !inStr) { parameterIndex++; string s; if (parametersDict.TryGetValue(parameterIndex, out s)) { sb.Append(s); } else { sb.Append(c); } } else { sb.Append(c); } } return sb.ToString(); } /// public IItemEnumerable Query(bool searchAllVersions) { return session.Query(ToQueryString(), searchAllVersions); } /// public IItemEnumerable Query(bool searchAllVersions, IOperationContext context) { return session.Query(ToQueryString(), searchAllVersions, context); } // --- internal --- private static string Escape(string str) { StringBuilder sb = new StringBuilder("'"); for (int i = 0; i < str.Length; i++) { char c = str[i]; if (c == '\'' || c == '\\') { sb.Append('\\'); } sb.Append(c); } sb.Append('\''); return sb.ToString(); } private static string EscapeLike(string str) { StringBuilder sb = new StringBuilder("'"); for (int i = 0; i < str.Length; i++) { char c = str[i]; if (c == '\'') { sb.Append('\\'); } else if (c == '\\') { if (i + 1 < str.Length && (str[i + 1] == '%' || str[i + 1] == '_')) { // no additional back slash } else { sb.Append('\\'); } } sb.Append(c); } sb.Append('\''); return sb.ToString(); } private static string EscapeContains(string str) { StringBuilder sb = new StringBuilder("'"); for (int i = 0; i < str.Length; i++) { char c = str[i]; if (c == '\\') { sb.Append('\\'); } else if (c == '\'' || c == '\"') { sb.Append("\\\\\\"); } sb.Append(c); } sb.Append('\''); return sb.ToString(); } } }