1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.partition.impl.btree.jdbm;
21
22
23 import java.io.IOException;
24
25 import jdbm.btree.BTree;
26
27 import org.apache.directory.api.ldap.model.constants.Loggers;
28 import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
29 import org.apache.directory.api.ldap.model.cursor.Cursor;
30 import org.apache.directory.api.ldap.model.cursor.CursorException;
31 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
32 import org.apache.directory.api.ldap.model.cursor.Tuple;
33 import org.apache.directory.api.ldap.model.exception.LdapException;
34 import org.apache.directory.server.core.avltree.ArrayTree;
35 import org.apache.directory.server.core.avltree.ArrayTreeCursor;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42
43
44
45 class DupsCursor<K, V> extends AbstractCursor<Tuple<K, V>>
46 {
47 private static final Logger LOG = LoggerFactory.getLogger( DupsCursor.class );
48
49
50 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
51
52
53 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
54
55
56
57
58 private final JdbmTable<K, V> table;
59
60
61
62
63
64
65
66 private final DupsContainerCursor<K, V> containerCursor;
67
68
69
70
71 private final Tuple<K, DupsContainer<V>> containerTuple = new Tuple<>();
72
73
74
75
76
77
78
79
80 private Cursor<V> dupsCursor;
81
82
83
84
85
86
87 private final Tuple<K, V> returnedTuple = new Tuple<>();
88
89
90
91
92 private boolean valueAvailable;
93
94
95 DupsCursor( JdbmTable<K, V> table )
96 {
97 if ( IS_DEBUG )
98 {
99 LOG_CURSOR.debug( "Creating DupsCursor {}", this );
100 }
101
102 this.table = table;
103 this.containerCursor = new DupsContainerCursor<>( table );
104 LOG.debug( "Created on table {}", table );
105 }
106
107
108 public boolean available()
109 {
110 return valueAvailable;
111 }
112
113
114 public void beforeKey( K key ) throws Exception
115 {
116 beforeValue( key, null );
117 }
118
119
120 public void beforeValue( K key, V value ) throws LdapException, CursorException
121 {
122 checkNotClosed();
123 containerCursor.before( new Tuple<K, DupsContainer<V>>( key, null ) );
124
125 if ( containerCursor.next() )
126 {
127 containerTuple.setBoth( containerCursor.get() );
128 DupsContainer<V> values = containerTuple.getValue();
129
130 if ( values.isArrayTree() )
131 {
132 ArrayTree<V> set = values.getArrayTree();
133 dupsCursor = new ArrayTreeCursor<>( set );
134 }
135 else
136 {
137 try
138 {
139 BTree tree = table.getBTree( values.getBTreeRedirect() );
140 dupsCursor = new KeyBTreeCursor<>( tree, table.getValueComparator() );
141 }
142 catch ( IOException e )
143 {
144 throw new CursorException( e );
145 }
146 }
147
148 if ( value == null )
149 {
150 return;
151 }
152
153
154 if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
155 {
156 dupsCursor.before( value );
157 }
158
159 return;
160 }
161
162 clearValue();
163 containerTuple.setKey( null );
164 containerTuple.setValue( null );
165 }
166
167
168 public void afterKey( K key ) throws Exception
169 {
170 afterValue( key, null );
171 }
172
173
174 public void afterValue( K key, V value ) throws LdapException, CursorException
175 {
176 checkNotClosed();
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 if ( value == null )
199 {
200 containerCursor.after( new Tuple<K, DupsContainer<V>>( key, null ) );
201 }
202 else
203 {
204 containerCursor.before( new Tuple<K, DupsContainer<V>>( key, null ) );
205 }
206
207 if ( containerCursor.next() )
208 {
209 containerTuple.setBoth( containerCursor.get() );
210 DupsContainer<V> values = containerTuple.getValue();
211
212 if ( values.isArrayTree() )
213 {
214 ArrayTree<V> set = values.getArrayTree();
215 dupsCursor = new ArrayTreeCursor<>( set );
216 }
217 else
218 {
219 try
220 {
221 BTree tree = table.getBTree( values.getBTreeRedirect() );
222 dupsCursor = new KeyBTreeCursor<>( tree, table.getValueComparator() );
223 }
224 catch ( IOException e )
225 {
226 throw new CursorException( e );
227 }
228 }
229
230 if ( value == null )
231 {
232 return;
233 }
234
235
236 if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
237 {
238 dupsCursor.after( value );
239 }
240
241 return;
242 }
243
244 clearValue();
245 containerTuple.setKey( null );
246 containerTuple.setValue( null );
247 }
248
249
250
251
252
253 public void before( Tuple<K, V> element ) throws LdapException, CursorException
254 {
255 beforeValue( element.getKey(), element.getValue() );
256 }
257
258
259
260
261
262 public void after( Tuple<K, V> element ) throws LdapException, CursorException
263 {
264 afterValue( element.getKey(), element.getValue() );
265 }
266
267
268
269
270
271 public void beforeFirst() throws LdapException, CursorException
272 {
273 checkNotClosed();
274 clearValue();
275 containerCursor.beforeFirst();
276 containerTuple.setKey( null );
277 containerTuple.setValue( null );
278 dupsCursor = null;
279 }
280
281
282
283
284
285 public void afterLast() throws LdapException, CursorException
286 {
287 checkNotClosed();
288 clearValue();
289 containerCursor.afterLast();
290 containerTuple.setKey( null );
291 containerTuple.setValue( null );
292 dupsCursor = null;
293 }
294
295
296
297
298
299 public boolean first() throws LdapException, CursorException
300 {
301 checkNotClosed();
302 clearValue();
303 dupsCursor = null;
304
305 if ( containerCursor.first() )
306 {
307 containerTuple.setBoth( containerCursor.get() );
308 DupsContainer<V> values = containerTuple.getValue();
309
310 if ( containerTuple.getValue().isArrayTree() )
311 {
312 dupsCursor = new ArrayTreeCursor<>( values.getArrayTree() );
313 }
314 else
315 {
316 try
317 {
318 BTree bt = table.getBTree( values.getBTreeRedirect() );
319 dupsCursor = new KeyBTreeCursor<>( bt, table.getValueComparator() );
320 }
321 catch ( IOException e )
322 {
323 throw new CursorException( e );
324 }
325 }
326
327
328
329
330
331
332 dupsCursor.first();
333 valueAvailable = true;
334 returnedTuple.setKey( containerTuple.getKey() );
335 returnedTuple.setValue( dupsCursor.get() );
336
337 return true;
338 }
339
340 return false;
341 }
342
343
344
345
346
347 public boolean last() throws LdapException, CursorException
348 {
349 checkNotClosed();
350 clearValue();
351 dupsCursor = null;
352
353 if ( containerCursor.last() )
354 {
355 containerTuple.setBoth( containerCursor.get() );
356 DupsContainer<V> values = containerTuple.getValue();
357
358 if ( values.isArrayTree() )
359 {
360 ArrayTree<V> set = values.getArrayTree();
361 dupsCursor = new ArrayTreeCursor<>( set );
362 }
363 else
364 {
365 try
366 {
367 BTree tree = table.getBTree( values.getBTreeRedirect() );
368 dupsCursor = new KeyBTreeCursor<>( tree, table.getValueComparator() );
369 }
370 catch ( IOException e )
371 {
372 throw new CursorException( e );
373 }
374 }
375
376
377
378
379
380
381 dupsCursor.last();
382 valueAvailable = true;
383 returnedTuple.setKey( containerTuple.getKey() );
384 returnedTuple.setValue( dupsCursor.get() );
385
386 return true;
387 }
388
389 return false;
390 }
391
392
393 private void clearValue()
394 {
395 returnedTuple.setKey( null );
396 returnedTuple.setValue( null );
397 valueAvailable = false;
398 }
399
400
401
402
403
404 public boolean previous() throws LdapException, CursorException
405 {
406 checkNotClosed();
407
408
409
410
411 if ( null == dupsCursor || !dupsCursor.previous() )
412 {
413 if ( dupsCursor != null )
414 {
415 try
416 {
417 dupsCursor.close();
418 }
419 catch ( IOException ioe )
420 {
421 throw new LdapException( ioe.getMessage(), ioe );
422 }
423 }
424
425
426
427
428
429
430 if ( containerCursor.previous() )
431 {
432 containerTuple.setBoth( containerCursor.get() );
433 DupsContainer<V> values = containerTuple.getValue();
434
435 if ( values.isArrayTree() )
436 {
437 ArrayTree<V> set = values.getArrayTree();
438 dupsCursor = new ArrayTreeCursor<>( set );
439 }
440 else
441 {
442 try
443 {
444 BTree tree = table.getBTree( values.getBTreeRedirect() );
445 dupsCursor = new KeyBTreeCursor<>( tree, table.getValueComparator() );
446 }
447 catch ( IOException e )
448 {
449 throw new CursorException( e );
450 }
451 }
452
453
454
455
456
457
458
459 dupsCursor.afterLast();
460 dupsCursor.previous();
461 }
462 else
463 {
464 dupsCursor = null;
465 return false;
466 }
467 }
468
469 returnedTuple.setKey( containerTuple.getKey() );
470 returnedTuple.setValue( dupsCursor.get() );
471
472 valueAvailable = true;
473 return true;
474 }
475
476
477
478
479
480 public boolean next() throws LdapException, CursorException
481 {
482 checkNotClosed();
483
484
485
486
487 if ( ( null == dupsCursor ) || !dupsCursor.next() )
488 {
489 if ( dupsCursor != null )
490 {
491 try
492 {
493 dupsCursor.close();
494 }
495 catch ( IOException ioe )
496 {
497 throw new LdapException( ioe.getMessage(), ioe );
498 }
499 }
500
501
502
503
504
505 if ( containerCursor.next() )
506 {
507 containerTuple.setBoth( containerCursor.get() );
508 DupsContainer<V> values = containerTuple.getValue();
509
510 if ( values.isArrayTree() )
511 {
512 ArrayTree<V> set = values.getArrayTree();
513 dupsCursor = new ArrayTreeCursor<>( set );
514 }
515 else
516 {
517 try
518 {
519 BTree tree = table.getBTree( values.getBTreeRedirect() );
520 dupsCursor = new KeyBTreeCursor<>( tree, table.getValueComparator() );
521 }
522 catch ( IOException e )
523 {
524 throw new CursorException( e );
525 }
526 }
527
528
529
530
531
532
533
534 dupsCursor.beforeFirst();
535 dupsCursor.next();
536 }
537 else
538 {
539 dupsCursor = null;
540 return false;
541 }
542 }
543
544
545
546
547
548
549
550
551 returnedTuple.setKey( containerTuple.getKey() );
552 returnedTuple.setValue( dupsCursor.get() );
553
554 valueAvailable = true;
555 return true;
556 }
557
558
559
560
561
562 public Tuple<K, V> get() throws CursorException
563 {
564 checkNotClosed();
565
566 if ( !valueAvailable )
567 {
568 throw new InvalidCursorPositionException();
569 }
570
571 return returnedTuple;
572 }
573
574
575
576
577
578 @Override
579 public void close() throws IOException
580 {
581 if ( IS_DEBUG )
582 {
583 LOG_CURSOR.debug( "Closing DupsCursor {}", this );
584 }
585
586 super.close();
587 containerCursor.close();
588
589 if ( dupsCursor != null )
590 {
591 dupsCursor.close();
592 }
593 }
594
595
596
597
598
599 @Override
600 public void close( Exception cause ) throws IOException
601 {
602 if ( IS_DEBUG )
603 {
604 LOG_CURSOR.debug( "Closing DupsCursor {}", this );
605 }
606
607 super.close( cause );
608 containerCursor.close( cause );
609
610 if ( dupsCursor != null )
611 {
612 dupsCursor.close( cause );
613 }
614 }
615 }