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