blob: 53b803c334ec1246f5a1f7afd3860b6c32bc4075 [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.Text;
using System.Web;
using DotCMIS.Binding.Impl;
namespace DotCMIS.Binding.AtomPub
{
internal class LinkCache
{
private static HashSet<string> KnownLinks = new HashSet<string>();
static LinkCache()
{
KnownLinks.Add(AtomPubConstants.RelACL);
KnownLinks.Add(AtomPubConstants.RelDown);
KnownLinks.Add(AtomPubConstants.RelUp);
KnownLinks.Add(AtomPubConstants.RelFolderTree);
KnownLinks.Add(AtomPubConstants.RelRelationships);
KnownLinks.Add(AtomPubConstants.RelSelf);
KnownLinks.Add(AtomPubConstants.RelAllowableActions);
KnownLinks.Add(AtomPubConstants.RelEditMedia);
KnownLinks.Add(AtomPubConstants.RelPolicies);
KnownLinks.Add(AtomPubConstants.RelVersionHistory);
KnownLinks.Add(AtomPubConstants.LinkRelContent);
}
private const int CacheSizeRepositories = 10;
private const int CacheSizeTypes = 100;
private const int CacheSizeLinks = 400;
private IBindingCache linkCache;
private IBindingCache typeLinkCache;
private IBindingCache collectionLinkCache;
private IBindingCache templateCache;
private IBindingCache repositoryLinkCache;
public LinkCache(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;
}
int objCount = session.GetValue(SessionParameter.CacheSizeLinks, CacheSizeLinks);
if (objCount < 1)
{
objCount = CacheSizeLinks;
}
linkCache = new Cache("Link Cache");
linkCache.Initialize(new string[] {
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount, // repository
typeof(LruCacheLevel).FullName + " " + LruCacheLevel.MaxEntries + "=" + objCount, // id
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=16", // rel
typeof(ContentTypeCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=3,"
+ DictionaryCacheLevel.SingleValue + "=true" // type
});
typeLinkCache = new Cache("Type Link Cache");
typeLinkCache.Initialize(new string[] {
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount, // repository
typeof(LruCacheLevel).FullName + " " + LruCacheLevel.MaxEntries + "=" + typeCount, // id
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=16", // rel
typeof(ContentTypeCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=3,"
+ DictionaryCacheLevel.SingleValue + "=true"// type
});
collectionLinkCache = new Cache("Collection Link Cache");
collectionLinkCache.Initialize(new string[] {
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount, // repository
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=8" // collection
});
templateCache = new Cache("URI Template Cache");
templateCache.Initialize(new string[] {
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount, // repository
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=6" // type
});
repositoryLinkCache = new Cache("Repository Link Cache");
repositoryLinkCache.Initialize(new string[] {
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=" + repCount, // repository
typeof(DictionaryCacheLevel).FullName + " " + DictionaryCacheLevel.Capacity + "=6" // rel
});
}
// ---- links ---
public void AddLink(string repositoryId, string id, string rel, string type, string link)
{
if (KnownLinks.Contains(rel))
{
linkCache.Put(new string[] { repositoryId, id, rel, type }, link);
}
}
public void RemoveLinks(string repositoryId, string id)
{
linkCache.Remove(new string[] { repositoryId, id });
}
public string GetLink(string repositoryId, string id, string rel, string type)
{
return (string)linkCache.Get(new string[] { repositoryId, id, rel, type });
}
public string GetLink(string repositoryId, string id, string rel)
{
return GetLink(repositoryId, id, rel, null);
}
public int CheckLink(string repositoryId, string id, string rel, string type)
{
return linkCache.Check(new string[] { repositoryId, id, rel, type });
}
public void LockLinks()
{
linkCache.Lock();
}
public void UnlockLinks()
{
linkCache.Unlock();
}
// ---- type links ---
public void AddTypeLink(string repositoryId, string id, string rel, string type, string link)
{
if (KnownLinks.Contains(rel))
{
typeLinkCache.Put(new string[] { repositoryId, id, rel, type }, link);
}
}
public void RemoveTypeLinks(string repositoryId, string id)
{
typeLinkCache.Remove(new string[] { repositoryId, id });
}
public string GetTypeLink(string repositoryId, string id, string rel, string type)
{
return (string)typeLinkCache.Get(new string[] { repositoryId, id, rel, type });
}
public void LockTypeLinks()
{
typeLinkCache.Lock();
}
public void UnlockTypeLinks()
{
typeLinkCache.Unlock();
}
// ---- collections ----
public void AddCollection(string repositoryId, string collection, string link)
{
collectionLinkCache.Put(new string[] { repositoryId, collection }, link);
}
public string GetCollection(string repositoryId, string collection)
{
return (string)collectionLinkCache.Get(new string[] { repositoryId, collection });
}
// ---- templates ----
public void AddTemplate(string repositoryId, string type, string link)
{
templateCache.Put(new string[] { repositoryId, type }, link);
}
public string GetTemplateLink(string repositoryId, string type, IDictionary<string, object> parameters)
{
string template = (string)templateCache.Get(new string[] { repositoryId, type });
if (template == null)
{
return null;
}
StringBuilder result = new StringBuilder();
StringBuilder param = new StringBuilder();
bool paramMode = false;
for (int i = 0; i < template.Length; i++)
{
char c = template[i];
if (paramMode)
{
if (c == '}')
{
paramMode = false;
object paramValue;
if (parameters.TryGetValue(param.ToString(), out paramValue))
{
result.Append(HttpUtility.UrlEncode(UrlBuilder.NormalizeParameter(paramValue)));
}
param = new StringBuilder();
}
else
{
param.Append(c);
}
}
else
{
if (c == '{')
{
paramMode = true;
}
else
{
result.Append(c);
}
}
}
return result.ToString();
}
// ---- repository links ----
public void AddRepositoryLink(string repositoryId, string rel, string link)
{
repositoryLinkCache.Put(new string[] { repositoryId, rel }, link);
}
public string GetRepositoryLink(string repositoryId, string rel)
{
return (string)repositoryLinkCache.Get(new string[] { repositoryId, rel });
}
// ---- clear ----
public void ClearRepository(string repositoryId)
{
linkCache.Remove(new string[] { repositoryId });
typeLinkCache.Remove(new string[] { repositoryId });
collectionLinkCache.Remove(new string[] { repositoryId });
templateCache.Remove(new string[] { repositoryId });
repositoryLinkCache.Remove(new string[] { repositoryId });
}
}
internal class ContentTypeCacheLevel : DictionaryCacheLevel
{
public ContentTypeCacheLevel()
{
EnableKeyFallback(NullKey);
}
public override object this[string key]
{
get
{
return base[Normalize(key)];
}
set
{
base[Normalize(key)] = value;
}
}
public override void Remove(string key)
{
base.Remove(Normalize(key));
}
private string Normalize(string key)
{
if (key == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
int parameterStart = 0;
// first, get the MIME type
for (int i = 0; i < key.Length; i++)
{
char c = key[i];
if (Char.IsWhiteSpace(c))
{
continue;
}
else if (c == ';')
{
parameterStart = i;
break;
}
sb.Append(Char.ToLower(c));
}
// if parameters have been found, gather them
if (parameterStart > 0)
{
SortedList<string, string> parameter = new SortedList<string, string>();
StringBuilder ksb = new StringBuilder();
StringBuilder vsb = new StringBuilder();
bool isKey = true;
for (int i = parameterStart + 1; i < key.Length; i++)
{
char c = key[i];
if (Char.IsWhiteSpace(c))
{
continue;
}
if (isKey)
{
if (c == '=')
{
// value start
isKey = false;
continue;
}
ksb.Append(Char.ToLower(c));
}
else
{
if (c == ';')
{
// next key
isKey = true;
parameter.Add(ksb.ToString(), vsb.ToString());
ksb = new StringBuilder();
vsb = new StringBuilder();
continue;
}
else if (c == '"')
{
// filter quotes
continue;
}
vsb.Append(Char.ToLower(c));
}
}
// add last parameter
if (ksb.Length > 0)
{
parameter.Add(ksb.ToString(), vsb.ToString());
}
// write parameters sorted by key
for (int i = 0; i < parameter.Count; i++)
{
sb.Append(";");
sb.Append(parameter.Keys[i]);
sb.Append("=");
sb.Append(parameter.Values[i]);
}
}
return sb.ToString();
}
}
}