View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.api.subtree;
21  
22  
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.concurrent.ConcurrentHashMap;
26  import java.util.concurrent.atomic.AtomicInteger;
27  
28  import org.apache.directory.api.ldap.model.name.Dn;
29  import org.apache.directory.api.ldap.model.subtree.Subentry;
30  
31  
32  /**
33   * A cache for subtree specifications. It associates a Subentry with a Dn,
34   * representing its position in the DIT.<br>
35   * This cache has a size limit set to 1000 at the moment. We should add a configuration
36   * parameter to manage its size.
37   *
38   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
39   */
40  public class SubentryCache implements Iterable<Dn>
41  {
42      /** The default cache size limit */
43      private static final int DEFAULT_CACHE_MAX_SIZE = 1000;
44  
45      /** The cache size limit */
46      private int cacheMaxSize = DEFAULT_CACHE_MAX_SIZE;
47  
48      /** The current cache size */
49      private AtomicInteger cacheSize;
50  
51      /** The Subentry cache */
52      private final Map<Dn, Subentry> cache;
53  
54  
55      /**
56       * Creates a new instance of SubentryCache with a default maximum size.
57       */
58      public SubentryCache()
59      {
60          cache = new ConcurrentHashMap<>();
61          cacheSize = new AtomicInteger( 0 );
62      }
63  
64  
65      /**
66       * Creates a new instance of SubentryCache with a specific maximum size.
67       * 
68       * @param maxSize The max number of elements in teh cache
69       */
70      public SubentryCache( int maxSize )
71      {
72          cache = new ConcurrentHashMap<>();
73          cacheSize = new AtomicInteger( 0 );
74          cacheMaxSize = maxSize;
75      }
76  
77  
78      /**
79       * Retrieve a Subentry given a Dn. If there is none, null will be returned.
80       *
81       * @param dn The Dn we want to get the Subentry for
82       * @return The found Subentry, or null
83       */
84      public final Subentry getSubentry( Dn dn )
85      {
86          return cache.get( dn );
87      }
88  
89  
90      /**
91       * Remove a Subentry for a given Dn
92       *
93       * @param dn The Dn for which we want to remove the
94       * associated Subentry
95       * @return The removed Subentry, if any
96       */
97      public final Subentry removeSubentry( Dn dn )
98      {
99          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 }