blob: ec3fa86da1ca7c20181288b70fee584f1d744856 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotCMIS.Binding;
using DotCMIS.Binding.Services;
using System.Threading;
using DotCMIS.Exceptions;
using DotCMIS.Data;
using DotCMIS.Data.Extensions;
namespace DotCMIS.Binding.Impl
{
/// <summary>
/// Binding layer implementation.
/// </summary>
internal class CmisBinding : ICmisBinding
{
private BindingSession session;
private BindingRepositoryService repositoryServiceWrapper;
public CmisBinding(IDictionary<string, string> sessionParameters)
{
if (sessionParameters == null)
{
throw new ArgumentNullException("sessionParameters");
}
if (!sessionParameters.ContainsKey(SessionParameter.BindingSpiClass))
{
throw new ArgumentException("Session parameters do not contain a SPI class name!");
}
// initialize session
session = new BindingSession();
foreach (string key in sessionParameters.Keys)
{
session.PutValue(key, sessionParameters[key]);
}
// set up authentication provider
string authenticationProviderClass;
if (sessionParameters.TryGetValue(SessionParameter.AuthenticationProviderClass, out authenticationProviderClass))
{
try
{
Type authProvType = Type.GetType(authenticationProviderClass);
AbstractAuthenticationProvider authenticationProvider = (AbstractAuthenticationProvider)Activator.CreateInstance(authProvType);
authenticationProvider.Session = session;
session.PutValue(BindingSession.AuthenticationProvider, authenticationProvider);
}
catch (Exception e)
{
throw new CmisRuntimeException("Could not load authentictaion provider: " + e.Message, e);
}
}
// initialize the SPI
GetSpi();
// set up caches
ClearAllCaches();
// set up repository service
repositoryServiceWrapper = new BindingRepositoryService(session);
}
public IRepositoryService GetRepositoryService()
{
CheckSession();
return repositoryServiceWrapper;
}
public INavigationService GetNavigationService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetNavigationService();
}
public IObjectService GetObjectService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetObjectService();
}
public IVersioningService GetVersioningService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetVersioningService();
}
public IRelationshipService GetRelationshipService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetRelationshipService();
}
public IDiscoveryService GetDiscoveryService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetDiscoveryService();
}
public IMultiFilingService GetMultiFilingService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetMultiFilingService();
}
public IAclService GetAclService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetAclService();
}
public IPolicyService GetPolicyService()
{
CheckSession();
ICmisSpi spi = GetSpi();
return spi.GetPolicyService();
}
public void ClearAllCaches()
{
CheckSession();
session.Lock();
try
{
session.PutValue(BindingSession.RepositoryInfoCache, new RepositoryInfoCache(session));
session.PutValue(BindingSession.TypeDefinitionCache, new TypeDefinitionCache(session));
ICmisSpi spi = GetSpi();
spi.ClearAllCaches();
}
finally
{
session.Unlock();
}
}
public void ClearRepositoryCache(string repositoryId)
{
CheckSession();
if (repositoryId == null)
{
return;
}
session.Lock();
try
{
RepositoryInfoCache repInfoCache = session.GetRepositoryInfoCache();
repInfoCache.Remove(repositoryId);
TypeDefinitionCache typeDefCache = session.GetTypeDefinitionCache();
typeDefCache.Remove(repositoryId);
ICmisSpi spi = GetSpi();
spi.ClearRepositoryCache(repositoryId);
}
finally
{
session.Unlock();
}
}
public void Dispose()
{
CheckSession();
session.Lock();
try
{
GetSpi().Dispose();
}
finally
{
session.Unlock();
session = null;
}
}
private void CheckSession()
{
if (session == null)
{
throw new ApplicationException("Already closed.");
}
}
private ICmisSpi GetSpi()
{
return session.GetSpi();
}
}
/// <summary>
/// Session object implementation of the binding layer.
/// </summary>
internal class BindingSession : IBindingSession
{
public const string RepositoryInfoCache = "org.apache.chemistry.dotcmis.bindings.repositoryInfoCache";
public const string TypeDefinitionCache = "org.apache.chemistry.dotcmis.bindings.typeDefintionCache";
public const string AuthenticationProvider = "org.apache.chemistry.dotcmis.bindings.authenticationProvider";
public const string SpiObject = "org.apache.chemistry.dotcmis.bindings.spi.object";
private Dictionary<string, object> data;
private object sessionLock = new object();
public BindingSession()
{
data = new Dictionary<string, object>();
}
public object GetValue(string key)
{
return GetValue(key, null);
}
public object GetValue(string key, object defValue)
{
object result = null;
Lock();
try
{
if (data.TryGetValue(key, out result))
{
return result;
}
else
{
return defValue;
}
}
finally
{
Unlock();
}
}
public int GetValue(string key, int defValue)
{
object value = GetValue(key);
try
{
if (value is string)
{
return Int32.Parse((string)value);
}
else if (value is int)
{
return (int)value;
}
}
catch (Exception)
{
}
return defValue;
}
public void PutValue(string key, object value)
{
Lock();
try
{
data[key] = value;
}
finally
{
Unlock();
}
}
public void RemoveValue(string key)
{
Lock();
try
{
data.Remove(key);
}
finally
{
Unlock();
}
}
public ICmisSpi GetSpi()
{
Lock();
try
{
ICmisSpi spi = GetValue(SpiObject) as ICmisSpi;
if (spi != null)
{
return spi;
}
// ok, we have to create it...
try
{
object spiObject;
if (data.TryGetValue(SessionParameter.BindingSpiClass, out spiObject))
{
string spiClassName = spiObject as string;
if (spiClassName != null)
{
Type spiClass = Type.GetType(spiClassName);
spi = (ICmisSpi)Activator.CreateInstance(spiClass);
spi.initialize(this);
}
else
{
throw new CmisRuntimeException("SPI class is not set!");
}
}
else
{
throw new CmisRuntimeException("SPI class is not set!");
}
}
catch (CmisBaseException ce)
{
throw ce;
}
catch (Exception e)
{
throw new CmisRuntimeException("SPI cannot be initialized: " + e.Message, e);
}
// we have a SPI object -> put it into the session
data[SpiObject] = spi;
return spi;
}
finally
{
Unlock();
}
}
public RepositoryInfoCache GetRepositoryInfoCache()
{
return GetValue(RepositoryInfoCache) as RepositoryInfoCache;
}
public TypeDefinitionCache GetTypeDefinitionCache()
{
return GetValue(TypeDefinitionCache) as TypeDefinitionCache;
}
public AbstractAuthenticationProvider GetAuthenticationProvider()
{
return GetValue(AuthenticationProvider) as AbstractAuthenticationProvider;
}
public void Lock()
{
Monitor.Enter(sessionLock);
}
public void Unlock()
{
Monitor.Exit(sessionLock);
}
public override string ToString()
{
return data.ToString();
}
}
/// <summary>
/// Repository service proxy that caches repository infos and type defintions.
/// </summary>
internal class BindingRepositoryService : IRepositoryService
{
private BindingSession session;
public BindingRepositoryService(BindingSession session)
{
this.session = session;
}
public IList<IRepositoryInfo> GetRepositoryInfos(IExtensionsData extension)
{
IList<IRepositoryInfo> result = null;
bool hasExtension = (extension != null) && (extension.Extensions != null) && (extension.Extensions.Count > 0);
// get the SPI and fetch the repository infos
ICmisSpi spi = session.GetSpi();
result = spi.GetRepositoryService().GetRepositoryInfos(extension);
// put it into the cache
if (!hasExtension && (result != null))
{
RepositoryInfoCache cache = session.GetRepositoryInfoCache();
foreach (RepositoryInfo rid in result)
{
cache.Put(rid);
}
}
return result;
}
public IRepositoryInfo GetRepositoryInfo(string repositoryId, IExtensionsData extension)
{
IRepositoryInfo result = null;
bool hasExtension = (extension != null) && (extension.Extensions != null) && (extension.Extensions.Count > 0);
RepositoryInfoCache cache = session.GetRepositoryInfoCache();
// if extension is not set, check the cache first
if (!hasExtension)
{
result = cache.Get(repositoryId);
if (result != null)
{
return result;
}
}
// it was not in the cache -> get the SPI and fetch the repository info
ICmisSpi spi = session.GetSpi();
result = spi.GetRepositoryService().GetRepositoryInfo(repositoryId, extension);
// put it into the cache
if (!hasExtension)
{
cache.Put(result);
}
return result;
}
public ITypeDefinitionList GetTypeChildren(string repositoryId, string typeId, bool? includePropertyDefinitions,
long? maxItems, long? skipCount, IExtensionsData extension)
{
ITypeDefinitionList result = null;
bool hasExtension = (extension != null) && (extension.Extensions != null) && (extension.Extensions.Count > 0);
// get the SPI and fetch the type definitions
ICmisSpi spi = session.GetSpi();
result = spi.GetRepositoryService().GetTypeChildren(repositoryId, typeId, includePropertyDefinitions, maxItems,
skipCount, extension);
// put it into the cache
if (!hasExtension && (includePropertyDefinitions ?? false) && (result != null))
{
TypeDefinitionCache cache = session.GetTypeDefinitionCache();
foreach (ITypeDefinition tdd in result.List)
{
cache.Put(repositoryId, tdd);
}
}
return result;
}
public IList<ITypeDefinitionContainer> GetTypeDescendants(string repositoryId, string typeId, long? depth,
bool? includePropertyDefinitions, IExtensionsData extension)
{
IList<ITypeDefinitionContainer> result = null;
bool hasExtension = (extension != null) && (extension.Extensions != null) && (extension.Extensions.Count > 0);
// get the SPI and fetch the type definitions
ICmisSpi spi = session.GetSpi();
result = spi.GetRepositoryService().GetTypeDescendants(repositoryId, typeId, depth, includePropertyDefinitions,
extension);
// put it into the cache
if (!hasExtension && (includePropertyDefinitions ?? false) && (result != null))
{
TypeDefinitionCache cache = session.GetTypeDefinitionCache();
AddToTypeCache(cache, repositoryId, result);
}
return result;
}
private void AddToTypeCache(TypeDefinitionCache cache, string repositoryId, IList<ITypeDefinitionContainer> containers)
{
if (containers == null)
{
return;
}
foreach (ITypeDefinitionContainer container in containers)
{
cache.Put(repositoryId, container.TypeDefinition);
AddToTypeCache(cache, repositoryId, container.Children);
}
}
public ITypeDefinition GetTypeDefinition(string repositoryId, string typeId, IExtensionsData extension)
{
ITypeDefinition result = null;
bool hasExtension = (extension != null) && (extension.Extensions != null) && (extension.Extensions.Count > 0);
TypeDefinitionCache cache = session.GetTypeDefinitionCache();
// if extension is not set, check the cache first
if (!hasExtension)
{
result = cache.Get(repositoryId, typeId);
if (result != null)
{
return result;
}
}
// it was not in the cache -> get the SPI and fetch the type definition
ICmisSpi spi = session.GetSpi();
result = spi.GetRepositoryService().GetTypeDefinition(repositoryId, typeId, extension);
// put it into the cache
if (!hasExtension && (result != null))
{
cache.Put(repositoryId, result);
}
return result;
}
}
/// <summary>
/// SPI interface.
/// </summary>
internal interface ICmisSpi : IDisposable
{
void initialize(BindingSession session);
IRepositoryService GetRepositoryService();
INavigationService GetNavigationService();
IObjectService GetObjectService();
IVersioningService GetVersioningService();
IRelationshipService GetRelationshipService();
IDiscoveryService GetDiscoveryService();
IMultiFilingService GetMultiFilingService();
IAclService GetAclService();
IPolicyService GetPolicyService();
void ClearAllCaches();
void ClearRepositoryCache(string repositoryId);
}
}