001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.core.api.subtree; 021 022 023import java.util.Iterator; 024import java.util.Map; 025import java.util.concurrent.ConcurrentHashMap; 026import java.util.concurrent.atomic.AtomicInteger; 027 028import org.apache.directory.api.ldap.model.name.Dn; 029import org.apache.directory.api.ldap.model.subtree.Subentry; 030 031 032/** 033 * A cache for subtree specifications. It associates a Subentry with a Dn, 034 * representing its position in the DIT.<br> 035 * This cache has a size limit set to 1000 at the moment. We should add a configuration 036 * parameter to manage its size. 037 * 038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 039 */ 040public class SubentryCache implements Iterable<Dn> 041{ 042 /** The default cache size limit */ 043 private static final int DEFAULT_CACHE_MAX_SIZE = 1000; 044 045 /** The cache size limit */ 046 private int cacheMaxSize = DEFAULT_CACHE_MAX_SIZE; 047 048 /** The current cache size */ 049 private AtomicInteger cacheSize; 050 051 /** The Subentry cache */ 052 private final Map<Dn, Subentry> cache; 053 054 055 /** 056 * Creates a new instance of SubentryCache with a default maximum size. 057 */ 058 public SubentryCache() 059 { 060 cache = new ConcurrentHashMap<>(); 061 cacheSize = new AtomicInteger( 0 ); 062 } 063 064 065 /** 066 * Creates a new instance of SubentryCache with a specific maximum size. 067 * 068 * @param maxSize The max number of elements in teh cache 069 */ 070 public SubentryCache( int maxSize ) 071 { 072 cache = new ConcurrentHashMap<>(); 073 cacheSize = new AtomicInteger( 0 ); 074 cacheMaxSize = maxSize; 075 } 076 077 078 /** 079 * Retrieve a Subentry given a Dn. If there is none, null will be returned. 080 * 081 * @param dn The Dn we want to get the Subentry for 082 * @return The found Subentry, or null 083 */ 084 public final Subentry getSubentry( Dn dn ) 085 { 086 return cache.get( dn ); 087 } 088 089 090 /** 091 * Remove a Subentry for a given Dn 092 * 093 * @param dn The Dn for which we want to remove the 094 * associated Subentry 095 * @return The removed Subentry, if any 096 */ 097 public final Subentry removeSubentry( Dn dn ) 098 { 099 Subentry oldSubentry = cache.remove( dn ); 100 101 if ( oldSubentry != null ) 102 { 103 cacheSize.decrementAndGet(); 104 } 105 106 return oldSubentry; 107 } 108 109 110 /** 111 * Stores a new Subentry into the cache, associated with a Dn 112 * 113 * @param dn The Subentry Dn 114 * @param subentry The SubtreeSpecification 115 * @return The old Subentry, if any 116 */ 117 public Subentry addSubentry( Dn dn, Subentry subentry ) 118 { 119 if ( cacheSize.get() > cacheMaxSize ) 120 { 121 throw new IllegalStateException( "Cache is full: size=" + cacheSize.get() + ", max=" + cacheMaxSize ); 122 } 123 124 Subentry oldSubentry = cache.put( dn, subentry ); 125 126 if ( oldSubentry == null ) 127 { 128 cacheSize.getAndIncrement(); 129 } 130 131 return oldSubentry; 132 } 133 134 135 /** 136 * Tells if there is a Subentry associated with a Dn 137 * @param dn The Dn 138 * @return True if a Subentry is found 139 */ 140 public boolean hasSubentry( Dn dn ) 141 { 142 return cache.containsKey( dn ); 143 } 144 145 146 /** 147 * @return An Iterator over the Subentry's DNs 148 */ 149 public Iterator<Dn> iterator() 150 { 151 return cache.keySet().iterator(); 152 } 153 154 155 /** 156 * @return The number of elements in the cache 157 */ 158 public int getCacheSize() 159 { 160 return cacheSize.get(); 161 } 162}