org.wso2.carbon.registry.core.caching.CacheBackedRegistry.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.registry.core.caching.CacheBackedRegistry.java

Source

/*
 * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * Licensed 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.wso2.carbon.registry.core.caching;

import javax.cache.Cache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.registry.api.GhostResource;
import org.wso2.carbon.registry.core.ActionConstants;
import org.wso2.carbon.registry.core.Aspect;
import org.wso2.carbon.registry.core.Association;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Comment;
import org.wso2.carbon.registry.core.LogEntry;
import org.wso2.carbon.registry.core.LogEntryCollection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.ResourcePath;
import org.wso2.carbon.registry.core.TaggedResourcePath;
import org.wso2.carbon.registry.core.Tag;
import org.wso2.carbon.registry.core.config.DataBaseConfiguration;
import org.wso2.carbon.registry.core.config.Mount;
import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.core.config.RemoteConfiguration;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.jdbc.EmbeddedRegistry;
import org.wso2.carbon.registry.core.secure.AuthorizationFailedException;
import org.wso2.carbon.registry.core.session.CurrentSession;
import org.wso2.carbon.registry.core.utils.AuthorizationUtils;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;

import java.io.Reader;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * CacheBackedRegistry has wrapped from original Registry interface to support caching
 */
public class CacheBackedRegistry implements Registry {

    /**
     * wrapped this original registry object from CachedBackedRegistry
     */
    private Registry registry;

    private int tenantId = MultitenantConstants.INVALID_TENANT_ID;

    private Map<String, String> cacheIds = new HashMap<String, String>();
    private Map<String, DataBaseConfiguration> dbConfigs = new HashMap<String, DataBaseConfiguration>();
    private Map<String, String> pathMap = new HashMap<String, String>();

    private static Cache<RegistryCacheKey, GhostResource> getCache() {
        return RegistryUtils.getResourceCache(RegistryConstants.REGISTRY_CACHE_BACKED_ID);
    }

    private static final Log log = LogFactory.getLog(CacheBackedRegistry.class);
    private static final Log audit = CarbonConstants.AUDIT_LOG;

    public CacheBackedRegistry(Registry registry) {
        this.registry = registry;
        RegistryContext registryContext = RegistryContext.getBaseInstance();
        for (Mount mount : registryContext.getMounts()) {
            for (RemoteConfiguration configuration : registryContext.getRemoteInstances()) {
                if (configuration.getDbConfig() != null && mount.getInstanceId().equals(configuration.getId())) {
                    dbConfigs.put(mount.getPath(), registryContext.getDBConfig(configuration.getDbConfig()));
                    pathMap.put(mount.getPath(), mount.getTargetPath());
                } else if (configuration.getCacheId() != null
                        && mount.getInstanceId().equals(configuration.getId())) {
                    cacheIds.put(mount.getPath(), configuration.getCacheId());
                    pathMap.put(mount.getPath(), mount.getTargetPath());
                }
            }
        }
    }

    public CacheBackedRegistry(Registry registry, int tenantId) {
        this(registry);
        this.tenantId = tenantId;
    }

    /**
     * This method used to calculate the cache key
     *
     * @param registry Registry
     * @param path     Resource path
     *
     * @return RegistryCacheKey
     */
    private RegistryCacheKey getRegistryCacheKey(Registry registry, String path) {
        String connectionId = "";

        int tenantId;
        if (this.tenantId == MultitenantConstants.INVALID_TENANT_ID) {
            tenantId = CurrentSession.getTenantId();
            if (tenantId == MultitenantConstants.INVALID_TENANT_ID) {
                tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
            }
        } else {
            tenantId = this.tenantId;
        }
        String resourceCachePath;
        RegistryContext registryContext = registry.getRegistryContext();
        if (registryContext == null) {
            registryContext = RegistryContext.getBaseInstance();
        }
        if (registry instanceof EmbeddedRegistry) {
            resourceCachePath = path;
        } else {
            resourceCachePath = RegistryUtils.getAbsolutePath(registryContext, path);
        }
        DataBaseConfiguration dataBaseConfiguration = null;
        if (dbConfigs.size() > 0) {
            for (String sourcePath : dbConfigs.keySet()) {
                if (resourceCachePath.startsWith(sourcePath)) {
                    resourceCachePath = pathMap.get(sourcePath) + resourceCachePath.substring(sourcePath.length());
                    dataBaseConfiguration = dbConfigs.get(sourcePath);
                    break;
                }
            }
        } else if (cacheIds.size() > 0) {
            for (String sourcePath : cacheIds.keySet()) {
                if (resourceCachePath.startsWith(sourcePath)) {
                    resourceCachePath = pathMap.get(sourcePath) + resourceCachePath.substring(sourcePath.length());
                    connectionId = cacheIds.get(sourcePath);
                    break;
                }
            }
        }
        if (connectionId.length() == 0) {
            if (dataBaseConfiguration == null) {
                dataBaseConfiguration = registryContext.getDefaultDataBaseConfiguration();
            }
            if (dataBaseConfiguration != null) {
                connectionId = (dataBaseConfiguration.getUserName() != null
                        ? dataBaseConfiguration.getUserName().split("@")[0]
                        : dataBaseConfiguration.getUserName()) + "@" + dataBaseConfiguration.getDbUrl();
            }
        }

        return RegistryUtils.buildRegistryCacheKey(connectionId, tenantId, resourceCachePath);
    }

    @SuppressWarnings("unchecked")
    public Resource get(String path) throws RegistryException {
        if (registry.getRegistryContext().isNoCachePath(path) || isCommunityFeatureRequest(path)) {
            return registry.get(path);
        }

        Resource resource;
        if (!AuthorizationUtils.authorize(path, ActionConstants.GET)) {
            StringBuilder builder = new StringBuilder();
            builder.append("User ").append(CurrentSession.getUser())
                    .append(" is not authorized to read the resource ").append(path).append(".");
            String msg = builder.toString();
            audit.warn(msg);
            throw new AuthorizationFailedException(msg);
        }

        GhostResource<Resource> ghostResource = getGhostResourceFromCache(path);

        resource = ghostResource.getResource();
        if (resource == null) {
            synchronized (path.intern()) {
                resource = registry.get(path);
                if (resource.getProperty(RegistryConstants.REGISTRY_LINK) == null
                        || resource.getProperty(RegistryConstants.REGISTRY_MOUNT) != null) {
                    ghostResource.setResource(resource);
                }
            }
        }

        return resource;
    }

    private GhostResource<Resource> getGhostResourceFromCache(String path) throws RegistryException {
        Resource resource;
        RegistryCacheKey registryCacheKey = getRegistryCacheKey(registry, path);

        GhostResource<Resource> ghostResource;
        Object ghostResourceObject;
        Cache<RegistryCacheKey, GhostResource> cache = getCache();
        if ((ghostResourceObject = cache.get(registryCacheKey)) == null) {
            synchronized (path.intern()) {
                //Checking again as the some other previous thread might have updated the cache
                if ((ghostResourceObject = cache.get(registryCacheKey)) == null) {
                    resource = registry.get(path);
                    ghostResource = new GhostResource<Resource>(resource);
                    if (resource.getProperty(RegistryConstants.REGISTRY_LINK) == null
                            || resource.getProperty(RegistryConstants.REGISTRY_MOUNT) != null) {
                        cache.put(registryCacheKey, ghostResource);
                    }
                } else {
                    ghostResource = (GhostResource<Resource>) ghostResourceObject;
                }
            }
        } else {
            ghostResource = (GhostResource<Resource>) ghostResourceObject;
        }
        return ghostResource;
    }

    private GhostResource<Resource> getGhostCollectionFromCache(String path, int start, int pageSize)
            throws RegistryException {
        Collection collection;

        GhostResource<Resource> ghostResource;

        RegistryCacheKey registryCacheKey = getRegistryCacheKey(registry,
                path + ";start=" + start + ";pageSize=" + pageSize);

        Cache<RegistryCacheKey, GhostResource> cache = getCache();
        if (!cache.containsKey(registryCacheKey)) {
            synchronized (path.intern()) {
                //check again to cache to validate whether any other thread have updated with that time.
                if (!cache.containsKey(registryCacheKey)) {
                    collection = registry.get(path, start, pageSize);
                    ghostResource = new GhostResource<Resource>(collection);
                    if (collection.getProperty(RegistryConstants.REGISTRY_LINK) == null) {
                        cache.put(registryCacheKey, ghostResource);
                    }
                } else {
                    ghostResource = (GhostResource<Resource>) cache.get(registryCacheKey);
                }
            }
        } else {
            ghostResource = (GhostResource<Resource>) cache.get(registryCacheKey);
        }

        return ghostResource;
    }

    @SuppressWarnings("unchecked")
    public Collection get(String path, int start, int pageSize) throws RegistryException {
        if (registry.getRegistryContext().isNoCachePath(path) || isCommunityFeatureRequest(path)) {
            return registry.get(path, start, pageSize);
        }
        if (!AuthorizationUtils.authorize(path, ActionConstants.GET)) {
            StringBuilder builder = new StringBuilder();
            builder.append("User ").append(CurrentSession.getUser())
                    .append(" is not authorized to read the resource ").append(path).append(".");
            String msg = builder.toString();
            audit.warn(msg);
            throw new AuthorizationFailedException(msg);
        }

        GhostResource<Resource> ghostResource = getGhostCollectionFromCache(path, start, pageSize);
        Collection collection = (Collection) ghostResource.getResource();
        if (collection == null) {
            synchronized (path.intern()) {
                collection = registry.get(path, start, pageSize);
                if (collection.getProperty(RegistryConstants.REGISTRY_LINK) == null) {
                    ghostResource.setResource(collection);
                }
            }
        }
        return collection;
    }

    // test whether this request was made specifically for a tag, comment or a rating.
    private boolean isCommunityFeatureRequest(String path) {
        if (path == null) {
            return false;
        }
        String resourcePath = new ResourcePath(path).getPath();
        if (path.length() > resourcePath.length()) {
            String fragment = path.substring(resourcePath.length());
            for (String temp : new String[] { "tags", "comments", "ratings" }) {
                if (fragment.contains(temp)) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean resourceExists(String path) throws RegistryException {
        if (registry.getRegistryContext().isNoCachePath(path)) {
            return registry.resourceExists(path);
        }
        Cache<RegistryCacheKey, GhostResource> cache = getCache();
        RegistryCacheKey registryCacheKey = getRegistryCacheKey(registry, path);
        if (cache.containsKey(registryCacheKey)) {
            return true;
        } else if (registry.resourceExists(path)) {
            cache.put(registryCacheKey, new GhostResource<Resource>(null));
            return true;
        }
        return false;
    }

    public Resource getMetaData(String path) throws RegistryException {
        return registry.getMetaData(path);
    }

    public String importResource(String suggestedPath, String sourceURL, Resource resource)
            throws RegistryException {
        return registry.importResource(suggestedPath, sourceURL, resource);
    }

    public String rename(String currentPath, String newName) throws RegistryException {
        return registry.rename(currentPath, newName);
    }

    public String move(String currentPath, String newPath) throws RegistryException {
        return registry.move(currentPath, newPath);
    }

    public String copy(String sourcePath, String targetPath) throws RegistryException {
        return registry.copy(sourcePath, targetPath);
    }

    public void createVersion(String path) throws RegistryException {
        registry.createVersion(path);
    }

    public String[] getVersions(String path) throws RegistryException {
        return registry.getVersions(path);
    }

    public void restoreVersion(String versionPath) throws RegistryException {
        registry.restoreVersion(versionPath);
    }

    public void addAssociation(String sourcePath, String targetPath, String associationType)
            throws RegistryException {
        registry.addAssociation(sourcePath, targetPath, associationType);
    }

    public void removeAssociation(String sourcePath, String targetPath, String associationType)
            throws RegistryException {
        registry.removeAssociation(sourcePath, targetPath, associationType);
    }

    public Association[] getAllAssociations(String resourcePath) throws RegistryException {
        return registry.getAllAssociations(resourcePath);
    }

    public Association[] getAssociations(String resourcePath, String associationType) throws RegistryException {
        return registry.getAssociations(resourcePath, associationType);
    }

    public void applyTag(String resourcePath, String tag) throws RegistryException {
        registry.applyTag(resourcePath, tag);
    }

    public TaggedResourcePath[] getResourcePathsWithTag(String tag) throws RegistryException {
        return registry.getResourcePathsWithTag(tag);
    }

    public Tag[] getTags(String resourcePath) throws RegistryException {
        return registry.getTags(resourcePath);
    }

    public void removeTag(String path, String tag) throws RegistryException {
        registry.removeTag(path, tag);
    }

    public String addComment(String resourcePath, Comment comment) throws RegistryException {
        return registry.addComment(resourcePath, comment);
    }

    public void editComment(String commentPath, String text) throws RegistryException {
        registry.editComment(commentPath, text);
    }

    public void removeComment(String commentPath) throws RegistryException {
        registry.removeComment(commentPath);
    }

    public Comment[] getComments(String resourcePath) throws RegistryException {
        return registry.getComments(resourcePath);
    }

    public void rateResource(String resourcePath, int rating) throws RegistryException {
        registry.rateResource(resourcePath, rating);
    }

    public float getAverageRating(String resourcePath) throws RegistryException {
        return registry.getAverageRating(resourcePath);
    }

    public int getRating(String path, String userName) throws RegistryException {
        return registry.getRating(path, userName);
    }

    public Collection executeQuery(String path, Map parameters) throws RegistryException {
        return registry.executeQuery(path, parameters);
    }

    public LogEntry[] getLogs(String resourcePath, int action, String userName, Date from, Date to,
            boolean recentFirst) throws RegistryException {
        return registry.getLogs(resourcePath, action, userName, from, to, recentFirst);
    }

    public LogEntryCollection getLogCollection(String resourcePath, int action, String userName, Date from, Date to,
            boolean recentFirst) throws RegistryException {
        return registry.getLogCollection(resourcePath, action, userName, from, to, recentFirst);
    }

    public String[] getAvailableAspects() {
        return registry.getAvailableAspects();
    }

    public void associateAspect(String resourcePath, String aspect) throws RegistryException {
        registry.associateAspect(resourcePath, aspect);
    }

    public void invokeAspect(String resourcePath, String aspectName, String action) throws RegistryException {
        registry.invokeAspect(resourcePath, aspectName, action);
    }

    public void invokeAspect(String resourcePath, String aspectName, String action, Map<String, String> parameters)
            throws RegistryException {
        registry.invokeAspect(resourcePath, aspectName, action, parameters);
    }

    public String[] getAspectActions(String resourcePath, String aspectName) throws RegistryException {
        return registry.getAspectActions(resourcePath, aspectName);
    }

    public RegistryContext getRegistryContext() {
        return registry.getRegistryContext();
    }

    public Collection searchContent(String keywords) throws RegistryException {
        return registry.searchContent(keywords);
    }

    public void createLink(String path, String target) throws RegistryException {
        registry.createLink(path, target);
    }

    public void createLink(String path, String target, String subTargetPath) throws RegistryException {
        registry.createLink(path, target, subTargetPath);
    }

    public void removeLink(String path) throws RegistryException {
        registry.removeLink(path);
    }

    public void restore(String path, Reader reader) throws RegistryException {
        registry.restore(path, reader);
    }

    public void dump(String path, Writer writer) throws RegistryException {
        registry.dump(path, writer);
    }

    public String getEventingServiceURL(String path) throws RegistryException {
        return registry.getEventingServiceURL(path);
    }

    public void setEventingServiceURL(String path, String eventingServiceURL) throws RegistryException {
        registry.setEventingServiceURL(path, eventingServiceURL);
    }

    public boolean removeAspect(String aspect) throws RegistryException {
        return registry.removeAspect(aspect);
    }

    public boolean addAspect(String name, Aspect aspect) throws RegistryException {
        return registry.addAspect(name, aspect);
    }

    public void beginTransaction() throws RegistryException {
        registry.beginTransaction();
    }

    public void commitTransaction() throws RegistryException {
        registry.commitTransaction();
    }

    public void rollbackTransaction() throws RegistryException {
        registry.rollbackTransaction();
    }

    public Resource newResource() throws RegistryException {
        return registry.newResource();
    }

    public Collection newCollection() throws RegistryException {
        return registry.newCollection();
    }

    public String importResource(String suggestedPath, String sourceURL,
            org.wso2.carbon.registry.api.Resource resource) throws org.wso2.carbon.registry.api.RegistryException {
        return registry.importResource(suggestedPath, sourceURL, resource);
    }

    public String put(String suggestedPath, Resource resource) throws RegistryException {
        return registry.put(suggestedPath, resource);
    }

    public void delete(String path) throws RegistryException {
        registry.delete(path);
    }

    public String addComment(String resourcePath, org.wso2.carbon.registry.api.Comment comment)
            throws org.wso2.carbon.registry.api.RegistryException {
        return registry.addComment(resourcePath, comment);
    }

    public String put(String suggestedPath, org.wso2.carbon.registry.api.Resource resource)
            throws org.wso2.carbon.registry.api.RegistryException {
        return registry.put(suggestedPath, resource);
    }

    public boolean removeVersionHistory(String path, long snapshotId) throws RegistryException {
        return registry.removeVersionHistory(path, snapshotId);
    }

    @Override
    public void dumpLite(String path, Writer writer) throws RegistryException {
        registry.dumpLite(path, writer);
    }
}