/* * Copyright (C) 2005-2007 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have recieved a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.dictionary; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.namespace.NamespaceException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Simple in-memory namespace DAO */ public class NamespaceDAOImpl implements NamespaceDAO { private static final Log logger = LogFactory.getLog(NamespaceDAOImpl.class); /** * Lock objects */ private ReadWriteLock lock = new ReentrantReadWriteLock(); private Lock readLock = lock.readLock(); private Lock writeLock = lock.writeLock(); // internal caches that are clusterable private SimpleCache> urisCache; private SimpleCache> prefixesCache; // Dependencies private TenantService tenantService; public void setTenantService(TenantService tenantService) { this.tenantService = tenantService; } public void setUrisCache(SimpleCache> urisCache) { this.urisCache = urisCache; } public void setPrefixesCache(SimpleCache> prefixesCache) { this.prefixesCache = prefixesCache; } private DictionaryDAO dictionaryDAO; public void registerDictionary(DictionaryDAO dictionaryDAO) { this.dictionaryDAO = dictionaryDAO; } /** * Initialise empty namespaces */ public void init() { String tenantDomain = getTenantDomain(); putUrisCtx(tenantDomain, new ArrayList()); putPrefixesCtx(tenantDomain, new HashMap()); if (logger.isDebugEnabled()) { logger.debug("Empty namespaces initialised"); } } /** * Destroy the namespaces */ public void destroy() { String tenantDomain = getTenantDomain(); removeUrisCtx(tenantDomain); removePrefixesCtx(tenantDomain); if (logger.isDebugEnabled()) { logger.debug("Namespaces destroyed"); } } /** * Resets the namespaces (by resetting the dictionary) */ private void reset() { if (logger.isDebugEnabled()) { logger.debug("Resetting namespaces ..."); } if (dictionaryDAO == null) { // Unexpected throw new AlfrescoRuntimeException("Dictionary should be registered in order to perform reset"); } else { dictionaryDAO.reset(); } if (logger.isDebugEnabled()) { logger.debug("... resetting namespaces completed"); } } /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getURIs() */ public Collection getURIs() { if (! tenantService.isTenantUser()) { return Collections.unmodifiableCollection(getUrisCtx()); } else { // Get tenant-specific URIs List domainUris = getUrisCtx(); // Get non-tenant-specific URIs (and filter out, if overridden) List urisFiltered = new ArrayList(); for(String uri : getUrisCtx("")) { if (domainUris.contains(uri)) { // overridden, hence skip this default prefix continue; } urisFiltered.add(uri); } // default (non-overridden) + tenant-specific urisFiltered.addAll(domainUris); return Collections.unmodifiableCollection(urisFiltered); } } /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getPrefixes() */ public Collection getPrefixes() { if (! tenantService.isTenantUser()) { return Collections.unmodifiableCollection(getPrefixesCtx().keySet()); } else { // Get tenant-specific prefixes Collection domainPrefixes = getPrefixesCtx().keySet(); // Get non-tenant-specific URIs (and filter out, if overridden) List prefixesFiltered = new ArrayList(); for(String prefix : getPrefixesCtx("").keySet()) { if (domainPrefixes.contains(prefix)) { // overridden, hence skip this default prefix continue; } prefixesFiltered.add(prefix); } // default (non-overridden) + tenant-specific prefixesFiltered.addAll(domainPrefixes); return Collections.unmodifiableCollection(prefixesFiltered); } } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#addURI(java.lang.String) */ public void addURI(String uri) { if (getUrisCtx().contains(uri)) { throw new NamespaceException("URI " + uri + " has already been defined"); } getUrisCtx().add(uri); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#addPrefix(java.lang.String, java.lang.String) */ public void addPrefix(String prefix, String uri) { if (!getUrisCtx().contains(uri)) { throw new NamespaceException("Namespace URI " + uri + " does not exist"); } getPrefixesCtx().put(prefix, uri); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#removeURI(java.lang.String) */ public void removeURI(String uri) { getUrisCtx().remove(uri); } /* (non-Javadoc) * @see org.alfresco.repo.dictionary.impl.NamespaceDAO#removePrefix(java.lang.String) */ public void removePrefix(String prefix) { getPrefixesCtx().remove(prefix); } /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getNamespaceURI(java.lang.String) */ public String getNamespaceURI(String prefix) { if (! tenantService.isTenantUser()) { return getPrefixesCtx().get(prefix); } else { // first look for tenant-specific prefix String uri = getPrefixesCtx().get(prefix); if (uri != null) { // found tenant specific uri return uri; } else { // try with default (non-tenant-specific) prefix return getPrefixesCtx("").get(prefix); } } } /* (non-Javadoc) * @see org.alfresco.repo.ref.NamespacePrefixResolver#getPrefixes(java.lang.String) */ public Collection getPrefixes(String URI) { if (! tenantService.isTenantUser()) { Collection uriPrefixes = new ArrayList(); for (String key : getPrefixesCtx().keySet()) { String uri = getPrefixesCtx().get(key); if ((uri != null) && (uri.equals(URI))) { uriPrefixes.add(key); } } return uriPrefixes; } else { // check domain prefixes Collection domainUriPrefixes = new ArrayList(); for (String key : getPrefixesCtx().keySet()) { String uri = getPrefixesCtx().get(key); if ((uri != null) && (uri.equals(URI))) { domainUriPrefixes.add(key); } } // check non-domain prefixes Collection uriPrefixes = new ArrayList(); for (String key : getPrefixesCtx("").keySet()) { String uri = getPrefixesCtx("").get(key); if ((uri != null) && (uri.equals(URI))) { if (domainUriPrefixes != null) { if (domainUriPrefixes.contains(key)) { // overridden, hence skip this default prefix continue; } } uriPrefixes.add(key); } } if (domainUriPrefixes != null) { // default (non-overridden) + domain uriPrefixes.addAll(domainUriPrefixes); } return uriPrefixes; } } /** * Get URIs from the cache (in the context of the current user's tenant domain) * * @return URIs */ private List getUrisCtx() { return getUrisCtx(getTenantDomain()); } /** * Get URIs from the cache * * @param tenantDomain * @return URIs */ private List getUrisCtx(String tenantDomain) { List uris = null; try { readLock.lock(); uris = urisCache.get(tenantDomain); } finally { readLock.unlock(); } if (uris == null) { reset(); // reset caches - may have been invalidated (e.g. in a cluster) try { readLock.lock(); uris = urisCache.get(tenantDomain); } finally { readLock.unlock(); } if (uris == null) { // unexpected throw new AlfrescoRuntimeException("Failed to re-initialise urisCache " + tenantDomain); } } return uris; } /** * Put URIs into the cache * * @param tenantDomain * @param uris */ private void putUrisCtx(String tenantDomain, List uris) { try { writeLock.lock(); urisCache.put(tenantDomain, uris); } finally { writeLock.unlock(); } } /** * Remove URIs from the cache * * @param tenantDomain */ private void removeUrisCtx(String tenantDomain) { try { writeLock.lock(); if (urisCache.get(tenantDomain) != null) { urisCache.get(tenantDomain).clear(); urisCache.remove(tenantDomain); } } finally { writeLock.unlock(); } } /** * Get prefixes from the cache * * @return prefixes */ private Map getPrefixesCtx() { return getPrefixesCtx(getTenantDomain()); } /** * Get prefixes from the cache * * @param tenantDomain * @return prefixes */ private Map getPrefixesCtx(String tenantDomain) { Map prefixes = null; try { readLock.lock(); prefixes = prefixesCache.get(tenantDomain); } finally { readLock.unlock(); } if (prefixes == null) { reset(); // reset caches - may have been invalidated (e.g. in a cluster) try { readLock.lock(); prefixes = prefixesCache.get(tenantDomain); } finally { readLock.unlock(); } if (prefixes == null) { // unexpected throw new AlfrescoRuntimeException("Failed to re-initialise prefixesCache " + tenantDomain); } } return prefixes; } /** * Put prefixes into the cache * * @param tenantDomain * @param prefixes */ private void putPrefixesCtx(String tenantDomain, Map prefixes) { try { writeLock.lock(); prefixesCache.put(tenantDomain, prefixes); } finally { writeLock.unlock(); } } /** * Remove prefixes from the cache * * @param tenantDomain */ private void removePrefixesCtx(String tenantDomain) { try { writeLock.lock(); if (prefixesCache.get(tenantDomain) != null) { prefixesCache.get(tenantDomain).clear(); prefixesCache.remove(tenantDomain); } } finally { writeLock.unlock(); } } /** * Local helper - returns tenant domain (or empty string if default non-tenant) */ private String getTenantDomain() { return tenantService.getCurrentUserDomain(); } }