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.xdbm.impl.avl;
21  
22  
23  import java.net.URI;
24  
25  import org.apache.directory.api.ldap.model.cursor.Cursor;
26  import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
27  import org.apache.directory.api.ldap.model.cursor.Tuple;
28  import org.apache.directory.api.ldap.model.exception.LdapException;
29  import org.apache.directory.api.ldap.model.schema.AttributeType;
30  import org.apache.directory.api.ldap.model.schema.LdapComparator;
31  import org.apache.directory.api.ldap.model.schema.MatchingRule;
32  import org.apache.directory.api.ldap.model.schema.Normalizer;
33  import org.apache.directory.api.ldap.model.schema.SchemaManager;
34  import org.apache.directory.api.ldap.model.schema.comparators.UuidComparator;
35  import org.apache.directory.server.core.partition.impl.btree.IndexCursorAdaptor;
36  import org.apache.directory.server.i18n.I18n;
37  import org.apache.directory.server.xdbm.AbstractIndex;
38  import org.apache.directory.server.xdbm.EmptyIndexCursor;
39  import org.apache.directory.server.xdbm.IndexEntry;
40  
41  
42  /**
43   * An Index backed by an AVL Tree.
44   *
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   */
47  public class AvlIndex<K, O> extends AbstractIndex<K, O, String>
48  {
49      protected Normalizer normalizer;
50      protected AvlTable<K, String> forward;
51      protected AvlTable<String, K> reverse;
52  
53  
54      public AvlIndex()
55      {
56          super( true );
57      }
58  
59  
60      public AvlIndex( String attributeId )
61      {
62          super( attributeId, true );
63      }
64  
65  
66      public AvlIndex( String attributeId, boolean withReverse )
67      {
68          super( attributeId, withReverse );
69      }
70  
71  
72      public void init( SchemaManager schemaManager, AttributeType attributeType ) throws Exception
73      {
74          this.attributeType = attributeType;
75  
76          MatchingRule mr = attributeType.getEquality();
77  
78          if ( mr == null )
79          {
80              mr = attributeType.getOrdering();
81          }
82  
83          if ( mr == null )
84          {
85              mr = attributeType.getSubstring();
86          }
87  
88          normalizer = mr.getNormalizer();
89  
90          if ( normalizer == null )
91          {
92              throw new Exception( I18n.err( I18n.ERR_212, attributeType ) );
93          }
94  
95          LdapComparator<K> comp = ( LdapComparator<K> ) mr.getLdapComparator();
96  
97          /*
98           * The forward key/value map stores attribute values to master table
99           * primary keys.  A value for an attribute can occur several times in
100          * different entries so the forward map can have more than one value.
101          */
102         forward = new AvlTable<K, String>( attributeType.getName(), comp, UuidComparator.INSTANCE, true );
103 
104         /*
105          * Now the reverse map stores the primary key into the master table as
106          * the key and the values of attributes as the value.  If an attribute
107          * is single valued according to its specification based on a schema
108          * then duplicate keys should not be allowed within the reverse table.
109          */
110         if ( withReverse )
111         {
112             if ( attributeType.isSingleValued() )
113             {
114                 reverse = new AvlTable<String, K>( attributeType.getName(), UuidComparator.INSTANCE, comp, false );
115             }
116             else
117             {
118                 reverse = new AvlTable<String, K>( attributeType.getName(), UuidComparator.INSTANCE, comp, true );
119             }
120         }
121     }
122 
123 
124     public void add( K attrVal, String id ) throws Exception
125     {
126         forward.put( attrVal, id );
127 
128         if ( withReverse )
129         {
130             reverse.put( id, attrVal );
131         }
132     }
133 
134 
135     /**
136      * {@inheritDoc}
137      */
138     public void close() throws Exception
139     {
140         if ( forward != null )
141         {
142             forward.close();
143         }
144 
145         if ( reverse != null )
146         {
147             reverse.close();
148         }
149     }
150 
151 
152     /**
153      * {@inheritDoc}
154      */
155     public int count() throws Exception
156     {
157         return forward.count();
158     }
159 
160 
161     /**
162      * {@inheritDoc}
163      */
164     public int count( K attrVal ) throws Exception
165     {
166         return forward.count( attrVal );
167     }
168 
169 
170     /**
171      * {@inheritDoc}
172      */
173     public void drop( String id ) throws Exception
174     {
175         if ( withReverse )
176         {
177             if ( isDupsEnabled() )
178             {
179                 Cursor<Tuple<String, K>> cursor = reverse.cursor( id );
180 
181                 while ( cursor.next() )
182                 {
183                     Tuple<String, K> tuple = cursor.get();
184                     forward.remove( tuple.getValue(), id );
185                 }
186 
187                 cursor.close();
188 
189             }
190             else
191             {
192                 K key = reverse.get( id );
193                 forward.remove( key );
194             }
195 
196             reverse.remove( id );
197         }
198     }
199 
200 
201     /**
202      * {@inheritDoc}
203      */
204     public void drop( K attrVal, String id ) throws Exception
205     {
206         forward.remove( attrVal, id );
207 
208         if ( withReverse )
209         {
210             reverse.remove( id, attrVal );
211         }
212     }
213 
214 
215     /**
216      * {@inheritDoc}
217      */
218     public boolean forward( K attrVal ) throws Exception
219     {
220         return forward.has( attrVal );
221     }
222 
223 
224     /**
225      * {@inheritDoc}
226      */
227     public boolean forward( K attrVal, String id ) throws LdapException
228     {
229         return forward.has( attrVal, id );
230     }
231 
232 
233     /**
234      * {@inheritDoc}
235      */
236     @SuppressWarnings("unchecked")
237     public Cursor<IndexEntry<K, String>> forwardCursor() throws LdapException
238     {
239         return new IndexCursorAdaptor( forward.cursor(), true );
240     }
241 
242 
243     /**
244      * {@inheritDoc}
245      */
246     @SuppressWarnings("unchecked")
247     public Cursor<IndexEntry<K, String>> forwardCursor( K key ) throws Exception
248     {
249         return new IndexCursorAdaptor( forward.cursor( key ), true );
250     }
251 
252 
253     /**
254      * {@inheritDoc}
255      */
256     public boolean forwardGreaterOrEq( K attrVal ) throws Exception
257     {
258         return forward.hasGreaterOrEqual( attrVal );
259     }
260 
261 
262     /**
263      * {@inheritDoc}
264      */
265     public boolean forwardGreaterOrEq( K attrVal, String id ) throws Exception
266     {
267         return forward.hasGreaterOrEqual( attrVal, id );
268     }
269 
270 
271     /**
272      * {@inheritDoc}
273      */
274     public boolean forwardLessOrEq( K attrVal ) throws Exception
275     {
276         return forward.hasLessOrEqual( attrVal );
277     }
278 
279 
280     /**
281      * {@inheritDoc}
282      */
283     public boolean forwardLessOrEq( K attrVal, String id ) throws Exception
284     {
285         return forward.hasLessOrEqual( attrVal, id );
286     }
287 
288 
289     /**
290      * {@inheritDoc}
291      */
292     public String forwardLookup( K attrVal ) throws Exception
293     {
294         return forward.get( attrVal );
295     }
296 
297 
298     /**
299      * {@inheritDoc}
300      */
301     public Cursor<String> forwardValueCursor( K key ) throws Exception
302     {
303         return forward.valueCursor( key );
304     }
305 
306 
307     /**
308      * {@inheritDoc}
309      */
310     public int greaterThanCount( K attrVal ) throws Exception
311     {
312         return forward.greaterThanCount( attrVal );
313     }
314 
315 
316     /**
317      * {@inheritDoc}
318      */
319     public int lessThanCount( K attrVal ) throws Exception
320     {
321         return forward.lessThanCount( attrVal );
322     }
323 
324 
325     /**
326      * {@inheritDoc}
327      */
328     public boolean reverse( String id ) throws Exception
329     {
330         if ( withReverse )
331         {
332             return reverse.has( id );
333         }
334         else
335         {
336             return false;
337         }
338     }
339 
340 
341     /**
342      * {@inheritDoc}
343      */
344     public boolean reverse( String id, K attrVal ) throws Exception
345     {
346         if ( withReverse )
347         {
348             return reverse.has( id, attrVal );
349         }
350         else
351         {
352             return false;
353         }
354     }
355 
356 
357     /**
358      * {@inheritDoc}
359      */
360     @SuppressWarnings("unchecked")
361     public Cursor<IndexEntry<K, String>> reverseCursor() throws Exception
362     {
363         if ( withReverse )
364         {
365             return new IndexCursorAdaptor( reverse.cursor(), false );
366         }
367         else
368         {
369             return new EmptyIndexCursor<K>();
370         }
371     }
372 
373 
374     /**
375      * {@inheritDoc}
376      */
377     @SuppressWarnings("unchecked")
378     public Cursor<IndexEntry<K, String>> reverseCursor( String id ) throws Exception
379     {
380         if ( withReverse )
381         {
382             return new IndexCursorAdaptor( reverse.cursor( id ), false );
383         }
384         else
385         {
386             return new EmptyIndexCursor<K>();
387         }
388     }
389 
390 
391     /**
392      * {@inheritDoc}
393      */
394     public boolean reverseGreaterOrEq( String id ) throws Exception
395     {
396         if ( withReverse )
397         {
398             return reverse.hasGreaterOrEqual( id );
399         }
400         else
401         {
402             return false;
403         }
404     }
405 
406 
407     /**
408      * {@inheritDoc}
409      */
410     public boolean reverseGreaterOrEq( String id, K attrVal ) throws LdapException
411     {
412         if ( withReverse )
413         {
414             return reverse.hasGreaterOrEqual( id, attrVal );
415         }
416         else
417         {
418             return false;
419         }
420     }
421 
422 
423     /**
424      * {@inheritDoc}
425      */
426     public boolean reverseLessOrEq( String id ) throws Exception
427     {
428         if ( withReverse )
429         {
430             return reverse.hasLessOrEqual( id );
431         }
432         else
433         {
434             return false;
435         }
436     }
437 
438 
439     /**
440      * {@inheritDoc}
441      */
442     public boolean reverseLessOrEq( String id, K attrVal ) throws Exception
443     {
444         if ( withReverse )
445         {
446             return reverse.hasLessOrEqual( id, attrVal );
447         }
448         else
449         {
450             return false;
451         }
452     }
453 
454 
455     /**
456      * {@inheritDoc}
457      */
458     public K reverseLookup( String id ) throws LdapException
459     {
460         if ( withReverse )
461         {
462             return reverse.get( id );
463         }
464         else
465         {
466             return null;
467         }
468     }
469 
470 
471     /**
472      * {@inheritDoc}
473      */
474     public Cursor<K> reverseValueCursor( String id ) throws Exception
475     {
476         if ( withReverse )
477         {
478             return reverse.valueCursor( id );
479         }
480         else
481         {
482             return new EmptyCursor<K>();
483         }
484     }
485 
486 
487     /**
488      * throws UnsupportedOperationException cause it is a in-memory index
489      */
490     public void setWkDirPath( URI wkDirPath )
491     {
492         throw new UnsupportedOperationException( I18n.err( I18n.ERR_213 ) );
493     }
494 
495 
496     /**
497      * this method always returns null for AvlIndex cause this is a in-memory index.
498      */
499     public URI getWkDirPath()
500     {
501         return null;
502     }
503 
504 
505     /**
506      * {@inheritDoc}
507      */
508     public boolean isDupsEnabled()
509     {
510         if ( withReverse )
511         {
512             return reverse.isDupsEnabled();
513         }
514         else
515         {
516             return false;
517         }
518     }
519 
520 
521     /**
522      * {@inheritDoc}
523      */
524     public void sync() throws Exception
525     {
526     }
527 }