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.LessEqEvaluator;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47
48
49
50
51
52 public class LessEqCursor<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 = I18n.err( I18n.ERR_716 );
61
62
63 private final LessEqEvaluator<V> lessEqEvaluator;
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 LessEqCursor( PartitionTxn partitionTxn, Store store, LessEqEvaluator<V> lessEqEvaluator )
90 throws LdapException, IndexNotFoundException
91 {
92 if ( IS_DEBUG )
93 {
94 LOG_CURSOR.debug( "Creating LessEqCursor {}", this );
95 }
96
97 this.lessEqEvaluator = lessEqEvaluator;
98 this.partitionTxn = partitionTxn;
99
100 AttributeType attributeType = lessEqEvaluator.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
143
144
145
146
147 int compareValue = lessEqEvaluator.getComparator().compare( element.getKey(),
148 lessEqEvaluator.getExpression().getValue().getString() );
149
150 if ( compareValue > 0 )
151 {
152 afterLast();
153 return;
154 }
155 else if ( compareValue == 0 )
156 {
157 last();
158 previous();
159 setAvailable( false );
160 return;
161 }
162
163 userIdxCursor.before( element );
164 setAvailable( false );
165 }
166 else
167 {
168 super.before( element );
169 }
170 }
171
172
173
174
175
176 @Override
177 public void after( IndexEntry<V, String> element ) throws LdapException, CursorException
178 {
179 checkNotClosed();
180
181 if ( userIdxCursor != null )
182 {
183 int comparedValue = lessEqEvaluator.getComparator().compare( element.getKey(),
184 lessEqEvaluator.getExpression().getValue().getString() );
185
186
187
188
189
190
191
192
193
194
195
196
197 if ( comparedValue >= 0 )
198 {
199 afterLast();
200 return;
201 }
202
203
204 userIdxCursor.after( element );
205 setAvailable( false );
206 }
207 else
208 {
209 super.after( element );
210 }
211 }
212
213
214
215
216
217 public void beforeFirst() throws LdapException, CursorException
218 {
219 checkNotClosed();
220
221 if ( userIdxCursor != null )
222 {
223 userIdxCursor.beforeFirst();
224 }
225 else
226 {
227 uuidIdxCursor.beforeFirst();
228 uuidCandidate = null;
229 }
230
231 setAvailable( false );
232 }
233
234
235
236
237
238 public void afterLast() throws LdapException, CursorException
239 {
240 checkNotClosed();
241
242 if ( userIdxCursor != null )
243 {
244 IndexEntry<V, String> advanceTo = new IndexEntry<>();
245
246 String normalizedKey = lessEqEvaluator.getAttributeType().getEquality().getNormalizer().normalize(
247 lessEqEvaluator.getExpression().getValue().getString() );
248
249 advanceTo.setKey( ( V ) normalizedKey );
250 userIdxCursor.after( advanceTo );
251 }
252 else
253 {
254 uuidIdxCursor.afterLast();
255 uuidCandidate = null;
256 }
257
258 setAvailable( false );
259 }
260
261
262
263
264
265 public boolean first() throws LdapException, CursorException
266 {
267 beforeFirst();
268 return next();
269 }
270
271
272
273
274
275 public boolean last() throws LdapException, CursorException
276 {
277 afterLast();
278
279 return previous();
280 }
281
282
283
284
285
286 @Override
287 public boolean previous() throws LdapException, CursorException
288 {
289 checkNotClosed();
290
291 if ( userIdxCursor != null )
292 {
293
294
295
296
297
298 return setAvailable( userIdxCursor.previous() );
299 }
300
301 while ( uuidIdxCursor.previous() )
302 {
303 checkNotClosed();
304 uuidCandidate = uuidIdxCursor.get();
305
306 if ( lessEqEvaluator.evaluate( partitionTxn, uuidCandidate ) )
307 {
308 return setAvailable( true );
309 }
310 else
311 {
312 uuidCandidate = null;
313 }
314 }
315
316 return setAvailable( false );
317 }
318
319
320
321
322
323 @Override
324 public boolean next() throws LdapException, CursorException
325 {
326 checkNotClosed();
327
328 if ( userIdxCursor != null )
329 {
330
331
332
333
334
335
336 while ( userIdxCursor.next() )
337 {
338 checkNotClosed();
339 IndexEntry<?, String> candidate = userIdxCursor.get();
340
341 if ( lessEqEvaluator.getComparator().compare( candidate.getKey(),
342 lessEqEvaluator.getExpression().getValue().getString() ) <= 0 )
343 {
344 return setAvailable( true );
345 }
346 }
347
348 return setAvailable( false );
349 }
350
351 while ( uuidIdxCursor.next() )
352 {
353 checkNotClosed();
354 uuidCandidate = uuidIdxCursor.get();
355
356 if ( lessEqEvaluator.evaluate( partitionTxn, uuidCandidate ) )
357 {
358 return setAvailable( true );
359 }
360 else
361 {
362 uuidCandidate = null;
363 }
364 }
365
366 return setAvailable( false );
367 }
368
369
370
371
372
373 public IndexEntry<V, String> get() throws CursorException
374 {
375 checkNotClosed();
376
377 if ( userIdxCursor != null )
378 {
379 if ( available() )
380 {
381 return userIdxCursor.get();
382 }
383
384 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) );
385 }
386
387 if ( available() )
388 {
389 return ( IndexEntry<V, String> ) uuidCandidate;
390 }
391
392 throw new InvalidCursorPositionException( I18n.err( I18n.ERR_708 ) );
393 }
394
395
396
397
398
399 @Override
400 public void close() throws IOException
401 {
402 if ( IS_DEBUG )
403 {
404 LOG_CURSOR.debug( "Closing LessEqCursor {}", this );
405 }
406
407 super.close();
408
409 if ( userIdxCursor != null )
410 {
411 userIdxCursor.close();
412 }
413 else
414 {
415 uuidIdxCursor.close();
416 uuidCandidate = null;
417 }
418 }
419
420
421
422
423
424 @Override
425 public void close( Exception cause ) throws IOException
426 {
427 LOG_CURSOR.debug( "Closing LessEqCursor {}", this );
428 super.close( cause );
429
430 if ( userIdxCursor != null )
431 {
432 userIdxCursor.close( cause );
433 }
434 else
435 {
436 uuidIdxCursor.close( cause );
437 uuidCandidate = null;
438 }
439 }
440
441
442
443
444
445 @Override
446 public String toString( String tabs )
447 {
448 StringBuilder sb = new StringBuilder();
449
450 sb.append( tabs ).append( "LessEqCursor (" );
451
452 if ( available() )
453 {
454 sb.append( "available)" );
455 }
456 else
457 {
458 sb.append( "absent)" );
459 }
460
461 sb.append( "#candidate<" ).append( uuidCandidate ).append( ">:\n" );
462
463 sb.append( tabs + " >>" ).append( lessEqEvaluator ).append( '\n' );
464
465 if ( userIdxCursor != null )
466 {
467 sb.append( tabs + " <user>\n" );
468 sb.append( userIdxCursor.toString( tabs + " " ) );
469 }
470
471 if ( uuidIdxCursor != null )
472 {
473 sb.append( tabs + " <uuid>\n" );
474 sb.append( uuidIdxCursor.toString( tabs + " " ) );
475 }
476
477 return sb.toString();
478 }
479
480
481
482
483
484 public String toString()
485 {
486 return toString( "" );
487 }
488 }