blob: 01c5a00f8b4c38e8d6c588b08f13810c2c8c31c0 [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.
*/
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.SessionParameterDefaults;
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 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,
SessionParameterDefaults.CACHE_SIZE_REPOSITORIES);
if (repCount < 1) {
repCount = SessionParameterDefaults.CACHE_SIZE_REPOSITORIES;
}
int typeCount = session.get(SessionParameter.CACHE_SIZE_TYPES, SessionParameterDefaults.CACHE_SIZE_TYPES);
if (typeCount < 1) {
typeCount = SessionParameterDefaults.CACHE_SIZE_TYPES;
}
int objCount = session.get(SessionParameter.CACHE_SIZE_LINKS, SessionParameterDefaults.CACHE_SIZE_LINKS);
if (objCount < 1) {
objCount = SessionParameterDefaults.CACHE_SIZE_LINKS;
}
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 + "]";
}
}