/** * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2008 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: IndexCache.java,v 1.3 2009/12/12 00:03:13 veiming Exp $ * * Portions copyright 2013 ForgeRock, Inc. */ package com.sun.identity.entitlement.opensso; import com.sun.identity.entitlement.ResourceSaveIndexes; import com.sun.identity.entitlement.ResourceSearchIndexes; import java.util.HashSet; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Caches the indexes which are stored in Directory Server. */ public class IndexCache { public static final String HOST_ID = "host"; public static final String SUBJECT_ID = "subject"; public static final String PATH_ID = "path"; public static final String PARENTPATH_ID = "parentpath"; private static final int CACHE_BUCKET_LIMIT = 25; private int size = 1000000; private int initCapacity; private Cache subjectIndexCache; private Cache hostIndexCache; private Cache pathIndexCache; private Cache parentPathIndexCache; private ReadWriteLock rwlock = new ReentrantReadWriteLock(); /** * Constructs * * @param size Size of cache. */ public IndexCache(int size) { this.size = size; initCapacity = (int) (size * 0.01d); clearCaches(); } /** * Caches indexes. * * @param indexes Resource cache indexes. * @param subjectIndexes Subject search indexes. * @param dn Distinguished name of the privilege. */ public void cache( ResourceSaveIndexes indexes, Set subjectIndexes, String dn) { if (subjectIndexes != null) { cache(dn, subjectIndexes, subjectIndexCache); } cache(dn, indexes.getHostIndexes(), hostIndexCache); cache(dn, indexes.getPathIndexes(), pathIndexCache); cache(dn, indexes.getParentPathIndexes(), parentPathIndexCache); } private void cache(String dn, Set indexes, Cache cache) { rwlock.writeLock().lock(); try { for (String s : indexes) { String lc = s.toLowerCase(); Set setDNs = (Set)cache.get(lc); if (setDNs == null) { setDNs = new HashSet(); cache.put(lc, setDNs); setDNs.add(dn); } else { String cacheName = cache.getName(); if (!CacheTaboo.isTaboo(cacheName, lc)) { if (setDNs.size() >= CACHE_BUCKET_LIMIT) { CacheTaboo.taboo(cacheName, lc); cache.remove(lc); } else { setDNs.add(dn); } } } } } finally { rwlock.writeLock().unlock(); } } /** * Clear index cache. * * @param indexes Resource cache indexes. * @param dn Distinguished name of the privilege. */ public void clear(ResourceSaveIndexes indexes, String dn) { if (indexes != null) { clear(dn, indexes.getHostIndexes(), hostIndexCache); clear(dn, indexes.getPathIndexes(), pathIndexCache); clear(dn, indexes.getParentPathIndexes(), parentPathIndexCache); } } private void clear(String dn, Set indexes, Cache cache) { rwlock.writeLock().lock(); try { for (String s : indexes) { Set setDNs = (Set)cache.get(s); if (setDNs != null) { setDNs.remove(dn); } } } finally { rwlock.writeLock().unlock(); } } private synchronized void clearCaches() { rwlock.writeLock().lock(); try { subjectIndexCache = new Cache(SUBJECT_ID, initCapacity, size); hostIndexCache = new Cache(HOST_ID, initCapacity, size); pathIndexCache = new Cache(PATH_ID, initCapacity, size); parentPathIndexCache = new Cache(PARENTPATH_ID, initCapacity, size); } finally { rwlock.writeLock().unlock(); } } /** * Returns a set of DN that matches the resource and subject indexes. * * @param indexes Resource search indexes. * @param subjectIndexes Subject search indexes * @param bSubTree true for sub tree search mode. * @return A set of DN that matches the resource and subject indexes. */ public Set getMatchingEntries( ResourceSearchIndexes indexes, Set subjectIndexes, boolean bSubTree ) { rwlock.readLock().lock(); try { Set results = new HashSet(); boolean hasSubjectIndexes = (subjectIndexes != null) && !subjectIndexes.isEmpty(); if (hasSubjectIndexes) { for (String i : subjectIndexes) { Set r = (Set)subjectIndexCache.get(i); if (r != null) { results.addAll(r); } } results.retainAll(getHostIndexes(indexes)); } else { results.addAll(getHostIndexes(indexes)); } if (bSubTree) { results.retainAll(getPathParentIndexes(indexes)); } else { results.retainAll(getPathIndexes(indexes)); } return results; } finally { rwlock.readLock().unlock(); } } private Set getPathParentIndexes(ResourceSearchIndexes indexes) { Set parentPathIndexes = indexes.getParentPathIndexes(); Set results = new HashSet(); for (String i : parentPathIndexes) { Set r = (Set) parentPathIndexCache.get( i.toLowerCase()); if (r != null) { results.addAll(r); } } return results; } private Set getPathIndexes(ResourceSearchIndexes indexes) { Set pathIndexes = indexes.getPathIndexes(); Set results = new HashSet(); for (String i : pathIndexes) { Set r = (Set) pathIndexCache.get(i.toLowerCase()); if (r != null) { results.addAll(r); } }return results; } private Set getHostIndexes(ResourceSearchIndexes indexes) { Set results = new HashSet(); Set hostIndexes = indexes.getHostIndexes(); for (String i : hostIndexes) { Set r = (Set) hostIndexCache.get(i.toLowerCase()); if (r != null) { results.addAll(r); } } return results; } }