/* * 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(128); StringBuilder param = new StringBuilder(32); 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.setLength(0); } 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 + "]"; } }