org.jahia.services.usermanager.UserCacheHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.services.usermanager.UserCacheHelper.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     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 3 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, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.services.usermanager;

import java.io.Serializable;

import javax.jcr.RepositoryException;
import javax.jcr.query.Query;
import javax.jcr.query.RowIterator;

import net.sf.ehcache.Element;
import net.sf.ehcache.config.Searchable;
import net.sf.ehcache.constructs.blocking.CacheEntryFactory;
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;

import net.sf.ehcache.search.Result;
import net.sf.ehcache.search.Results;
import net.sf.ehcache.search.expression.EqualTo;
import org.apache.commons.lang.StringUtils;
import org.jahia.api.Constants;
import org.jahia.services.cache.ehcache.EhCacheProvider;
import org.jahia.services.content.JCRContentUtils;
import org.jahia.services.content.JCRSessionFactory;
import org.jahia.services.query.QueryWrapper;
import org.jahia.services.sites.JahiaSitesService;

/**
 * User path by user name cache helper.
 *
 * @author Sergiy Shyrkov
 */
public class UserCacheHelper {

    private EhCacheProvider ehCacheProvider;
    private SelfPopulatingCache userPathByUserNameCache;
    private int timeToLiveForNonExistingUsers = 600;

    private class UserPathByUserNameCacheEntryFactory implements CacheEntryFactory {

        @Override
        public Object createEntry(final Object key) throws Exception {
            UserPathCacheKey k = (UserPathCacheKey) key;
            String path = internalGetUserPath(k.user, k.site);
            if (path != null) {
                return new Element(key, path);
            } else {
                return new Element(key, StringUtils.EMPTY, 0, timeToLiveForNonExistingUsers);
            }
        }
    }

    private static class UserPathCacheKey implements Serializable {

        private static final long serialVersionUID = -727853070149556455L;

        private final int hash;
        private final String site;
        private final String user;

        private UserPathCacheKey(String user, String site) {
            super();
            this.user = user;
            this.site = site;
            this.hash = getHashCode();
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }

            if (null == other || other.getClass() != this.getClass()) {
                return false;
            }

            UserPathCacheKey otherKey = (UserPathCacheKey) other;

            return StringUtils.equals(this.user, otherKey.user) && StringUtils.equals(this.site, otherKey.site);
        }

        private final int getHashCode() {
            int iTotal = 17;
            iTotal = 37 * iTotal + (user != null ? user.hashCode() : 0);
            iTotal = 37 * iTotal + (site != null ? site.hashCode() : 0);

            return iTotal;
        }

        @Override
        public int hashCode() {
            return hash;
        }
    }

    public String getUserPath(String name, String site) {
        final String value = (String) getUserPathByUserNameCache()
                .get(new UserPathCacheKey(name, StringUtils.isEmpty(site) ? null : site)).getObjectValue();
        if (value.equals(StringUtils.EMPTY)) {
            return null;
        }
        return value;
    }

    private SelfPopulatingCache getUserPathByUserNameCache() {
        // First do non-synchronized check to avoid locking any threads that invoke the method simultaneously.
        if (userPathByUserNameCache == null) {
            // Then check-again-and-initialize-if-needed within the synchronized block to ensure check-and-initialization consistency.
            synchronized (this) {
                if (userPathByUserNameCache == null) {
                    userPathByUserNameCache = ehCacheProvider.registerSelfPopulatingCache(
                            "org.jahia.services.usermanager.JahiaUserManagerService.userPathByUserNameCache",
                            new Searchable(), new UserPathByUserNameCacheEntryFactory());
                }
            }
        }
        return userPathByUserNameCache;
    }

    private String internalGetUserPath(String name, String siteName) throws RepositoryException {
        StringBuilder q = new StringBuilder();
        q.append("SELECT [j:nodename] from [jnt:user] where localname()='").append(JCRContentUtils.sqlEncode(name))
                .append("' and isdescendantnode('");
        if (siteName != null) {
            q.append(JahiaSitesService.SITES_JCR_PATH + "/").append(JCRContentUtils.sqlEncode(siteName));
        }
        q.append("/users/')");
        String p = queryUserPathInWorkspace(q, Constants.LIVE_WORKSPACE);
        if (p == null) {
            p = queryUserPathInWorkspace(q, null);
        }
        return p;
    }

    private String queryUserPathInWorkspace(StringBuilder q, String workspace) throws RepositoryException {
        final QueryWrapper query = JCRSessionFactory.getInstance().getCurrentSystemSession(workspace, null, null)
                .getWorkspace().getQueryManager().createQuery(q.toString(), Query.JCR_SQL2);
        query.setLimit(1);
        RowIterator it = query.execute().getRows();
        if (!it.hasNext()) {
            return null;
        }
        return it.nextRow().getPath();
    }

    public void setEhCacheProvider(EhCacheProvider ehCacheProvider) {
        this.ehCacheProvider = ehCacheProvider;
    }

    public void setTimeToLiveForNonExistingUsers(int timeToLiveForNonExistingUsers) {
        this.timeToLiveForNonExistingUsers = timeToLiveForNonExistingUsers;
    }

    public void updateAdded(String userPath) {
        getUserPathByUserNameCache().put(new Element(
                new UserPathCacheKey(StringUtils.substringAfterLast(userPath, "/"), getSiteKey(userPath)),
                userPath));
    }

    public void updateRemoved(String userPath) {
        getUserPathByUserNameCache()
                .remove(new UserPathCacheKey(StringUtils.substringAfterLast(userPath, "/"), getSiteKey(userPath)));
    }

    private String getSiteKey(String userPath) {
        return userPath.startsWith("/sites/") ? StringUtils.substringBetween(userPath, "/sites/", "/") : null;
    }

    public void clearNonExistingUsersCache() {
        SelfPopulatingCache cache = getUserPathByUserNameCache();
        Results results = cache.createQuery().addCriteria(new EqualTo("value", "")).includeKeys().execute();
        for (Result result : results.all()) {
            cache.remove(result.getKey());
        }
    }
}