You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2011/01/20 12:38:50 UTC

svn commit: r1061233 [9/15] - in /incubator/chemistry/dotcmis: branches/ tags/ trunk/ trunk/DotCMIS/ trunk/DotCMIS/Properties/ trunk/DotCMIS/Service References/ trunk/DotCMIS/Service References/CMISWebServicesReference/ trunk/DotCMIS/binding/ trunk/Dot...

Added: incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-caches.cs
URL: http://svn.apache.org/viewvc/incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-caches.cs?rev=1061233&view=auto
==============================================================================
--- incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-caches.cs (added)
+++ incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-caches.cs Thu Jan 20 11:38:48 2011
@@ -0,0 +1,662 @@
+/*
+ * 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.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using DotCMIS.Binding.Impl;
+using DotCMIS.Data;
+
+namespace DotCMIS.Binding
+{
+    // --- base cache implementation ---
+
+    internal interface ICache
+    {
+        void Initialize(string[] cacheLevelConfig);
+
+        void Put(string[] keys, object value);
+
+        object Get(string[] keys);
+
+        void Remove(string[] keys);
+
+        int Check(string[] keys);
+
+        void Lock();
+
+        void Unlock();
+    }
+
+    internal interface ICacheLevel
+    {
+        void Initialize(IDictionary<string, string> cacheLevelConfig);
+
+        object this[string key] { get; set; }
+
+        void Remove(string key);
+    }
+
+    internal class Cache : ICache
+    {
+        private IList<Type> cacheLevels;
+        private IList<IDictionary<string, string>> cacheLevelParameters;
+        private ICacheLevel root;
+        private string name;
+        private object cacheLock = new object();
+ 
+        public Cache()
+            : this("Cache")
+        {
+        }
+
+        public Cache(string name)
+        {
+            this.name = name;
+        }
+
+        public void Initialize(string[] cacheLevelConfig)
+        {
+            if (cacheLevels != null)
+            {
+                throw new ApplicationException("Cache already initialize!");
+            }
+
+            if ((cacheLevelConfig == null) || (cacheLevelConfig.Length == 0))
+            {
+                throw new ArgumentException("Cache config must not be empty!");
+            }
+
+            Lock();
+            try
+            {
+                cacheLevels = new List<Type>();
+                cacheLevelParameters = new List<IDictionary<string, string>>();
+
+                // build level lists
+                foreach (string config in cacheLevelConfig)
+                {
+                    int x = config.IndexOf(' ');
+                    if (x == -1)
+                    {
+                        AddLevel(config, null);
+                    }
+                    else
+                    {
+                        AddLevel(config.Substring(0, x), config.Substring(x + 1));
+                    }
+                }
+
+                root = CreateCacheLevel(0);
+            }
+            finally
+            {
+                Unlock();
+            }
+        }
+
+        public void Put(string[] keys, object value)
+        {
+            if (keys == null) { return; }
+
+            if (keys.Length != cacheLevels.Count)
+            {
+                throw new ArgumentException("Wrong number of keys!");
+            }
+
+            Lock();
+            try
+            {
+                ICacheLevel cacheLevel = root;
+
+                // follow the branch
+                for (int i = 0; i < keys.Length - 1; i++)
+                {
+                    object level = cacheLevel[keys[i]];
+
+                    // does the branch exist?
+                    if (level == null)
+                    {
+                        level = CreateCacheLevel(i + 1);
+                        cacheLevel[keys[i]] = level;
+                    }
+
+                    // next level
+                    cacheLevel = (ICacheLevel)level;
+                }
+
+                cacheLevel[keys[keys.Length - 1]] = value;
+
+                Trace.WriteLine(name + ": put [" + GetFormattedKeys(keys) + "] = " + value);
+            }
+            finally
+            {
+                Unlock();
+            }
+        }
+
+        public object Get(string[] keys)
+        {
+            if (keys == null) { return null; }
+
+            if (keys.Length != cacheLevels.Count)
+            {
+                throw new ArgumentException("Wrong number of keys!");
+            }
+
+            object result = null;
+
+            Lock();
+            try
+            {
+                ICacheLevel cacheLevel = root;
+
+                // follow the branch
+                for (int i = 0; i < keys.Length - 1; i++)
+                {
+                    object level = cacheLevel[keys[i]];
+
+                    // does the branch exist?
+                    if (level == null) { return null; }
+
+                    // next level
+                    cacheLevel = (ICacheLevel)level;
+                }
+
+                // get the value
+                result = cacheLevel[keys[keys.Length - 1]];
+            }
+            finally
+            {
+                Unlock();
+            }
+
+            return result;
+        }
+
+        public void Remove(string[] keys)
+        {
+            if (keys == null) { return; }
+
+            Lock();
+            try
+            {
+                ICacheLevel cacheLevel = root;
+
+                // follow the branch
+                for (int i = 0; i < keys.Length - 1; i++)
+                {
+                    object level = cacheLevel[keys[i]];
+
+                    // does the branch exist?
+                    if (level == null) { return; }
+
+                    // next level
+                    cacheLevel = (ICacheLevel)level;
+                }
+
+                cacheLevel.Remove(keys[keys.Length - 1]);
+
+                Trace.WriteLine(name + ": removed [" + GetFormattedKeys(keys) + "]");
+            }
+            finally
+            {
+                Unlock();
+            }
+        }
+
+        public int Check(string[] keys)
+        {
+            if (keys == null) { return -1; }
+
+            Lock();
+            try
+            {
+                ICacheLevel cacheLevel = root;
+
+                // follow the branch
+                for (int i = 0; i < keys.Length - 1; i++)
+                {
+                    object level = cacheLevel[keys[i]];
+
+                    // does the branch exist?
+                    if (level == null) { return i; }
+
+                    // next level
+                    cacheLevel = (ICacheLevel)level;
+                }
+
+                return keys.Length;
+            }
+            finally
+            {
+                Unlock();
+            }
+        }
+
+        public void Lock()
+        {
+            Monitor.Enter(cacheLock);
+        }
+
+        public void Unlock()
+        {
+            Monitor.Exit(cacheLock);
+        }
+
+        // --- internal ---
+
+        private void AddLevel(string typeName, string parameters)
+        {
+            Type levelType;
+
+            try
+            {
+                levelType = Type.GetType(typeName);
+            }
+            catch (Exception e)
+            {
+                throw new ArgumentException("Class '" + typeName + "' not found!", e);
+            }
+
+            if (!typeof(ICacheLevel).IsAssignableFrom(levelType))
+            {
+                throw new ArgumentException("Class '" + typeName + "' does not implement the ICacheLevel interface!");
+            }
+
+            cacheLevels.Add(levelType);
+
+            // process parameters
+            if (parameters == null)
+            {
+                cacheLevelParameters.Add(null);
+            }
+            else
+            {
+                Dictionary<string, string> parameterDict = new Dictionary<string, string>();
+                cacheLevelParameters.Add(parameterDict);
+
+                foreach (string pair in parameters.Split(','))
+                {
+                    string[] keyValue = pair.Split('=');
+                    if (keyValue.Length == 1)
+                    {
+                        parameterDict[keyValue[0]] = "";
+                    }
+                    else
+                    {
+                        parameterDict[keyValue[0]] = keyValue[1];
+                    }
+                }
+            }
+        }
+
+        private ICacheLevel CreateCacheLevel(int level)
+        {
+            if ((level < 0) || (level >= cacheLevels.Count))
+            {
+                throw new ArgumentException("Cache level doesn't fit the configuration!");
+            }
+
+            // get the class and create an instance
+            Type levelType = cacheLevels[level];
+            ICacheLevel cacheLevel = null;
+            try
+            {
+                cacheLevel = (ICacheLevel)Activator.CreateInstance(levelType);
+            }
+            catch (Exception e)
+            {
+                throw new ArgumentException("Cache level problem?!", e);
+            }
+
+            // initialize it
+            cacheLevel.Initialize(cacheLevelParameters[level]);
+
+            return cacheLevel;
+        }
+
+        private string GetFormattedKeys(string[] keys)
+        {
+            StringBuilder sb = new StringBuilder();
+            foreach (string k in keys)
+            {
+                if (sb.Length > 0)
+                {
+                    sb.Append(", ");
+                }
+                sb.Append(k);
+            }
+
+            return sb.ToString();
+        }
+    }
+
+    internal abstract class AbstractDictionaryCacheLevel : ICacheLevel
+    {
+        private static string NullKey = "";
+
+        private IDictionary<string, object> dict;
+        private bool fallbackEnabled = false;
+        private string fallbackKey = null;
+        private bool singleValueEnabled = false;
+
+        public abstract void Initialize(IDictionary<string, string> cacheLevelConfig);
+
+        public virtual object this[string key]
+        {
+            get
+            {
+                object value = null;
+                if (dict.TryGetValue(key == null ? NullKey : key, out value))
+                {
+                    return value;
+                }
+
+                if (fallbackEnabled && dict.TryGetValue(fallbackKey, out value))
+                {
+                    return value;
+                }
+
+                if (singleValueEnabled && dict.Count == 1)
+                {
+                    value = dict.Values.First();
+                }
+
+                return value;
+            }
+            set
+            {
+                if (value != null)
+                {
+                    dict[key == null ? NullKey : key] = value;
+                }
+            }
+        }
+
+        public virtual void Remove(string key)
+        {
+            dict.Remove(key);
+        }
+
+        public void SetDictionary(IDictionary<string, object> dict)
+        {
+            this.dict = dict;
+        }
+
+        protected void EnableKeyFallback(string key)
+        {
+            fallbackKey = key;
+            fallbackEnabled = true;
+        }
+
+        protected void DisableKeyFallback()
+        {
+            fallbackEnabled = false;
+        }
+
+        protected void EnableSingeValueFallback()
+        {
+            singleValueEnabled = true;
+        }
+
+        protected void DisableSingeValueFallback()
+        {
+            singleValueEnabled = false;
+        }
+
+        protected int GetIntParameter(IDictionary<string, string> parameters, string name, int defValue)
+        {
+            if (parameters == null)
+            {
+                return defValue;
+            }
+
+            string value;
+            if (!parameters.TryGetValue(name, out value))
+            {
+                return defValue;
+            }
+
+            try
+            {
+                return Int32.Parse(value);
+            }
+            catch (Exception)
+            {
+                return defValue;
+            }
+        }
+
+        protected bool GetBooleanParameter(IDictionary<string, string> parameters, string name, bool defValue)
+        {
+            if (parameters == null)
+            {
+                return defValue;
+            }
+
+            string value;
+            if (!parameters.TryGetValue(name, out value))
+            {
+                return defValue;
+            }
+
+            try
+            {
+                return Boolean.Parse(value);
+            }
+            catch (Exception)
+            {
+                return defValue;
+            }
+        }
+    }
+
+    internal class DictionaryCacheLevel : AbstractDictionaryCacheLevel
+    {
+        public const string Capacity = "capacity";
+        public const string SingleValue = "singleValue";
+
+        public override void Initialize(IDictionary<string, string> parameters)
+        {
+            int initialCapacity = GetIntParameter(parameters, Capacity, 32);
+            bool singleValue = GetBooleanParameter(parameters, SingleValue, false);
+
+            SetDictionary(new Dictionary<string, object>(initialCapacity));
+            if (singleValue)
+            {
+                EnableSingeValueFallback();
+            }
+        }
+    }
+
+    internal class LruCacheLevel : AbstractDictionaryCacheLevel
+    {
+        public const string MaxEntries = "maxEntries";
+
+        private LinkedList<string> keyList;
+        private int maxEntries;
+
+        public override void Initialize(IDictionary<string, string> parameters)
+        {
+            maxEntries = GetIntParameter(parameters, MaxEntries, 100);
+            keyList = new LinkedList<string>();
+            SetDictionary(new Dictionary<string, object>(maxEntries + 1));
+        }
+
+        public override object this[string key]
+        {
+            get
+            {
+                object value = base[key];
+                if (value != null)
+                {
+                    LinkedListNode<string> node = keyList.Find(key);
+                    if (node == null)
+                    {
+                        throw new ApplicationException("Cache error!");
+                    }
+                    else
+                    {
+                        keyList.Remove(node);
+                        keyList.AddFirst(node);
+                    }
+                }
+
+                return value;
+            }
+            set
+            {
+                if (value == null)
+                {
+                    return;
+                }
+
+                LinkedListNode<string> node = keyList.Find(key);
+                if (node == null)
+                {
+                    keyList.AddFirst(key);
+                    while (keyList.Count > maxEntries)
+                    {
+                        LinkedListNode<string> lastNode = keyList.Last;
+                        base.Remove(lastNode.Value);
+                        keyList.RemoveLast();
+                    }
+                }
+                else
+                {
+                    keyList.Remove(node);
+                    keyList.AddFirst(node);
+                }
+
+                base[key] = value;
+            }
+        }
+
+        public override void Remove(string key)
+        {
+            keyList.Remove(key);
+            base.Remove(key);
+        }
+    }
+
+    // ---- Caches ----
+
+    /// <summary>
+    /// Repository Info cache.
+    /// </summary>
+    internal class RepositoryInfoCache
+    {
+        private const int CacheSizeRepositories = 10;
+
+        private ICache cache;
+
+        public RepositoryInfoCache(BindingSession session)
+        {
+            int repCount = session.GetValue(SessionParameter.CacheSizeRepositories, CacheSizeRepositories);
+            if (repCount < 1)
+            {
+                repCount = CacheSizeRepositories;
+            }
+
+            cache = new Cache("Repository Info Cache");
+            cache.Initialize(new string[] { 
+                typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount });
+        }
+
+        public void Put(IRepositoryInfo repositoryInfo)
+        {
+            if ((repositoryInfo == null) || (repositoryInfo.Id == null))
+            {
+                return;
+            }
+
+            cache.Put(new string[] { repositoryInfo.Id }, repositoryInfo);
+        }
+
+        public IRepositoryInfo Get(string repositoryId)
+        {
+            return (IRepositoryInfo)cache.Get(new string[] { repositoryId });
+        }
+
+        public void Remove(string repositoryId)
+        {
+            cache.Remove(new string[] { repositoryId });
+        }
+    }
+
+    /// <summary>
+    /// Type Definition cache.
+    /// </summary>
+    internal class TypeDefinitionCache
+    {
+        private const int CacheSizeRepositories = 10;
+        private const int CacheSizeTypes = 100;
+
+        private ICache cache;
+
+        public TypeDefinitionCache(BindingSession session)
+        {
+            int repCount = session.GetValue(SessionParameter.CacheSizeRepositories, CacheSizeRepositories);
+            if (repCount < 1)
+            {
+                repCount = CacheSizeRepositories;
+            }
+
+            int typeCount = session.GetValue(SessionParameter.CacheSizeTypes, CacheSizeTypes);
+            if (typeCount < 1)
+            {
+                typeCount = CacheSizeTypes;
+            }
+
+            cache = new Cache("Type Definition Cache");
+            cache.Initialize(new string[] {
+                typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount, // repository
+                typeof(LruCacheLevel).FullName + " " + LruCacheLevel.MaxEntries + "=" + typeCount // type
+        });
+        }
+
+        public void Put(string repositoryId, ITypeDefinition typeDefinition)
+        {
+            if ((typeDefinition == null) || (typeDefinition.Id == null))
+            {
+                return;
+            }
+
+            cache.Put(new string[] { repositoryId, typeDefinition.Id }, typeDefinition);
+        }
+
+        public ITypeDefinition Get(string repositoryId, string typeId)
+        {
+            return (ITypeDefinition)cache.Get(new string[] { repositoryId, typeId });
+        }
+
+        public void Remove(string repositoryId, string typeId)
+        {
+            cache.Remove(new string[] { repositoryId, typeId });
+        }
+
+        public void Remove(string repositoryId)
+        {
+            cache.Remove(new string[] { repositoryId });
+        }
+    }
+}

Added: incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-impl.cs
URL: http://svn.apache.org/viewvc/incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-impl.cs?rev=1061233&view=auto
==============================================================================
--- incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-impl.cs (added)
+++ incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-impl.cs Thu Jan 20 11:38:48 2011
@@ -0,0 +1,604 @@
+/*
+ * 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 BindingsObjectFactory objectFactory;
+        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 object factory
+            objectFactory = new BindingsObjectFactory();
+
+            // 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 IBindingsObjectFactory GetObjectFactory()
+        {
+            return objectFactory;
+        }
+
+        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 Close()
+        {
+            CheckSession();
+
+            session.Lock();
+            try
+            {
+                GetSpi().Close();
+            }
+            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>
+    /// Object factory implementation.
+    /// </summary>
+    internal class BindingsObjectFactory : IBindingsObjectFactory
+    {
+    }
+
+    /// <summary>
+    /// SPI interface.
+    /// </summary>
+    internal interface ICmisSpi
+    {
+        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);
+
+        void Close();
+    }
+}

Added: incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-intf.cs
URL: http://svn.apache.org/viewvc/incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-intf.cs?rev=1061233&view=auto
==============================================================================
--- incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-intf.cs (added)
+++ incubator/chemistry/dotcmis/trunk/DotCMIS/binding/binding-intf.cs Thu Jan 20 11:38:48 2011
@@ -0,0 +1,296 @@
+/*
+ * 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.Services;
+using DotCMIS.Binding.Impl;
+using DotCMIS.CMISWebServicesReference;
+using System.Net;
+
+namespace DotCMIS.Binding
+{
+    public interface ICmisBinding
+    {
+        IRepositoryService GetRepositoryService();
+
+        INavigationService GetNavigationService();
+
+        IObjectService GetObjectService();
+
+        IVersioningService GetVersioningService();
+
+        IRelationshipService GetRelationshipService();
+
+        IDiscoveryService GetDiscoveryService();
+
+        IMultiFilingService GetMultiFilingService();
+
+        IAclService GetAclService();
+
+        IPolicyService GetPolicyService();
+
+        IBindingsObjectFactory GetObjectFactory();
+
+        void ClearAllCaches();
+
+        void ClearRepositoryCache(string repositoryId);
+
+        void Close();
+    }
+
+    public interface IBindingSession
+    {
+        object GetValue(string key);
+
+        object GetValue(string key, object defValue);
+
+        int GetValue(string key, int defValue);
+    }
+
+    public abstract class AbstractAuthenticationProvider
+    {
+        public IBindingSession Session { get; set; }
+
+        public abstract void Authenticate(object connection);
+
+        public string GetUser()
+        {
+            return Session.GetValue(SessionParameter.User) as string;
+        }
+
+        public string GetPassword()
+        {
+            return Session.GetValue(SessionParameter.Password) as string;
+        }
+    }
+
+    public class StandardAuthenticationProvider : AbstractAuthenticationProvider
+    {
+        public override void Authenticate(object connection)
+        {
+            string user = GetUser();
+            string password = GetPassword();
+            if (user == null || password == null)
+            {
+                return;
+            }
+
+            if (connection is RepositoryServicePortClient)
+            {
+                ((RepositoryServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((RepositoryServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is NavigationServicePortClient)
+            {
+                ((NavigationServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((NavigationServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is ObjectServicePortClient)
+            {
+                ((ObjectServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((ObjectServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is VersioningServicePortClient)
+            {
+                ((VersioningServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((VersioningServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is DiscoveryServicePortClient)
+            {
+                ((DiscoveryServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((DiscoveryServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is RelationshipServicePortClient)
+            {
+                ((RelationshipServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((RelationshipServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is MultiFilingServicePortClient)
+            {
+                ((MultiFilingServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((MultiFilingServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is PolicyServicePortClient)
+            {
+                ((PolicyServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((PolicyServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is ACLServicePortClient)
+            {
+                ((ACLServicePortClient)connection).ClientCredentials.UserName.UserName = user;
+                ((ACLServicePortClient)connection).ClientCredentials.UserName.Password = password;
+            }
+            else if (connection is WebRequest)
+            {
+                ((WebRequest)connection).Credentials = new NetworkCredential(user, password);
+            }
+        }
+    }
+
+
+    public interface IBindingsObjectFactory
+    {
+    }
+
+    public class CmisBindingFactory
+    {
+        // Default CMIS AtomPub binding SPI implementation
+        public const string BindingSpiAtomPub = "DotCMIS.Binding.AtomPub.CmisAtomPubSpi";
+        // Default CMIS Web Services binding SPI implementation
+        public const string BindingSpiWebServices = "DotCMIS.Binding.WebServices.CmisWebServicesSpi";
+
+        public const string StandardAuthenticationProviderClass = "DotCMIS.Binding.StandardAuthenticationProvider";
+
+        private IDictionary<string, string> defaults;
+
+        private CmisBindingFactory()
+        {
+            defaults = CreateNewDefaultParameters();
+        }
+
+        public static CmisBindingFactory NewInstance()
+        {
+            return new CmisBindingFactory();
+        }
+
+        public IDictionary<string, string> GetDefaultSessionParameters()
+        {
+            return defaults;
+        }
+
+        public void SetDefaultSessionParameters(IDictionary<string, string> sessionParameters)
+        {
+            if (sessionParameters == null)
+            {
+                defaults = CreateNewDefaultParameters();
+            }
+            else
+            {
+                defaults = sessionParameters;
+            }
+        }
+
+        public ICmisBinding CreateCmisBinding(IDictionary<string, string> sessionParameters)
+        {
+            CheckSessionParameters(sessionParameters, true);
+            AddDefaultParameters(sessionParameters);
+
+            return new CmisBinding(sessionParameters);
+        }
+
+        public ICmisBinding CreateCmisAtomPubBinding(IDictionary<string, string> sessionParameters)
+        {
+            CheckSessionParameters(sessionParameters, false);
+            sessionParameters[SessionParameter.BindingSpiClass] = BindingSpiAtomPub;
+            if (!sessionParameters.ContainsKey(SessionParameter.AuthenticationProviderClass))
+            {
+                sessionParameters[SessionParameter.AuthenticationProviderClass] = StandardAuthenticationProviderClass;
+            }
+
+            AddDefaultParameters(sessionParameters);
+
+            Check(sessionParameters, SessionParameter.AtomPubUrl);
+
+            return new CmisBinding(sessionParameters);
+        }
+
+        public ICmisBinding CreateCmisWebServicesBinding(IDictionary<string, string> sessionParameters)
+        {
+            CheckSessionParameters(sessionParameters, false);
+            sessionParameters[SessionParameter.BindingSpiClass] = BindingSpiWebServices;
+            if (!sessionParameters.ContainsKey(SessionParameter.AuthenticationProviderClass))
+            {
+                sessionParameters[SessionParameter.AuthenticationProviderClass] = StandardAuthenticationProviderClass;
+            }
+
+            AddDefaultParameters(sessionParameters);
+
+            Check(sessionParameters, SessionParameter.WebServicesAclService);
+            Check(sessionParameters, SessionParameter.WebServicesDiscoveryService);
+            Check(sessionParameters, SessionParameter.WebServicesMultifilingService);
+            Check(sessionParameters, SessionParameter.WebServicesNavigationService);
+            Check(sessionParameters, SessionParameter.WebServicesObjectService);
+            Check(sessionParameters, SessionParameter.WebServicesPolicyService);
+            Check(sessionParameters, SessionParameter.WebServicesRelationshipService);
+            Check(sessionParameters, SessionParameter.WebServicesRepositoryService);
+            Check(sessionParameters, SessionParameter.WebServicesVersioningService);
+
+            return new CmisBinding(sessionParameters);
+        }
+
+        // ---- internals ----
+
+        private void CheckSessionParameters(IDictionary<string, string> sessionParameters, bool mustContainSpi)
+        {
+            // don't accept null
+            if (sessionParameters == null)
+            {
+                throw new ArgumentNullException("sessionParameters");
+            }
+
+            // check binding entry
+            if (mustContainSpi)
+            {
+                string spiClass;
+
+                if (sessionParameters.TryGetValue(SessionParameter.BindingSpiClass, out spiClass))
+                {
+                    throw new ArgumentException("SPI class entry (" + SessionParameter.BindingSpiClass + ") is missing!");
+                }
+
+                if ((spiClass == null) || (spiClass.Trim().Length == 0))
+                {
+                    throw new ArgumentException("SPI class entry (" + SessionParameter.BindingSpiClass + ") is invalid!");
+                }
+            }
+        }
+
+        private void Check(IDictionary<string, string> sessionParameters, String parameter)
+        {
+            if (!sessionParameters.ContainsKey(parameter))
+            {
+                throw new ArgumentException("Parameter '" + parameter + "' is missing!");
+            }
+        }
+
+        private void AddDefaultParameters(IDictionary<string, string> sessionParameters)
+        {
+            foreach (string key in defaults.Keys)
+            {
+                if (!sessionParameters.ContainsKey(key))
+                {
+                    sessionParameters[key] = defaults[key];
+                }
+            }
+        }
+
+        private IDictionary<string, string> CreateNewDefaultParameters()
+        {
+            IDictionary<string, string> result = new Dictionary<string, string>();
+
+            result[SessionParameter.CacheSizeRepositories] = "10";
+            result[SessionParameter.CacheSizeTypes] = "100";
+            result[SessionParameter.CacheSizeLinks] = "400";
+
+            return result;
+        }
+    }
+}