/*
* 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.Threading;
using DotCMIS.Binding.Services;
using DotCMIS.Data;
using DotCMIS.Data.Extensions;
using DotCMIS.Exceptions;
namespace DotCMIS.Binding.Impl
{
///
/// Binding layer implementation.
///
internal class CmisBinding : ICmisBinding
{
private BindingSession session;
private BindingRepositoryService repositoryServiceWrapper;
public CmisBinding(IDictionary sessionParameters)
: this(sessionParameters, null)
{
}
public CmisBinding(IDictionary sessionParameters, AbstractAuthenticationProvider authenticationProvider)
{
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
if (authenticationProvider == null)
{
string authenticationProviderClass;
if (sessionParameters.TryGetValue(SessionParameter.AuthenticationProviderClass, out authenticationProviderClass))
{
try
{
Type authProvType = Type.GetType(authenticationProviderClass);
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);
}
}
}
else
{
authenticationProvider.Session = session;
session.PutValue(BindingSession.AuthenticationProvider, authenticationProvider);
}
// initialize the SPI
GetSpi();
// set up caches
ClearAllCaches();
// set up repository service
repositoryServiceWrapper = new BindingRepositoryService(session);
}
public string BindingType
{
get
{
CheckSession();
string bindingType = session.GetValue(SessionParameter.BindingType) as string;
if (bindingType == null)
{
bindingType = DotCMIS.BindingType.Custom;
}
return bindingType;
}
}
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 IAuthenticationProvider GetAuthenticationProvider()
{
return session.GetAuthenticationProvider();
}
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();
}
}
///
/// Session object implementation of the binding layer.
///
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 data;
private object sessionLock = new object();
public BindingSession()
{
data = new Dictionary();
}
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)
{
throw;
}
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 IAuthenticationProvider GetAuthenticationProvider()
{
return GetValue(AuthenticationProvider) as IAuthenticationProvider;
}
public void Lock()
{
Monitor.Enter(sessionLock);
}
public void Unlock()
{
Monitor.Exit(sessionLock);
}
public override string ToString()
{
return data.ToString();
}
}
///
/// Repository service proxy that caches repository infos and type defintions.
///
internal class BindingRepositoryService : IRepositoryService
{
private BindingSession session;
public BindingRepositoryService(BindingSession session)
{
this.session = session;
}
public IList GetRepositoryInfos(IExtensionsData extension)
{
IList 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 (IRepositoryInfo 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) && (result.List != null))
{
TypeDefinitionCache cache = session.GetTypeDefinitionCache();
foreach (ITypeDefinition tdd in result.List)
{
cache.Put(repositoryId, tdd);
}
}
return result;
}
public IList GetTypeDescendants(string repositoryId, string typeId, long? depth,
bool? includePropertyDefinitions, IExtensionsData extension)
{
IList 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 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;
}
}
///
/// SPI interface.
///
public interface ICmisSpi : IDisposable
{
void initialize(IBindingSession 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);
}
}