Added: chemistry/portcmis/PortCMIS/binding/browser/BrowserBinding.cs URL: http://svn.apache.org/viewvc/chemistry/portcmis/PortCMIS/binding/browser/BrowserBinding.cs?rev=1691890&view=auto ============================================================================== --- chemistry/portcmis/PortCMIS/binding/browser/BrowserBinding.cs (added) +++ chemistry/portcmis/PortCMIS/binding/browser/BrowserBinding.cs Mon Jul 20 08:48:57 2015 @@ -0,0 +1,2216 @@ +/* +* 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.Browser.Json; +using PortCMIS.Binding.Http; +using PortCMIS.Binding.Impl; +using PortCMIS.Binding.Services; +using PortCMIS.Client; +using PortCMIS.Data; +using PortCMIS.Data.Extensions; +using PortCMIS.Enums; +using PortCMIS.Exceptions; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace PortCMIS.Binding.Browser +{ + public class RepositoryInfoBrowserBinding : RepositoryInfo + { + public string RepositoryUrl { get; set; } + public string RootUrl { get; set; } + } + + /// <summary> + /// Browser binding SPI. + /// </summary> + internal class CmisBrowserSpi : ICmisSpi + { + public const string RepositoryUrlCache = "org.apache.chemistry.portcmis.binding.browser.repositoryurls"; + + private BindingSession session; + private RepositoryService repositoryService; + private NavigationService navigationService; + private ObjectService objectService; + private VersioningService versioningService; + private DiscoveryService discoveryService; + private MultiFilingService multiFilingService; + private RelationshipService relationshipService; + private PolicyService policyService; + private AclService aclService; + + public void Initialize(IBindingSession session) + { + this.session = session as BindingSession; + if (this.session == null) + { + throw new ArgumentException("Inavlid binding session!"); + } + + repositoryService = new RepositoryService(this.session); + navigationService = new NavigationService(this.session); + objectService = new ObjectService(this.session); + versioningService = new VersioningService(this.session); + discoveryService = new DiscoveryService(this.session); + multiFilingService = new MultiFilingService(this.session); + relationshipService = new RelationshipService(this.session); + policyService = new PolicyService(this.session); + aclService = new AclService(this.session); + } + + public IRepositoryService GetRepositoryService() + { + return repositoryService; + } + + public INavigationService GetNavigationService() + { + return navigationService; + } + + public IObjectService GetObjectService() + { + return objectService; + } + + public IVersioningService GetVersioningService() + { + return versioningService; + } + + public IRelationshipService GetRelationshipService() + { + return relationshipService; + } + + public IDiscoveryService GetDiscoveryService() + { + return discoveryService; + } + + public IMultiFilingService GetMultiFilingService() + { + return multiFilingService; + } + + public IAclService GetAclService() + { + return aclService; + } + + public IPolicyService GetPolicyService() + { + return policyService; + } + + public void ClearAllCaches() + { + session.RemoveValue(RepositoryUrlCache); + } + + public void ClearRepositoryCache(string repositoryId) + { + RepositoryUrlCache repUrlCache = session.GetValue(RepositoryUrlCache) as RepositoryUrlCache; + if (repUrlCache != null) + { + repUrlCache.RemoveRepository(repositoryId); + } + } + + public void Dispose() + { + // nothing to do + } + } + + internal class ClientTypeCache : ITypeCache + { + private string RepositoryId { get; set; } + private AbstractBrowserBindingService Service { get; set; } + + public ClientTypeCache(string repositoryId, AbstractBrowserBindingService service) + { + this.RepositoryId = repositoryId; + this.Service = service; + } + + public ITypeDefinition GetTypeDefinition(string typeId) + { + TypeDefinitionCache cache = Service.Session.GetTypeDefinitionCache(); + + ITypeDefinition type = cache.Get(RepositoryId, typeId); + if (type == null) + { + type = Service.GetTypeDefinitionInternal(RepositoryId, typeId); + if (type != null) + { + cache.Put(RepositoryId, type); + } + } + + return type; + } + + public ITypeDefinition ReloadTypeDefinition(string typeId) + { + TypeDefinitionCache cache = Service.Session.GetTypeDefinitionCache(); + + ITypeDefinition type = Service.GetTypeDefinitionInternal(RepositoryId, typeId); + if (type != null) + { + cache.Put(RepositoryId, type); + } + + return type; + } + + public ITypeDefinition GetTypeDefinitionForObject(string objectId) + { + return null; + } + + public IPropertyDefinition GetPropertyDefinition(string propId) + { + return null; + } + } + + internal class FormDataComposer + { + public string CmisAction { get; private set; } + + public IContentStream Stream { get; set; } + + public IProperties Properties { get; set; } + public bool Succinct { get; set; } + public DateTimeFormat DateTimeFormat { get; set; } + + public IAcl AddAces { get; set; } + public IAcl RemoveAces { get; set; } + + public IList<string> Policies { get; set; } + public string PolicyId { get; set; } + + public IList<string> AddSecondaryTypeIds { get; set; } + public IList<string> RemoveSecondaryTypeIds { get; set; } + + public IList<IBulkUpdateObjectIdAndChangeToken> ObjectIdsAndChangeTokens { get; set; } + + private IDictionary<string, object> parameters; + + public IDictionary<string, object> Parameters + { + get + { + if (parameters == null) + { + parameters = new Dictionary<string, object>(); + } + return parameters; + } + set { parameters = value; } + } + + public FormDataComposer(string cmisAction) + { + CmisAction = cmisAction; + } + + public HttpContent CreateHttpContent() + { + if (Stream == null) + { + return CreateFormUrlEncodedContent(); + } + else + { + return CreateMultipartFormDataContent(); + } + } + + protected FormUrlEncodedContent CreateFormUrlEncodedContent() + { + return new FormUrlEncodedContent(CreateContent()); + } + + protected MultipartFormDataContent CreateMultipartFormDataContent() + { + MultipartFormDataContent content = new MultipartFormDataContent(); + + IList<KeyValuePair<string, string>> parameters = CreateContent(); + foreach (KeyValuePair<string, string> p in parameters) + { + content.Add(new StringContent(p.Value, Encoding.UTF8), p.Key); + } + + if (Stream.Stream != null) + { + StreamContent streamContent = new StreamContent(Stream.Stream); + streamContent.Headers.ContentType = new MediaTypeHeaderValue(Stream.MimeType ?? "applictaion/octet-stream"); + + content.Add(streamContent, "content", Stream.FileName ?? "content"); + } + + return content; + } + + protected IList<KeyValuePair<string, string>> CreateContent() + { + IList<KeyValuePair<string, string>> result = new List<KeyValuePair<string, string>>(); + + // set cmisaction + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlCmisAction, CmisAction)); + + // set parameters + if (parameters != null) + { + foreach (KeyValuePair<string, object> p in parameters) + { + if (p.Value != null) + { + result.Add(new KeyValuePair<string, string>(p.Key, UrlBuilder.NormalizeParameter(p.Value))); + } + } + } + + // set succinct + if (Succinct) + { + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlSuccinct, "true")); + } + + // set properties + AddPropertiesParameters(Properties, result); + + // set Aces + AddAcesParameters(AddAces, BindingConstants.ControlAddAcePrincipal, BindingConstants.ControlRemoveAcePermission, result); + AddAcesParameters(RemoveAces, BindingConstants.ControlRemoveAcePrincipal, BindingConstants.ControlRemoveAcePermission, result); + + // set policies + AddPoliciesParameters(Policies, result); + AddPolicyIdParameter(PolicyId, result); + + // set secondary type IDs + AddSecondaryTypeIdParameters(AddSecondaryTypeIds, BindingConstants.ControlAddSecondaryType, result); + AddSecondaryTypeIdParameters(RemoveSecondaryTypeIds, BindingConstants.ControlRemoveSecondaryType, result); + + // set bulk update values + AddObjectIdsAndChangeTokens(ObjectIdsAndChangeTokens, result); + + return result; + } + + private void AddPropertiesParameters(IProperties properties, IList<KeyValuePair<string, string>> result) + { + if (properties == null || properties.PropertyList == null) + { + return; + } + + int idx = 0; + foreach (PropertyData prop in properties.PropertyList) + { + if (prop == null) + { + continue; + } + + string idxStr = "[" + idx + "]"; + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlPropId + idxStr, prop.Id)); + + if (prop.Values != null && prop.Values.Count > 0) + { + if (prop.Values.Count == 1) + { + result.Add(new KeyValuePair<string, string>( + BindingConstants.ControlPropValue + idxStr, ConvertPropertyValue(prop.FirstValue, DateTimeFormat))); + } + else + { + int vidx = 0; + foreach (object obj in prop.Values) + { + string vidxStr = "[" + vidx + "]"; + result.Add(new KeyValuePair<string, string>( + BindingConstants.ControlPropValue + idxStr + vidxStr, ConvertPropertyValue(obj, DateTimeFormat))); + vidx++; + } + } + } + idx++; + } + } + + private void AddAcesParameters(IAcl acl, string principalControl, string permissionControl, IList<KeyValuePair<string, string>> result) + { + if (acl == null || acl.Aces == null) + { + return; + } + + int idx = 0; + foreach (IAce ace in acl.Aces) + { + if (ace.PrincipalId != null && ace.Permissions != null && ace.Permissions.Count > 0) + { + string idxStr = "[" + idx + "]"; + result.Add(new KeyValuePair<string, string>(principalControl + idxStr, ace.PrincipalId)); + + int permIdx = 0; + foreach (string perm in ace.Permissions) + { + if (perm != null) + { + string permIdxStr = "[" + permIdx + "]"; + result.Add(new KeyValuePair<string, string>(permissionControl + idxStr + permIdxStr, perm)); + permIdx++; + } + } + idx++; + } + } + } + + private void AddPoliciesParameters(IList<string> policies, IList<KeyValuePair<string, string>> result) + { + if (policies == null) + { + return; + } + + int idx = 0; + foreach (string policy in policies) + { + if (policy != null) + { + string idxStr = "[" + idx + "]"; + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlPolicy + idxStr, policy)); + idx++; + } + } + } + + private void AddPolicyIdParameter(string policyId, IList<KeyValuePair<string, string>> result) + { + if (policyId == null) + { + return; + } + + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlPolicyId, policyId)); + } + + private void AddSecondaryTypeIdParameters(IList<string> secondaryTypeIds, string secondaryTypeIdControl, IList<KeyValuePair<string, string>> result) + { + if (secondaryTypeIds == null || secondaryTypeIds.Count == 0) + { + return; + } + + int idx = 0; + foreach (string typeId in secondaryTypeIds) + { + if (typeId == null || typeId.Length == 0) + { + continue; + } + + string idxStr = "[" + idx + "]"; + result.Add(new KeyValuePair<string, string>(secondaryTypeIdControl + idxStr, typeId)); + + idx++; + } + } + + public void AddObjectIdsAndChangeTokens(IList<IBulkUpdateObjectIdAndChangeToken> objectIdsAndChangeTokens, IList<KeyValuePair<string, string>> result) + { + if (objectIdsAndChangeTokens == null || objectIdsAndChangeTokens.Count == 0) + { + return; + } + + int idx = 0; + foreach (IBulkUpdateObjectIdAndChangeToken oc in objectIdsAndChangeTokens) + { + if (oc == null || oc.Id == null || oc.Id.Length == 0) + { + continue; + } + + string idxStr = "[" + idx + "]"; + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlObjectId + idxStr, oc.Id)); + result.Add(new KeyValuePair<string, string>(BindingConstants.ControlChangeToken + idxStr, oc.ChangeToken ?? "")); + + idx++; + } + } + + private string ConvertPropertyValue(object value, DateTimeFormat dateTimeFormat) + { + if (value == null) + { + return null; + } + else if (value is DateTime) + { + if (DateTimeFormat == DateTimeFormat.Extended) + { + return DateTimeHelper.FormatISO8601((DateTime)value); + } + else + { + return DateTimeHelper.ConvertDateTimeToMillis((DateTime)value).ToString(); + } + } + else if (value is decimal) + { + return ((decimal)value).ToString("#", CultureInfo.InvariantCulture); + } + else if (value is BigInteger) + { + return ((BigInteger)value).ToString("#", CultureInfo.InvariantCulture); + } + else + { + return value.ToString(); + } + } + } + + + /// <summary> + /// Common service data and operations. + /// </summary> + internal abstract class AbstractBrowserBindingService + { + private BindingSession session; + + public BindingSession Session + { + get + { + return session; + } + protected set + { + session = value; + + Succinct = true; + object succintObj = session.GetValue(SessionParameter.BrowserSuccinct); + if (succintObj is string) + { + Succinct = Convert.ToBoolean((string)succintObj); + } + + DateTimeFormat = DateTimeFormat.Simple; + object dateTimeFormatObj = session.GetValue(SessionParameter.BrowserDateTimeFormat); + if (dateTimeFormatObj is string) + { + DateTimeFormat? dtf = ((string)dateTimeFormatObj).GetCmisEnum<DateTimeFormat>(); + DateTimeFormat = dtf ?? DateTimeFormat.Simple; + } + } + } + protected bool Succinct { get; private set; } + protected string SuccinctParameter { get { return Succinct ? "true" : null; } } + + protected DateTimeFormat DateTimeFormat { get; private set; } + protected string DateTimeFormatParameter { get { return DateTimeFormat == DateTimeFormat.Simple ? null : DateTimeFormat.GetCmisValue(); } } + + protected string GetServiceUrl() + { + return Session.GetValue(SessionParameter.BrowserUrl) as string; + } + + protected UrlBuilder GetRepositoryUrl(string repositoryId, string selector) + { + UrlBuilder result = GetRepositoryUrlCache().GetRepositoryUrl(repositoryId, selector); + + if (result == null) + { + GetRepositoriesInternal(repositoryId); + result = GetRepositoryUrlCache().GetRepositoryUrl(repositoryId, selector); + } + + if (result == null) + { + throw new CmisObjectNotFoundException("Unknown repository!"); + } + + return result; + } + + protected UrlBuilder GetRepositoryUrl(string repositoryId) + { + UrlBuilder result = GetRepositoryUrlCache().GetRepositoryUrl(repositoryId); + + if (result == null) + { + GetRepositoriesInternal(repositoryId); + result = GetRepositoryUrlCache().GetRepositoryUrl(repositoryId); + } + + if (result == null) + { + throw new CmisObjectNotFoundException("Unknown repository!"); + } + + return result; + } + + protected UrlBuilder GetObjectUrl(string repositoryId, string objectId, string selector) + { + UrlBuilder result = GetRepositoryUrlCache().GetObjectUrl(repositoryId, objectId, selector); + + if (result == null) + { + GetRepositoriesInternal(repositoryId); + result = GetRepositoryUrlCache().GetObjectUrl(repositoryId, objectId, selector); + } + + if (result == null) + { + throw new CmisObjectNotFoundException("Unknown repository!"); + } + + return result; + } + + protected UrlBuilder GetObjectUrl(string repositoryId, string objectId) + { + UrlBuilder result = GetRepositoryUrlCache().GetObjectUrl(repositoryId, objectId); + + if (result == null) + { + GetRepositoriesInternal(repositoryId); + result = GetRepositoryUrlCache().GetObjectUrl(repositoryId, objectId); + } + + if (result == null) + { + throw new CmisObjectNotFoundException("Unknown repository!"); + } + + return result; + } + + protected UrlBuilder GetPathUrl(string repositoryId, string path, string selector) + { + UrlBuilder result = GetRepositoryUrlCache().GetPathUrl(repositoryId, path, selector); + + if (result == null) + { + GetRepositoriesInternal(repositoryId); + result = GetRepositoryUrlCache().GetPathUrl(repositoryId, path, selector); + } + + if (result == null) + { + throw new CmisObjectNotFoundException("Unknown repository!"); + } + + return result; + } + + + protected RepositoryUrlCache GetRepositoryUrlCache() + { + RepositoryUrlCache repositoryUrlCache = Session.GetValue(CmisBrowserSpi.RepositoryUrlCache) as RepositoryUrlCache; + if (repositoryUrlCache == null) + { + repositoryUrlCache = new RepositoryUrlCache(); + Session.PutValue(CmisBrowserSpi.RepositoryUrlCache, repositoryUrlCache); + } + + return repositoryUrlCache; + } + + protected void SetChangeToken(ref string changeToken, IObjectData obj) + { + if (changeToken == null) + { + return; + } + + changeToken = null; + + if (obj == null || obj.Properties == null) + { + return; + } + + IPropertyData ct = obj.Properties[PropertyIds.ChangeToken]; + if (ct != null && ct.PropertyType == PropertyType.String) + { + changeToken = (string)ct.FirstValue; + } + } + + // ---- exceptions ---- + + /// <summary> + /// Converts an error message or a HTTP status code into an Exception. + /// </summary> + protected CmisBaseException ConvertStatusCode(int code, string message, string errorContent, Exception e) + { + object obj = null; + try + { + if (errorContent != null) + { + JsonParser parser = new JsonParser(); + obj = parser.Parse(new StringReader(errorContent)); + } + } + catch (JsonParseException) + { + // error content is not valid JSON -> ignore + } + + if (obj is JsonObject) + { + JsonObject json = (JsonObject)obj; + object jsonError = json[BrowserConstants.ErrorException]; + if (jsonError is string) + { + object jsonMessage = json[BrowserConstants.ErrorMessage]; + if (jsonMessage != null) + { + message = jsonMessage.ToString(); + } + + if (CmisConstraintException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisConstraintException(message, errorContent, e); + } + else if (CmisContentAlreadyExistsException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisContentAlreadyExistsException(message, errorContent, e); + } + else if (CmisFilterNotValidException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisFilterNotValidException(message, errorContent, e); + } + else if (CmisInvalidArgumentException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisInvalidArgumentException(message, errorContent, e); + } + else if (CmisNameConstraintViolationException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisNameConstraintViolationException(message, errorContent, e); + } + else if (CmisNotSupportedException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisNotSupportedException(message, errorContent, e); + } + else if (CmisObjectNotFoundException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisObjectNotFoundException(message, errorContent, e); + } + else if (CmisPermissionDeniedException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisPermissionDeniedException(message, errorContent, e); + } + else if (CmisStorageException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisStorageException(message, errorContent, e); + } + else if (CmisStreamNotSupportedException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisStreamNotSupportedException(message, errorContent, e); + } + else if (CmisUpdateConflictException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisUpdateConflictException(message, errorContent, e); + } + else if (CmisVersioningException.ExceptionName.Equals((string)jsonError, StringComparison.OrdinalIgnoreCase)) + { + return new CmisVersioningException(message, errorContent, e); + } + else if (code == 503) + { + return new CmisServiceUnavailableException(message, errorContent, e); + } + } + } + + // fall back to status code + switch (code) + { + case 301: + case 302: + case 303: + case 307: + return new CmisConnectionException("Redirects are not supported (HTTP status code " + code + "): " + message, errorContent, e); + case 400: + return new CmisInvalidArgumentException(message, errorContent, e); + case 401: + return new CmisUnauthorizedException(message, errorContent, e); + case 403: + return new CmisPermissionDeniedException(message, errorContent, e); + case 404: + return new CmisObjectNotFoundException(message, errorContent, e); + case 405: + return new CmisNotSupportedException(message, errorContent, e); + case 407: + return new CmisProxyAuthenticationException(message, errorContent, e); + case 409: + return new CmisConstraintException(message, errorContent, e); + case 503: + return new CmisServiceUnavailableException(message, errorContent, e); + default: + return new CmisRuntimeException(message, errorContent, e); + } + } + + + // ---- helpers ---- + + /// <summary> + /// Parses an object from an input stream. + /// </summary> + protected JsonObject ParseObject(Stream stream, string charset) + { + object obj = Parse(stream, charset); + + if (obj is JsonObject) + { + return (JsonObject)obj; + } + + throw new CmisConnectionException("Unexpected object!"); + } + + /// <summary> + /// Parses an array from an input stream. + /// </summary> + protected JsonArray ParseArray(Stream stream, string charset) + { + object obj = Parse(stream, charset); + + if (obj is JsonArray) + { + return (JsonArray)obj; + } + + throw new CmisConnectionException("Unexpected object!"); + } + + /// <summary> + /// Parses an input stream. + /// </summary> + protected object Parse(Stream stream, string charset) + { + Encoding enc; + if (charset == null) + { + enc = Encoding.UTF8; + } + else + { + try + { + enc = Encoding.GetEncoding(charset); + } + catch (Exception e) + { + throw new CmisConnectionException("Unsupported charset: " + charset, e); + } + } + + StreamReader reader = null; + + object obj = null; + try + { + reader = new StreamReader(stream, enc); + JsonParser parser = new JsonParser(); + obj = parser.Parse(reader); + } + catch (Exception e) + { + throw new CmisConnectionException("Parsing exception!", e); + } + finally + { + IOUtils.ConsumeAndClose(reader); + if (reader == null) + { + stream.Dispose(); + } + } + + return obj; + } + + /// <summary> + /// Performs a GET on an URL, checks the response code and returns the + /// result. + /// </summary> + protected IResponse Read(UrlBuilder url) + { + // make the call + IResponse resp = Session.GetHttpInvoker().InvokeGET(url, session); + + // check response code + if (resp.StatusCode != 200) + { + throw ConvertStatusCode(resp.StatusCode, resp.Message, resp.ErrorContent, null); + } + + return resp; + } + + + /// <summary> + /// Performs a POST on an URL, checks the response code and returns the + /// result. + /// </summary> + protected IResponse Post(UrlBuilder url, HttpContent content) + { + // make the call + IResponse resp = Session.GetHttpInvoker().InvokePOST(url, content, session); + + // check response code + if (resp.StatusCode != 200 && resp.StatusCode != 201) + { + throw ConvertStatusCode(resp.StatusCode, resp.Message, resp.ErrorContent, null); + } + + return resp; + } + + /// <summary> + /// Performs a POST on an URL, checks the response code and returns the + /// result. + /// </summary> + protected void PostAndConsume(UrlBuilder url, HttpContent content) + { + IResponse resp = Post(url, content); + IOUtils.ConsumeAndClose(resp.Stream); + } + + // ----- + + protected IList<IRepositoryInfo> GetRepositoriesInternal(string repositoryId) + { + UrlBuilder url = null; + + if (repositoryId == null) + { + // no repository id provided -> get all + url = new UrlBuilder(GetServiceUrl()); + } + else + { + // use URL of the specified repository + url = GetRepositoryUrlCache().GetRepositoryUrl(repositoryId, BindingConstants.SelectorRepositoryInfo); + if (url == null) + { + // repository infos haven't been fetched yet -> get them all + url = new UrlBuilder(GetServiceUrl()); + } + } + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + IList<IRepositoryInfo> repInfos = new List<IRepositoryInfo>(); + + foreach (KeyValuePair<string, object> jri in json) + { + if (jri.Value is JsonObject) + { + IRepositoryInfo ri = JsonConverter.ConvertRepositoryInfo((JsonObject)jri.Value); + string id = ri.Id; + + if (ri is RepositoryInfoBrowserBinding) + { + string repositoryUrl = ((RepositoryInfoBrowserBinding)ri).RepositoryUrl; + string rootUrl = ((RepositoryInfoBrowserBinding)ri).RootUrl; + + if (id == null || repositoryUrl == null || rootUrl == null) + { + throw new CmisConnectionException("Found invalid Repository Info! (id: " + id + ")"); + } + + GetRepositoryUrlCache().AddRepository(id, repositoryUrl, rootUrl); + } + + repInfos.Add(ri); + } + else + { + throw new CmisConnectionException("Found invalid Repository Info!"); + } + } + + return repInfos; + } + + /** + * Retrieves a type definition. + */ + public ITypeDefinition GetTypeDefinitionInternal(string repositoryId, string typeId) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId, BindingConstants.SelectorTypeDefinition); + url.AddParameter(BindingConstants.ParamTypeId, typeId); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + return JsonConverter.ConvertTypeDefinition(json); + } + } + + internal class RepositoryService : AbstractBrowserBindingService, IRepositoryService + { + public RepositoryService(BindingSession session) + { + Session = session; + } + + public IList<IRepositoryInfo> GetRepositoryInfos(IExtensionsData extension) + { + return GetRepositoriesInternal(null); + } + + public IRepositoryInfo GetRepositoryInfo(string repositoryId, IExtensionsData extension) + { + IList<IRepositoryInfo> repositoryInfos = GetRepositoriesInternal(repositoryId); + + if (repositoryInfos.Count == 0) + { + throw new CmisObjectNotFoundException("Repository '" + repositoryId + "'not found!"); + } + + if (repositoryInfos.Count == 1) + { + return repositoryInfos[0]; + } + + // find the repository + foreach (IRepositoryInfo info in repositoryInfos) + { + if (info.Id == null) + { + continue; + } + + if (info.Id == repositoryId) + { + return info; + } + } + + throw new CmisObjectNotFoundException("Repository '" + repositoryId + "'not found!"); + } + + public ITypeDefinitionList GetTypeChildren(string repositoryId, string typeId, bool? includePropertyDefinitions, + BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId, BindingConstants.SelectorTypeChildren); + url.AddParameter(BindingConstants.ParamTypeId, typeId); + url.AddParameter(BindingConstants.ParamPropertyDefinitions, includePropertyDefinitions); + url.AddParameter(BindingConstants.ParamMaxItems, maxItems); + url.AddParameter(BindingConstants.ParamSkipCount, skipCount); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + return JsonConverter.ConvertTypeChildren(json); + } + + public IList<ITypeDefinitionContainer> GetTypeDescendants(string repositoryId, string typeId, BigInteger? depth, + bool? includePropertyDefinitions, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId, BindingConstants.SelectorTypeDecendants); + url.AddParameter(BindingConstants.ParamTypeId, typeId); + url.AddParameter(BindingConstants.ParamDepth, depth); + url.AddParameter(BindingConstants.ParamPropertyDefinitions, includePropertyDefinitions); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + return JsonConverter.ConvertTypeDescendants(json); + } + + public ITypeDefinition GetTypeDefinition(string repositoryId, string typeId, IExtensionsData extension) + { + return GetTypeDefinitionInternal(repositoryId, typeId); + } + + + public ITypeDefinition CreateType(string repositoryId, ITypeDefinition type, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreateType); + if (type != null) + { + StringWriter sw = new StringWriter(); + JsonConverter.Convert(type, DateTimeFormat).WriteJsonString(sw); + + composer.Parameters[BindingConstants.ControlType] = sw.ToString(); + } + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + return JsonConverter.ConvertTypeDefinition(json); + } + + public ITypeDefinition UpdateType(string repositoryId, ITypeDefinition type, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionUpdateType); + if (type != null) + { + StringWriter sw = new StringWriter(); + JsonConverter.Convert(type, DateTimeFormat).WriteJsonString(sw); + + composer.Parameters[BindingConstants.ControlType] = sw.ToString(); + } + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + return JsonConverter.ConvertTypeDefinition(json); + } + + public void DeleteType(string repositoryId, string typeId, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionDeleteType); + composer.Parameters[BindingConstants.ControlTypeId] = typeId; + + // send + PostAndConsume(url, composer.CreateHttpContent()); + } + } + + internal class NavigationService : AbstractBrowserBindingService, INavigationService + { + public NavigationService(BindingSession session) + { + Session = session; + } + + public IObjectInFolderList GetChildren(string repositoryId, string folderId, string filter, string orderBy, + bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter, + bool? includePathSegment, BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, folderId, BindingConstants.SelectorChildren); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamOrderBy, orderBy); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamPathSegment, includePathSegment); + url.AddParameter(BindingConstants.ParamMaxItems, maxItems); + url.AddParameter(BindingConstants.ParamSkipCount, skipCount); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObjectInFolderList(json, typeCache); + } + + public IList<IObjectInFolderContainer> GetDescendants(string repositoryId, string folderId, BigInteger? depth, string filter, + bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter, + bool? includePathSegment, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, folderId, BindingConstants.SelectorDecendants); + url.AddParameter(BindingConstants.ParamDepth, depth); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamPathSegment, includePathSegment); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertDescendants(json, typeCache); + } + + public IList<IObjectInFolderContainer> GetFolderTree(string repositoryId, string folderId, BigInteger? depth, string filter, + bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter, + bool? includePathSegment, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, folderId, BindingConstants.SelectorFolderTree); + url.AddParameter(BindingConstants.ParamDepth, depth); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamPathSegment, includePathSegment); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertDescendants(json, typeCache); + } + + public IList<IObjectParentData> GetObjectParents(string repositoryId, string objectId, string filter, + bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter, + bool? includeRelativePathSegment, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorParents); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamRelativePathSegment, includeRelativePathSegment); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObjectParents(json, typeCache); + } + + public IObjectData GetFolderParent(string repositoryId, string folderId, string filter, ExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, folderId, BindingConstants.SelectorParent); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObject(json, typeCache); + } + + public IObjectList GetCheckedOutDocs(string repositoryId, string folderId, string filter, string orderBy, + bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter, + BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension) + { + // build URL + UrlBuilder url = (folderId != null ? GetObjectUrl(repositoryId, folderId, BindingConstants.SelectorCheckedout) + : GetRepositoryUrl(repositoryId, BindingConstants.SelectorCheckedout)); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamOrderBy, orderBy); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamMaxItems, maxItems); + url.AddParameter(BindingConstants.ParamSkipCount, skipCount); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObjectList(json, typeCache, false); + } + } + + internal class ObjectService : AbstractBrowserBindingService, IObjectService + { + public ObjectService(BindingSession session) + { + Session = session; + } + + public string CreateDocument(string repositoryId, IProperties properties, string folderId, IContentStream contentStream, + VersioningState? versioningState, IList<string> policies, IAcl addAces, IAcl removeAces, IExtensionsData extension) + { + // build URL + UrlBuilder url = (folderId != null ? GetObjectUrl(repositoryId, folderId) : GetRepositoryUrl(repositoryId)); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreateDocument); + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Parameters[BindingConstants.ParamVersioningState] = versioningState; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + composer.Stream = contentStream; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + return (newObj == null ? null : newObj.Id); + } + + public string CreateDocumentFromSource(string repositoryId, string sourceId, IProperties properties, string folderId, + VersioningState? versioningState, IList<string> policies, IAcl addAces, IAcl removeAces, IExtensionsData extension) + { + // build URL + UrlBuilder url = (folderId != null ? GetObjectUrl(repositoryId, folderId) : GetRepositoryUrl(repositoryId)); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreateDocumentFromSource); + composer.Parameters[BindingConstants.ParamSourceId] = sourceId; + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Parameters[BindingConstants.ParamVersioningState] = versioningState; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + return (newObj == null ? null : newObj.Id); + } + + public string CreateFolder(string repositoryId, IProperties properties, string folderId, IList<string> policies, + IAcl addAces, IAcl removeAces, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, folderId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreateFolder); + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + return (newObj == null ? null : newObj.Id); + } + + public string CreateRelationship(string repositoryId, IProperties properties, IList<string> policies, IAcl addAces, + IAcl removeAces, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreateRelationship); + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + return (newObj == null ? null : newObj.Id); + } + + public string CreatePolicy(string repositoryId, IProperties properties, string folderId, IList<string> policies, + IAcl addAces, IAcl removeAces, IExtensionsData extension) + { + // build URL + UrlBuilder url = (folderId != null ? GetObjectUrl(repositoryId, folderId) : GetRepositoryUrl(repositoryId)); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreatePolicy); + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + return (newObj == null ? null : newObj.Id); + } + + public string CreateItem(string repositoryId, IProperties properties, string folderId, IList<string> policies, + IAcl addAces, IAcl removeAces, IExtensionsData extension) + { + // build URL + UrlBuilder url = (folderId != null ? GetObjectUrl(repositoryId, folderId) : GetRepositoryUrl(repositoryId)); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCreateItem); + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + return (newObj == null ? null : newObj.Id); + } + + public IAllowableActions GetAllowableActions(string repositoryId, string objectId, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorAllowableActionS); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + return JsonConverter.ConvertAllowableActions(json); + } + + public IProperties GetProperties(string repositoryId, string objectId, string filter, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorProperties); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + if (Succinct) + { + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + return JsonConverter.ConvertSuccinctProperties(json, null, typeCache); + } + else + { + return JsonConverter.ConvertProperties(json, null); + } + } + + public IList<IRenditionData> GetRenditions(string repositoryId, string objectId, string renditionFilter, + BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorRenditions); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamMaxItems, maxItems); + url.AddParameter(BindingConstants.ParamSkipCount, skipCount); + + // read and parse + IResponse resp = Read(url); + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + return JsonConverter.ConvertRenditions(json); + } + + public IObjectData GetObject(string repositoryId, string objectId, string filter, bool? includeAllowableActions, + IncludeRelationships? includeRelationships, string renditionFilter, bool? includePolicyIds, + bool? includeAcl, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorObject); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamPolicyIds, includePolicyIds); + url.AddParameter(BindingConstants.ParamAcl, includeAcl); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObject(json, typeCache); + } + + public IObjectData GetObjectByPath(string repositoryId, string path, string filter, bool? includeAllowableActions, + IncludeRelationships? includeRelationships, string renditionFilter, bool? includePolicyIds, bool? includeAcl, + IExtensionsData extension) + { + // build URL + UrlBuilder url = GetPathUrl(repositoryId, path, BindingConstants.SelectorObject); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamPolicyIds, includePolicyIds); + url.AddParameter(BindingConstants.ParamAcl, includeAcl); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObject(json, typeCache); + } + + public IContentStream GetContentStream(string repositoryId, string objectId, string streamId, BigInteger? offset, BigInteger? length, + IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorContent); + url.AddParameter(BindingConstants.ParamStreamId, streamId); + + // get the content + IResponse resp = Session.GetHttpInvoker().InvokeGET(url, Session, (long?)offset, (long?)length); + + // check response code + if ((resp.StatusCode != 200) && (resp.StatusCode != 206)) + { + throw ConvertStatusCode(resp.StatusCode, resp.Message, resp.ErrorContent, null); + } + + // build result object + ContentStream result; + if (resp.StatusCode == 206) + { + result = new PartialContentStream(); + } + else + { + result = new ContentStream(); + } + + result.FileName = resp.Filename; + result.Length = resp.ContentLength; + result.MimeType = resp.ContentType; + result.Stream = resp.Stream; + + return result; + } + + public void UpdateProperties(string repositoryId, ref string objectId, ref string changeToken, IProperties properties, + IExtensionsData extension) + { + // we need an object ID + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionUpdateProperties); + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Parameters[BindingConstants.ParamChangeToken] = + (changeToken == null || Session.GetValue(SessionParameter.OmitChangeTokens, false) ? null : changeToken); + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + + SetChangeToken(ref changeToken, newObj); + } + + public IList<IBulkUpdateObjectIdAndChangeToken> BulkUpdateProperties(string repositoryId, + IList<IBulkUpdateObjectIdAndChangeToken> objectIdAndChangeToken, IProperties properties, + IList<string> addSecondaryTypeIds, IList<string> removeSecondaryTypeIds, IExtensionsData extension) + { + // we need object ids + if (objectIdAndChangeToken == null || objectIdAndChangeToken.Count == 0) + { + throw new CmisInvalidArgumentException("Object IDs must be set!"); + } + + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionBulkUpdate); + composer.ObjectIdsAndChangeTokens = objectIdAndChangeToken; + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.AddSecondaryTypeIds = addSecondaryTypeIds; + composer.RemoveSecondaryTypeIds = removeSecondaryTypeIds; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + return JsonConverter.ConvertBulkUpdate(json); + } + + public void MoveObject(string repositoryId, ref string objectId, string targetFolderId, string sourceFolderId, + IExtensionsData extension) + { + // we need an object id + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionMove); + composer.Parameters[BindingConstants.ParamTargetFolderId] = targetFolderId; + composer.Parameters[BindingConstants.ParamSourceFolderId] = sourceFolderId; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + } + + public void DeleteObject(string repositoryId, string objectId, bool? allVersions, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionDelete); + composer.Parameters[BindingConstants.ParamAllVersions] = allVersions; + + // send + PostAndConsume(url, composer.CreateHttpContent()); + } + + public IFailedToDeleteData DeleteTree(string repositoryId, string folderId, bool? allVersions, UnfileObject? unfileObjects, + bool? continueOnFailure, ExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, folderId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionDeleteTree); + composer.Parameters[BindingConstants.ParamAllVersions] = allVersions; + composer.Parameters[BindingConstants.ParamUnfileObjects] = unfileObjects; + composer.Parameters[BindingConstants.ParamContinueOnFailure] = continueOnFailure; + + // send + IResponse resp = Post(url, composer.CreateHttpContent()); + + if (resp.StatusCode == 200 && resp.ContentLength > 0 && (!resp.Stream.CanSeek || resp.Stream.Length > 0)) + { + try + { + JsonObject json = ParseObject(resp.Stream, resp.Charset); + return JsonConverter.ConvertFailedToDelete(json); + } + catch (IOException e) + { + throw new CmisConnectionException("Cannot read response!", e); + } + } + + return new FailedToDeleteData(); + } + + public void SetContentStream(string repositoryId, ref string objectId, bool? overwriteFlag, ref string changeToken, + IContentStream contentStream, IExtensionsData extension) + { + // we need an object id + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionSetContent); + composer.Stream = contentStream; + composer.Parameters[BindingConstants.ParamOverwriteFlag] = overwriteFlag; + composer.Succinct = Succinct; + composer.Parameters[BindingConstants.ParamChangeToken] = + (changeToken == null || Session.GetValue(SessionParameter.OmitChangeTokens, false) ? null : changeToken); + + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + + SetChangeToken(ref changeToken, newObj); + } + + public void AppendContentStream(string repositoryId, ref string objectId, bool? isLastChunk, ref string changeToken, + IContentStream contentStream, IExtensionsData extension) + { + // we need an object id + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionAppendContent); + composer.Stream = contentStream; + composer.Parameters[BindingConstants.ControlIsLastChunk] = isLastChunk; + composer.Succinct = Succinct; + composer.Parameters[BindingConstants.ParamChangeToken] = + (changeToken == null || Session.GetValue(SessionParameter.OmitChangeTokens, false) ? null : changeToken); + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + + SetChangeToken(ref changeToken, newObj); + } + + public void DeleteContentStream(string repositoryId, ref string objectId, ref string changeToken, IExtensionsData extension) + { + // we need an object id + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionDeleteContent); + composer.Succinct = Succinct; + composer.Parameters[BindingConstants.ParamChangeToken] = + (changeToken == null || Session.GetValue(SessionParameter.OmitChangeTokens, false) ? null : changeToken); + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + + SetChangeToken(ref changeToken, newObj); + } + } + + internal class VersioningService : AbstractBrowserBindingService, IVersioningService + { + public VersioningService(BindingSession session) + { + Session = session; + } + + public void CheckOut(string repositoryId, ref string objectId, IExtensionsData extension, out bool? contentCopied) + { + // we need an object id + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCheckOut); + composer.Succinct = Succinct; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + + contentCopied = null; + } + + public void CancelCheckOut(string repositoryId, string objectId, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCancelCheckOut); + + // send + PostAndConsume(url, composer.CreateHttpContent()); + } + + public void CheckIn(string repositoryId, ref string objectId, bool? major, IProperties properties, + IContentStream contentStream, string checkinComment, IList<string> policies, IAcl addAces, IAcl removeAces, + IExtensionsData extension) + { + // we need an object id + if (objectId == null || objectId.Length == 0) + { + throw new CmisInvalidArgumentException("Object ID must be set!"); + } + + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionCheckIn); + composer.Stream = contentStream; + composer.Parameters[BindingConstants.ParamMajor] = major; + composer.Properties = properties; + composer.Succinct = Succinct; + composer.DateTimeFormat = DateTimeFormat; + composer.Parameters[BindingConstants.ParamCheckinComment] = checkinComment; + composer.Policies = policies; + composer.AddAces = addAces; + composer.RemoveAces = removeAces; + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + IObjectData newObj = JsonConverter.ConvertObject(json, typeCache); + + objectId = (newObj == null ? null : newObj.Id); + } + + public IObjectData GetObjectOfLatestVersion(string repositoryId, string objectId, string versionSeriesId, bool major, + string filter, bool? includeAllowableActions, IncludeRelationships? includeRelationships, + string renditionFilter, bool? includePolicyIds, bool? includeAcl, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorObject); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamRelationships, includeRelationships); + url.AddParameter(BindingConstants.ParamRenditionfilter, renditionFilter); + url.AddParameter(BindingConstants.ParamPolicyIds, includePolicyIds); + url.AddParameter(BindingConstants.ParamAcl, includeAcl); + url.AddParameter(BindingConstants.ParamReturnVersion, (!major ? ReturnVersion.Latest : ReturnVersion.LatestMajor)); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObject(json, typeCache); + } + + public IProperties GetPropertiesOfLatestVersion(string repositoryId, string objectId, string versionSeriesId, bool major, + string filter, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorProperties); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamReturnVersion, (!major ? ReturnVersion.Latest : ReturnVersion.LatestMajor)); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + if (Succinct) + { + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + return JsonConverter.ConvertSuccinctProperties(json, null, typeCache); + } + else + { + return JsonConverter.ConvertProperties(json, null); + } + } + + public IList<IObjectData> GetAllVersions(string repositoryId, string objectId, string versionSeriesId, string filter, + bool? includeAllowableActions, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorVersions); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + + JsonArray json = ParseArray(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObjects(json, typeCache); + } + } + + internal class DiscoveryService : AbstractBrowserBindingService, IDiscoveryService + { + public DiscoveryService(BindingSession session) + { + Session = session; + } + + public IObjectList Query(string repositoryId, string statement, bool? searchAllVersions, + bool? includeAllowableActions, IncludeRelationships? includeRelationships, string renditionFilter, + BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionQuery); + composer.Parameters[BindingConstants.ParamStatement] = statement; + composer.Parameters[BindingConstants.ParamSearchAllVersions] = searchAllVersions; + composer.Parameters[BindingConstants.ParamAllowableActions] = includeAllowableActions; + composer.Parameters[BindingConstants.ParamRelationships] = includeRelationships; + composer.Parameters[BindingConstants.ParamRenditionfilter] = renditionFilter; + composer.Parameters[BindingConstants.ParamMaxItems] = maxItems; + composer.Parameters[BindingConstants.ParamSkipCount] = skipCount; + composer.DateTimeFormat = DateTimeFormat; + // Important: No succinct flag here!!! + + // send and parse + IResponse resp = Post(url, composer.CreateHttpContent()); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + JsonObject json = ParseObject(resp.Stream, resp.Charset); + return JsonConverter.ConvertObjectList(json, typeCache, true); + } + + public IObjectList GetContentChanges(string repositoryId, ref string changeLogToken, bool? includeProperties, + string filter, bool? includePolicyIds, bool? includeAcl, BigInteger? maxItems, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetRepositoryUrl(repositoryId, BindingConstants.SelectorContentChanges); + url.AddParameter(BindingConstants.ParamChangeLogToken, changeLogToken); + url.AddParameter(BindingConstants.ParamProperties, includeProperties); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamPolicyIds, includePolicyIds); + url.AddParameter(BindingConstants.ParamAcl, includeAcl); + url.AddParameter(BindingConstants.ParamMaxItems, maxItems); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + if (changeLogToken != null && json != null) + { + object token = json[BrowserConstants.JsonObjectListChangeLogToken]; + if (token is string) + { + changeLogToken = (string)token; + } + } + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObjectList(json, typeCache, false); + } + } + + internal class RelationshipService : AbstractBrowserBindingService, IRelationshipService + { + public RelationshipService(BindingSession session) + { + Session = session; + } + + public IObjectList GetObjectRelationships(string repositoryId, string objectId, bool? includeSubRelationshipTypes, + RelationshipDirection? relationshipDirection, string typeId, string filter, bool? includeAllowableActions, + BigInteger? maxItems, BigInteger? skipCount, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId, BindingConstants.SelectorRelationships); + url.AddParameter(BindingConstants.ParamSubRelationshipTypes, includeSubRelationshipTypes); + url.AddParameter(BindingConstants.ParamRelationshipDirection, relationshipDirection); + url.AddParameter(BindingConstants.ParamTypeId, typeId); + url.AddParameter(BindingConstants.Paramfilter, filter); + url.AddParameter(BindingConstants.ParamAllowableActions, includeAllowableActions); + url.AddParameter(BindingConstants.ParamMaxItems, maxItems); + url.AddParameter(BindingConstants.ParamSkipCount, skipCount); + url.AddParameter(BindingConstants.ParamSuccinct, SuccinctParameter); + url.AddParameter(BindingConstants.ParamDateTimeFormat, DateTimeFormatParameter); + + // read and parse + IResponse resp = Read(url); + JsonObject json = ParseObject(resp.Stream, resp.Charset); + + ITypeCache typeCache = new ClientTypeCache(repositoryId, this); + + return JsonConverter.ConvertObjectList(json, typeCache, false); + } + } + + internal class MultiFilingService : AbstractBrowserBindingService, IMultiFilingService + { + public MultiFilingService(BindingSession session) + { + Session = session; + } + + public void AddObjectToFolder(string repositoryId, string objectId, string folderId, bool? allVersions, IExtensionsData extension) + { + // build URL + UrlBuilder url = GetObjectUrl(repositoryId, objectId); + + // prepare form data + FormDataComposer composer = new FormDataComposer(BindingConstants.CmisActionRemoveObjectToFolder); + composer.Parameters[BindingConstants.ParamFolderId] = folderId; + composer.Parameters[BindingConstants.ParamAllVersions] = allVersions; + + // send + PostAndConsume(url, composer.CreateHttpContent()); + } + + public void RemoveObjectFromFolder(string repositoryId, string objectId, string folderId, IExtensionsData extension) + { + // build URL
[... 104 lines stripped ...]
