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 import jdbm.helper.TupleBrowser;
27
28 import org.apache.directory.api.ldap.model.constants.Loggers;
29 import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
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.i18n.I18n;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41
42
43
44
45
46
47 public class DupsContainerCursor<K, V> extends AbstractCursor<Tuple<K, DupsContainer<V>>>
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 private final JdbmTable<K, V> table;
57
58
59 private jdbm.helper.Tuple<K, V> jdbmTuple = new jdbm.helper.Tuple<>();
60
61 private Tuple<K, DupsContainer<V>> returnedTuple = new Tuple<>();
62
63
64 private TupleBrowser<K, V> browser;
65
66
67 private boolean valueAvailable;
68
69
70 private Boolean forwardDirection;
71
72
73
74
75
76
77
78 public DupsContainerCursor( JdbmTable<K, V> table )
79 {
80 if ( IS_DEBUG )
81 {
82 LOG_CURSOR.debug( "Creating DupsContainerCursor {}", this );
83 }
84
85 if ( !table.isDupsEnabled() )
86 {
87 throw new IllegalStateException( I18n.err( I18n.ERR_572 ) );
88 }
89
90 this.table = table;
91 }
92
93
94
95
96
97 private void clearValue()
98 {
99 returnedTuple.setKey( null );
100 returnedTuple.setValue( null );
101 jdbmTuple.setKey( null );
102 jdbmTuple.setValue( null );
103 valueAvailable = false;
104 }
105
106
107
108
109
110 public boolean available()
111 {
112 return valueAvailable;
113 }
114
115
116
117
118
119 @SuppressWarnings("unchecked")
120 public void beforeKey( K key ) throws CursorException
121 {
122 checkNotClosed();
123 try
124 {
125 browser = ( ( BTree<K, V> ) table.getBTree() ).browse( key );
126 forwardDirection = null;
127 clearValue();
128 }
129 catch ( IOException e )
130 {
131 throw new CursorException( e );
132 }
133 }
134
135
136
137
138
139 @SuppressWarnings("unchecked")
140 public void afterKey( K key ) throws CursorException
141 {
142 checkNotClosed();
143
144 try
145 {
146 browser = ( ( BTree<K, V> ) table.getBTree() ).browse( key );
147 forwardDirection = null;
148
149
150
151
152
153
154
155
156 while ( browser.getNext( jdbmTuple ) )
157 {
158 checkNotClosed();
159 K next = jdbmTuple.getKey();
160
161 int nextCompared = table.getKeyComparator().compare( next, key );
162
163 if ( nextCompared > 0 )
164 {
165 browser.getPrevious( jdbmTuple );
166
167
168
169
170 browser.getPrevious( jdbmTuple );
171 forwardDirection = false;
172 clearValue();
173
174 return;
175 }
176 }
177
178 clearValue();
179 }
180 catch ( IOException e )
181 {
182 throw new CursorException( e );
183 }
184 }
185
186
187
188
189
190 public void beforeValue( K key, DupsContainer<V> value ) throws Exception
191 {
192 throw new UnsupportedOperationException( I18n.err( I18n.ERR_573 ) );
193 }
194
195
196
197
198
199 public void afterValue( K key, DupsContainer<V> value ) throws Exception
200 {
201 throw new UnsupportedOperationException( I18n.err( I18n.ERR_573 ) );
202 }
203
204
205
206
207
208
209
210
211
212 public void before( Tuple<K, DupsContainer<V>> element ) throws LdapException, CursorException
213 {
214 beforeKey( element.getKey() );
215 }
216
217
218
219
220
221 public void after( Tuple<K, DupsContainer<V>> element ) throws CursorException
222 {
223 afterKey( element.getKey() );
224 }
225
226
227
228
229
230 @SuppressWarnings("unchecked")
231 public void beforeFirst() throws LdapException, CursorException
232 {
233 checkNotClosed();
234 try
235 {
236 browser = table.getBTree().browse();
237 forwardDirection = null;
238 clearValue();
239 }
240 catch ( IOException e )
241 {
242 throw new CursorException( e );
243 }
244 }
245
246
247
248
249
250 @SuppressWarnings("unchecked")
251 public void afterLast() throws LdapException, CursorException
252 {
253 checkNotClosed();
254 try
255 {
256 browser = table.getBTree().browse( null );
257 forwardDirection = null;
258 clearValue();
259 }
260 catch ( IOException e )
261 {
262 throw new CursorException( e );
263 }
264 }
265
266
267
268
269
270 public boolean first() throws LdapException, CursorException
271 {
272 beforeFirst();
273
274 return next();
275 }
276
277
278
279
280
281 public boolean last() throws LdapException, CursorException
282 {
283 afterLast();
284
285 return previous();
286 }
287
288
289
290
291
292 public boolean previous() throws LdapException, CursorException
293 {
294 checkNotClosed();
295
296 if ( browser == null )
297 {
298 afterLast();
299 }
300
301 try
302 {
303 boolean advanceSuccess = browser.getPrevious( jdbmTuple );
304
305
306
307 if ( forwardDirection == null )
308 {
309 if ( advanceSuccess )
310 {
311 forwardDirection = false;
312 }
313 else
314 {
315 clearValue();
316
317 return false;
318 }
319 }
320 else if ( forwardDirection )
321 {
322 advanceSuccess = browser.getPrevious( jdbmTuple );
323 forwardDirection = false;
324 }
325
326 valueAvailable = advanceSuccess;
327
328 if ( valueAvailable )
329 {
330 returnedTuple.setKey( jdbmTuple.getKey() );
331 returnedTuple.setValue( table.getDupsContainer( ( byte[] ) jdbmTuple.getValue() ) );
332 }
333 else
334 {
335 clearValue();
336 }
337
338 return valueAvailable;
339 }
340 catch ( IOException e )
341 {
342 throw new CursorException( e );
343 }
344 }
345
346
347
348
349
350 public boolean next() throws LdapException, CursorException
351 {
352 checkNotClosed();
353
354 if ( browser == null )
355 {
356
357 beforeFirst();
358 }
359
360 try
361 {
362
363 boolean advanceSuccess = browser.getNext( jdbmTuple );
364
365
366
367 if ( forwardDirection == null )
368 {
369 if ( advanceSuccess )
370 {
371 forwardDirection = true;
372 }
373 else
374 {
375 clearValue();
376
377
378 return false;
379 }
380 }
381
382 if ( !forwardDirection )
383 {
384 advanceSuccess = browser.getNext( jdbmTuple );
385 forwardDirection = true;
386 }
387
388 valueAvailable = advanceSuccess;
389
390 if ( valueAvailable )
391 {
392
393 returnedTuple.setKey( jdbmTuple.getKey() );
394 returnedTuple.setValue( table.getDupsContainer( ( byte[] ) jdbmTuple.getValue() ) );
395 }
396 else
397 {
398 clearValue();
399 }
400
401 return valueAvailable;
402 }
403 catch ( IOException e )
404 {
405 throw new CursorException( e );
406 }
407 }
408
409
410
411
412
413 public Tuple<K, DupsContainer<V>> get() throws CursorException
414 {
415 checkNotClosed();
416
417 if ( valueAvailable )
418 {
419 return returnedTuple;
420 }
421
422 throw new InvalidCursorPositionException();
423 }
424
425
426
427
428
429 @Override
430 public void close() throws IOException
431 {
432 if ( IS_DEBUG )
433 {
434 LOG_CURSOR.debug( "Closing DupsContainerCursor {}", this );
435 }
436
437 super.close();
438 }
439
440
441
442
443
444 @Override
445 public void close( Exception cause ) throws IOException
446 {
447 if ( IS_DEBUG )
448 {
449 LOG_CURSOR.debug( "Closing DupsContainerCursor {}", this );
450 }
451
452 super.close( cause );
453 }
454 }