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.search.cursor;
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.Cursor;
27 import org.apache.directory.api.ldap.model.cursor.CursorException;
28 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
29 import org.apache.directory.api.ldap.model.exception.LdapException;
30 import org.apache.directory.api.ldap.model.schema.AttributeType;
31 import org.apache.directory.server.core.api.partition.PartitionTxn;
32 import org.apache.directory.server.i18n.I18n;
33 import org.apache.directory.server.xdbm.AbstractIndexCursor;
34 import org.apache.directory.server.xdbm.Index;
35 import org.apache.directory.server.xdbm.IndexEntry;
36 import org.apache.directory.server.xdbm.IndexNotFoundException;
37 import org.apache.directory.server.xdbm.Store;
38 import org.apache.directory.server.xdbm.search.evaluator.GreaterEqEvaluator;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47
48
49
50
51
52 public class GreaterEqCursor<V> extends AbstractIndexCursor<V>
53 {
54
55 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
56
57
58 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
59
60 private static final String UNSUPPORTED_MSG = "GreaterEqCursors only support positioning by element when a user index exists on the asserted attribute.";
61
62
63 private final GreaterEqEvaluator<V> greaterEqEvaluator;
64
65
66 private final Cursor<IndexEntry<V, String>> userIdxCursor;
67
68
69 private final Cursor<IndexEntry<String, String>> uuidIdxCursor;
70
71
72
73
74
75
76 private IndexEntry<String, String> uuidCandidate;
77
78
79
80
81
82
83
84
85
86
87
88 @SuppressWarnings("unchecked")
89 public GreaterEqCursor( PartitionTxn partitionTxn, Store store, GreaterEqEvaluator<V> greaterEqEvaluator )
90 throws LdapException, IndexNotFoundException
91 {
92 if ( IS_DEBUG )
93 {
94 LOG_CURSOR.debug( "Creating GreaterEqCursor {}", this );
95 }
96
97 this.greaterEqEvaluator = greaterEqEvaluator;
98 this.partitionTxn = partitionTxn;
99
100 AttributeType attributeType = greaterEqEvaluator.getExpression().getAttributeType();
101
102 if ( store.hasIndexOn( attributeType ) )
103 {
104 userIdxCursor = ( ( Index<V, String> ) store.getIndex( attributeType ) ).forwardCursor( partitionTxn );
105 uuidIdxCursor = null;
106 }
107 else
108 {
109 uuidIdxCursor = new AllEntriesCursor( partitionTxn, store );
110 userIdxCursor = null;
111 }
112 }
113
114
115
116
117
118 protected String getUnsupportedMessage()
119 {
120 return UNSUPPORTED_MSG;
121 }
122
123
124
125
126
127 @Override
128 public void before( IndexEntry<V, String> element ) throws LdapException, CursorException
129 {
130 checkNotClosed();
131
132 if ( userIdxCursor != null )
133 {
134
135
136
137
138
139
140
141
142 if ( greaterEqEvaluator.getComparator().compare( element.getKey(),
143 greaterEqEvaluator.getExpression().getValue().getString() ) <= 0 )
144 {
145 beforeFirst();
146 return;
147 }
148
149 userIdxCursor.before( element );
150 setAvailable( false );
151 }
152 else
153 {
154 super.before( element );
155 }
156 }
157
158
159
160
161
162 @Override
163 public void after( IndexEntry<V, String> element ) throws LdapException, CursorException
164 {
165 checkNotClosed();
166
167 if ( userIdxCursor != null )
168 {
169 int comparedValue = greaterEqEvaluator.getComparator().compare( element.getKey(),
170 greaterEqEvaluator.getExpression().getValue().getString() );
171
172
173
174
175
176
177
178
179
180 if ( comparedValue == 0 )
181 {
182 userIdxCursor.after( element );
183 setAvailable( false );
184
185 return;
186 }
187
188 if ( comparedValue < 0 )
189 {
190 beforeFirst();
191
192 return;
193 }
194
195
196 userIdxCursor.after( element );
197 setAvailable( false );
198 }
199 else
200 {
201 super.after( element );
202 }
203 }
204
205
206
207
208
209 @SuppressWarnings("unchecked")
210 public void beforeFirst() throws LdapException, CursorException
211 {
212 checkNotClosed();
213
214 if ( userIdxCursor != null )
215 {
216 IndexEntry<V, String> advanceTo = new IndexEntry<>();
217 String normalizedNode = greaterEqEvaluator.getNormalizer().normalize( greaterEqEvaluator.getExpression().getValue().getString() );
218 advanceTo.setKey( ( V ) normalizedNode );
219 userIdxCursor.before( advanceTo );
220 }
221 else
222 {
223 uuidIdxCursor.beforeFirst();
224 uuidCandidate = null;
225 }
226
227 setAvailable( false );
228 }
229
230
231
232
233
234 public void afterLast() throws LdapException, CursorException
235 {
236 checkNotClosed();
237
238 if ( userIdxCursor != null )
239 {
240 userIdxCursor.afterLast();
241 }
242 else
243 {
244 uuidIdxCursor.afterLast();
245 uuidCandidate = null;
246 }
247
248 setAvailable( false );
249 }
250
251
252
253
254
255 public boolean first() throws LdapException, CursorException
256 {
257 beforeFirst();
258
259 return next();
260 }
261
262
263
264
265
266 public boolean last() throws LdapException, CursorException
267 {
268 afterLast();
269
270 return previous();
271 }
272
273
274
275
276
277 @Override
278 public boolean previous() throws LdapException, CursorException
279 {
280 checkNotClosed();
281
282 if ( userIdxCursor != null )
283 {
284
285
286
287
288 while ( userIdxCursor.previous() )
289 {
290 checkNotClosed();
291 IndexEntry<?, String> candidate = userIdxCursor.get();
292
293 if ( greaterEqEvaluator.getComparator().compare( candidate.getKey(),
294 greaterEqEvaluator.getExpression().getValue().getString() ) >= 0 )
295 {
296 return setAvailable( true );
297 }
298 }
299
300 return setAvailable( false );
301 }
302
303 while ( uuidIdxCursor.previous() )
304 {
305 checkNotClosed();
306 uuidCandidate = uuidIdxCursor.get();
307
308 if ( greaterEqEvaluator.evaluate( partitionTxn, uuidCandidate ) )
309 {
310 return setAvailable( true );
311 }
312 }
313
314 return setAvailable( false );
315 }
316
317
318
319
320
321 @Override
322 public boolean next() throws LdapException, CursorException
323 {
324 checkNotClosed();
325
326 if ( userIdxCursor != null )
327 {
328
329
330
331
332 return setAvailable( userIdxCursor.next() );
333 }
334
335 while ( uuidIdxCursor.next() )
336 {
337 checkNotClosed();
338 uuidCandidate = uuidIdxCursor.get();
339
340 if ( greaterEqEvaluator.evaluate( partitionTxn, uuidCandidate ) )
341 {
342 return setAvailable( true );
343 }
344 }
345
346 return setAvailable( false );
347 }
348
349
350
351
352
353 public IndexEntry<V, String> get() throws CursorException
354 {
355 checkNotClosed();
356
357 if ( userIdxCursor != null )
358 {
359 if ( available() )
360 {
361 return userIdxCursor.get();
362 }
363
364 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) );
365 }
366
367 if ( available() )
368 {
369 return ( IndexEntry<V, String> ) uuidCandidate;
370 }
371
372 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) );
373 }
374
375
376
377
378
379 @Override
380 public void close() throws IOException
381 {
382 if ( IS_DEBUG )
383 {
384 LOG_CURSOR.debug( "Closing GreaterEqCursor {}", this );
385 }
386
387 super.close();
388
389 if ( userIdxCursor != null )
390 {
391 userIdxCursor.close();
392 }
393 else
394 {
395 uuidIdxCursor.close();
396 uuidCandidate = null;
397 }
398 }
399
400
401
402
403
404 @Override
405 public void close( Exception cause ) throws IOException
406 {
407 if ( IS_DEBUG )
408 {
409 LOG_CURSOR.debug( "Closing GreaterEqCursor {}", this );
410 }
411
412 super.close( cause );
413
414 if ( userIdxCursor != null )
415 {
416 userIdxCursor.close( cause );
417 }
418 else
419 {
420 uuidIdxCursor.close( cause );
421 uuidCandidate = null;
422 }
423 }
424
425
426
427
428
429 @Override
430 public String toString( String tabs )
431 {
432 StringBuilder sb = new StringBuilder();
433
434 sb.append( tabs ).append( "GreaterEqCursor (" );
435
436 if ( available() )
437 {
438 sb.append( "available)" );
439 }
440 else
441 {
442 sb.append( "absent)" );
443 }
444
445 sb.append( "#candidate<" ).append( uuidCandidate ).append( ">:\n" );
446
447 sb.append( tabs + " >>" ).append( greaterEqEvaluator ).append( '\n' );
448
449 if ( userIdxCursor != null )
450 {
451 sb.append( tabs + " <user>\n" );
452 sb.append( userIdxCursor.toString( tabs + " " ) );
453 }
454
455 if ( uuidIdxCursor != null )
456 {
457 sb.append( tabs + " <uuid>\n" );
458 sb.append( uuidIdxCursor.toString( tabs + " " ) );
459 }
460
461 return sb.toString();
462 }
463
464
465
466
467
468 public String toString()
469 {
470 return toString( "" );
471 }
472 }