1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.directory.server.core.partition.impl.btree.jdbm;
20
21
22 import java.io.IOException;
23 import java.util.Comparator;
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 public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
47 {
48
49 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
50
51
52 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
53
54 private final Comparator<V> comparator;
55 private final BTree btree;
56 private final K key;
57
58 private jdbm.helper.Tuple<K, V> valueTuple = new jdbm.helper.Tuple<>();
59 private Tuple<K, V> returnedTuple = new Tuple<>();
60 private TupleBrowser<K, V> browser;
61 private boolean valueAvailable;
62
63
64
65
66
67
68
69
70
71
72 public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws IOException
73 {
74 if ( IS_DEBUG )
75 {
76 LOG_CURSOR.debug( "Creating KeyTupleBTreeCursor {}", this );
77 }
78
79 this.key = key;
80 this.btree = btree;
81 this.comparator = comparator;
82 this.browser = btree.browse();
83 }
84
85
86 private void clearValue()
87 {
88 returnedTuple.setKey( key );
89 returnedTuple.setValue( null );
90 valueAvailable = false;
91 }
92
93
94
95
96
97 public boolean available()
98 {
99 return valueAvailable;
100 }
101
102
103 public void beforeKey( K key ) throws Exception
104 {
105 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
106 }
107
108
109
110
111
112 public void afterKey( K key ) throws Exception
113 {
114 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
115 }
116
117
118
119
120
121 public void beforeValue( K key, V value ) throws Exception
122 {
123 checkNotClosed();
124 if ( key != null && !key.equals( this.key ) )
125 {
126 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
127 }
128
129 browser = btree.browse( value );
130 clearValue();
131 }
132
133
134
135
136
137 @SuppressWarnings("unchecked")
138 public void afterValue( K key, V value ) throws CursorException
139 {
140 if ( key != null && !key.equals( this.key ) )
141 {
142 throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
143 }
144
145 try
146 {
147 browser = btree.browse( value );
148
149
150
151
152
153
154
155
156 while ( browser.getNext( valueTuple ) )
157 {
158 checkNotClosed();
159
160 V next = ( V ) valueTuple.getKey();
161
162 int nextCompared = comparator.compare( next, value );
163
164 if ( nextCompared > 0 )
165 {
166
167
168
169
170
171
172 if ( !browser.getPrevious( valueTuple ) )
173 {
174 browser = btree.browse( this.key );
175 }
176
177 clearValue();
178
179 return;
180 }
181 }
182
183 clearValue();
184 }
185 catch ( IOException e )
186 {
187 throw new CursorException( e );
188 }
189 }
190
191
192
193
194
195
196
197
198
199
200
201 public void before( Tuple<K, V> element ) throws LdapException, CursorException
202 {
203 checkNotClosed();
204 try
205 {
206 browser = btree.browse( element.getValue() );
207 clearValue();
208 }
209 catch ( IOException e )
210 {
211 throw new CursorException( e );
212 }
213 }
214
215
216
217
218
219 public void after( Tuple<K, V> element ) throws CursorException
220 {
221 afterValue( key, element.getValue() );
222 }
223
224
225
226
227
228 public void beforeFirst() throws LdapException, CursorException
229 {
230 checkNotClosed();
231 try
232 {
233 browser = btree.browse();
234 clearValue();
235 }
236 catch ( IOException e )
237 {
238 throw new CursorException( e );
239 }
240 }
241
242
243
244
245
246 public void afterLast() throws LdapException, CursorException
247 {
248 checkNotClosed();
249 try
250 {
251 browser = btree.browse( null );
252 }
253 catch ( IOException e )
254 {
255 throw new CursorException( e );
256 }
257 }
258
259
260
261
262
263 public boolean first() throws LdapException, CursorException
264 {
265 beforeFirst();
266
267 return next();
268 }
269
270
271
272
273
274 public boolean last() throws LdapException, CursorException
275 {
276 afterLast();
277
278 return previous();
279 }
280
281
282
283
284
285 @SuppressWarnings("unchecked")
286 public boolean previous() throws LdapException, CursorException
287 {
288 checkNotClosed();
289
290 try
291 {
292 if ( browser.getPrevious( valueTuple ) )
293 {
294
295 if ( ( returnedTuple.getValue() != null )
296 && ( comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 ) )
297 {
298 browser.getPrevious( valueTuple );
299 }
300 returnedTuple.setKey( key );
301 returnedTuple.setValue( ( V ) valueTuple.getKey() );
302
303 valueAvailable = true;
304 return true;
305 }
306 else
307 {
308 clearValue();
309
310 return false;
311 }
312 }
313 catch ( IOException e )
314 {
315 throw new CursorException( e );
316 }
317 }
318
319
320
321
322
323 @SuppressWarnings("unchecked")
324 public boolean next() throws LdapException, CursorException
325 {
326 checkNotClosed();
327
328 try
329 {
330 if ( browser.getNext( valueTuple ) )
331 {
332
333 if ( returnedTuple.getValue() != null
334 && comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
335 {
336 browser.getNext( valueTuple );
337 }
338
339 returnedTuple.setKey( key );
340 returnedTuple.setValue( ( V ) valueTuple.getKey() );
341
342 valueAvailable = true;
343 return true;
344 }
345 else
346 {
347 clearValue();
348
349 return false;
350 }
351 }
352 catch ( IOException e )
353 {
354 throw new CursorException( e );
355 }
356 }
357
358
359
360
361
362 public Tuple<K, V> get() throws CursorException
363 {
364 checkNotClosed();
365
366 if ( valueAvailable )
367 {
368 return returnedTuple;
369 }
370
371 throw new InvalidCursorPositionException();
372 }
373
374
375
376
377
378 @Override
379 public void close() throws IOException
380 {
381 if ( IS_DEBUG )
382 {
383 LOG_CURSOR.debug( "Closing KeyTupleBTreeCursor {}", this );
384 }
385
386 super.close();
387 }
388
389
390
391
392
393 @Override
394 public void close( Exception cause ) throws IOException
395 {
396 if ( IS_DEBUG )
397 {
398 LOG_CURSOR.debug( "Closing KeyTupleBTreeCursor {}", this );
399 }
400
401 super.close( cause );
402 }
403 }