/* | |
* 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. | |
*/ | |
package org.apache.chemistry.opencmis.client.bindings.spi.atompub; | |
import java.io.Serializable; | |
import java.util.HashSet; | |
import java.util.Map; | |
import java.util.Set; | |
import org.apache.chemistry.opencmis.client.bindings.cache.Cache; | |
import org.apache.chemistry.opencmis.client.bindings.cache.impl.CacheImpl; | |
import org.apache.chemistry.opencmis.client.bindings.cache.impl.ContentTypeCacheLevelImpl; | |
import org.apache.chemistry.opencmis.client.bindings.cache.impl.LruCacheLevelImpl; | |
import org.apache.chemistry.opencmis.client.bindings.cache.impl.MapCacheLevelImpl; | |
import org.apache.chemistry.opencmis.client.bindings.spi.BindingSession; | |
import org.apache.chemistry.opencmis.commons.SessionParameter; | |
import org.apache.chemistry.opencmis.commons.impl.Constants; | |
import org.apache.chemistry.opencmis.commons.impl.IOUtils; | |
import org.apache.chemistry.opencmis.commons.impl.UrlBuilder; | |
/** | |
* Link cache. | |
*/ | |
public class LinkCache implements Serializable { | |
private static final long serialVersionUID = 1L; | |
private static final Set<String> KNOWN_LINKS = new HashSet<String>(); | |
static { | |
KNOWN_LINKS.add(Constants.REL_ACL); | |
KNOWN_LINKS.add(Constants.REL_DOWN); | |
KNOWN_LINKS.add(Constants.REL_UP); | |
KNOWN_LINKS.add(Constants.REL_FOLDERTREE); | |
KNOWN_LINKS.add(Constants.REL_RELATIONSHIPS); | |
KNOWN_LINKS.add(Constants.REL_SELF); | |
KNOWN_LINKS.add(Constants.REL_ALLOWABLEACTIONS); | |
KNOWN_LINKS.add(Constants.REL_EDITMEDIA); | |
KNOWN_LINKS.add(Constants.REL_POLICIES); | |
KNOWN_LINKS.add(Constants.REL_VERSIONHISTORY); | |
KNOWN_LINKS.add(Constants.REL_WORKINGCOPY); | |
KNOWN_LINKS.add(AtomPubParser.LINK_REL_CONTENT); | |
} | |
private static final int CACHE_SIZE_REPOSITORIES = 10; | |
private static final int CACHE_SIZE_TYPES = 100; | |
private static final int CACHE_SIZE_OBJECTS = 400; | |
private final Cache linkCache; | |
private final Cache typeLinkCache; | |
private final Cache collectionLinkCache; | |
private final Cache templateCache; | |
private final Cache repositoryLinkCache; | |
/** | |
* Constructor. | |
*/ | |
public LinkCache(BindingSession session) { | |
int repCount = session.get(SessionParameter.CACHE_SIZE_REPOSITORIES, CACHE_SIZE_REPOSITORIES); | |
if (repCount < 1) { | |
repCount = CACHE_SIZE_REPOSITORIES; | |
} | |
int typeCount = session.get(SessionParameter.CACHE_SIZE_TYPES, CACHE_SIZE_TYPES); | |
if (typeCount < 1) { | |
typeCount = CACHE_SIZE_TYPES; | |
} | |
int objCount = session.get(SessionParameter.CACHE_SIZE_LINKS, CACHE_SIZE_OBJECTS); | |
if (objCount < 1) { | |
objCount = CACHE_SIZE_OBJECTS; | |
} | |
linkCache = new CacheImpl("Link Cache"); | |
linkCache.initialize(new String[] { | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository | |
LruCacheLevelImpl.class.getName() + " " + LruCacheLevelImpl.MAX_ENTRIES + "=" + objCount, // id | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=12", // rel | |
ContentTypeCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=3," | |
+ MapCacheLevelImpl.SINGLE_VALUE + "=true" // type | |
}); | |
typeLinkCache = new CacheImpl("Type Link Cache"); | |
typeLinkCache.initialize(new String[] { | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository | |
LruCacheLevelImpl.class.getName() + " " + LruCacheLevelImpl.MAX_ENTRIES + "=" + typeCount, // id | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=12", // rel | |
ContentTypeCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=3," | |
+ MapCacheLevelImpl.SINGLE_VALUE + "=true"// type | |
}); | |
collectionLinkCache = new CacheImpl("Collection Link Cache"); | |
collectionLinkCache.initialize(new String[] { | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=8" // collection | |
}); | |
templateCache = new CacheImpl("URI Template Cache"); | |
templateCache.initialize(new String[] { | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=6" // type | |
}); | |
repositoryLinkCache = new CacheImpl("Repository Link Cache"); | |
repositoryLinkCache.initialize(new String[] { | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=" + repCount, // repository | |
MapCacheLevelImpl.class.getName() + " " + MapCacheLevelImpl.CAPACITY + "=6" // rel | |
}); | |
} | |
/** | |
* Adds a link. | |
*/ | |
public void addLink(String repositoryId, String id, String rel, String type, String link) { | |
if (KNOWN_LINKS.contains(rel)) { | |
linkCache.put(link, repositoryId, id, rel, type); | |
} else if (Constants.REL_ALTERNATE.equals(rel)) { | |
// use streamId instead of type as discriminating parameter | |
String streamId = extractStreamId(link); | |
if (streamId != null) { | |
linkCache.put(link, repositoryId, id, rel, streamId); | |
} | |
} | |
} | |
/** | |
* Tries to extract a streamId from an alternate link. | |
*/ | |
// this is not strictly in the spec | |
protected String extractStreamId(String link) { | |
int i = link.lastIndexOf('?'); | |
if (i > 0) { | |
String[] params = link.substring(i + 1).split("&"); | |
for (String param : params) { | |
String[] parts = param.split("=", 2); | |
if (parts[0].equals(Constants.PARAM_STREAM_ID) && parts.length == 2) { | |
return parts[1]; | |
} | |
} | |
} | |
return null; | |
} | |
/** | |
* Removes all links of an object. | |
*/ | |
public void removeLinks(String repositoryId, String id) { | |
linkCache.remove(repositoryId, id); | |
} | |
/** | |
* Gets a link. | |
*/ | |
public String getLink(String repositoryId, String id, String rel, String type) { | |
return (String) linkCache.get(repositoryId, id, rel, type); | |
} | |
/** | |
* Gets a link. | |
*/ | |
public String getLink(String repositoryId, String id, String rel) { | |
return getLink(repositoryId, id, rel, null); | |
} | |
/** | |
* Checks a link. | |
*/ | |
public int checkLink(String repositoryId, String id, String rel, String type) { | |
return linkCache.check(repositoryId, id, rel, type); | |
} | |
/** | |
* Locks the link cache. | |
*/ | |
public void lockLinks() { | |
linkCache.writeLock(); | |
} | |
/** | |
* Unlocks the link cache. | |
*/ | |
public void unlockLinks() { | |
linkCache.writeUnlock(); | |
} | |
/** | |
* Adds a type link. | |
*/ | |
public void addTypeLink(String repositoryId, String id, String rel, String type, String link) { | |
if (KNOWN_LINKS.contains(rel)) { | |
typeLinkCache.put(link, repositoryId, id, rel, type); | |
} | |
} | |
/** | |
* Removes all links of a type. | |
*/ | |
public void removeTypeLinks(String repositoryId, String id) { | |
typeLinkCache.remove(repositoryId, id); | |
} | |
/** | |
* Gets a type link. | |
*/ | |
public String getTypeLink(String repositoryId, String id, String rel, String type) { | |
return (String) typeLinkCache.get(repositoryId, id, rel, type); | |
} | |
/** | |
* Locks the type link cache. | |
*/ | |
public void lockTypeLinks() { | |
typeLinkCache.writeLock(); | |
} | |
/** | |
* Unlocks the type link cache. | |
*/ | |
public void unlockTypeLinks() { | |
typeLinkCache.writeUnlock(); | |
} | |
/** | |
* Adds a collection. | |
*/ | |
public void addCollection(String repositoryId, String collection, String link) { | |
collectionLinkCache.put(link, repositoryId, collection); | |
} | |
/** | |
* Gets a collection. | |
*/ | |
public String getCollection(String repositoryId, String collection) { | |
return (String) collectionLinkCache.get(repositoryId, collection); | |
} | |
/** | |
* Adds an URI template. | |
*/ | |
public void addTemplate(String repositoryId, String type, String link) { | |
templateCache.put(link, repositoryId, type); | |
} | |
/** | |
* Gets an URI template and replaces place holders with the given | |
* parameters. | |
*/ | |
public String getTemplateLink(String repositoryId, String type, Map<String, Object> parameters) { | |
String template = (String) templateCache.get(repositoryId, type); | |
if (template == null) { | |
return null; | |
} | |
StringBuilder result = new StringBuilder(); | |
StringBuilder param = new StringBuilder(); | |
boolean paramMode = false; | |
for (int i = 0; i < template.length(); i++) { | |
char c = template.charAt(i); | |
if (paramMode) { | |
if (c == '}') { | |
paramMode = false; | |
String paramValue = UrlBuilder.normalizeParameter(parameters.get(param.toString())); | |
if (paramValue != null) { | |
result.append(IOUtils.encodeURL(paramValue)); | |
} | |
param = new StringBuilder(); | |
} else { | |
param.append(c); | |
} | |
} else { | |
if (c == '{') { | |
paramMode = true; | |
} else { | |
result.append(c); | |
} | |
} | |
} | |
return result.toString(); | |
} | |
/** | |
* Adds a collection. | |
*/ | |
public void addRepositoryLink(String repositoryId, String rel, String link) { | |
repositoryLinkCache.put(link, repositoryId, rel); | |
} | |
/** | |
* Gets a collection. | |
*/ | |
public String getRepositoryLink(String repositoryId, String rel) { | |
return (String) repositoryLinkCache.get(repositoryId, rel); | |
} | |
/** | |
* Removes all entries of the given repository from the caches. | |
*/ | |
public void clearRepository(String repositoryId) { | |
linkCache.remove(repositoryId); | |
typeLinkCache.remove(repositoryId); | |
collectionLinkCache.remove(repositoryId); | |
templateCache.remove(repositoryId); | |
repositoryLinkCache.remove(repositoryId); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see java.lang.Object#toString() | |
*/ | |
@Override | |
public String toString() { | |
return "Link Cache [link cache=" + linkCache + ", type link cache=" + typeLinkCache | |
+ ", collection link cache=" + collectionLinkCache + ", repository link cache=" + repositoryLinkCache | |
+ ", template cache=" + templateCache + "]"; | |
} | |
} |