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.api.filtering;
20
21
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.directory.api.i18n.I18n;
27 import org.apache.directory.api.ldap.model.constants.Loggers;
28 import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
29 import org.apache.directory.api.ldap.model.cursor.ClosureMonitor;
30 import org.apache.directory.api.ldap.model.cursor.Cursor;
31 import org.apache.directory.api.ldap.model.cursor.CursorException;
32 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
33 import org.apache.directory.api.ldap.model.entry.Entry;
34 import org.apache.directory.api.ldap.model.exception.LdapException;
35 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42
43
44
45
46
47
48
49
50 public class CursorList extends AbstractCursor<Entry> implements EntryFilteringCursor
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 List<EntryFilteringCursor> list;
60
61
62 private final int start;
63
64
65 private final int end;
66
67
68 private final int listSize;
69
70
71 private int index;
72
73
74 private EntryFilteringCursor currentCursor;
75
76
77 private SearchOperationContext searchContext;
78
79
80 private boolean closed;
81
82
83 private static final Logger LOG = LoggerFactory.getLogger( CursorList.class );
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 public CursorList( int start, List<EntryFilteringCursor> list, int end, SearchOperationContext searchContext )
100 {
101 if ( IS_DEBUG )
102 {
103 LOG_CURSOR.debug( "Creating CursorList {}", this );
104 }
105
106 if ( list != null )
107 {
108 this.list = list;
109 }
110 else
111 {
112 this.list = Collections.emptyList();
113 }
114
115 listSize = this.list.size();
116
117 if ( ( start < 0 ) || ( start > listSize ) )
118 {
119 throw new IllegalArgumentException( I18n.err( I18n.ERR_13105_START_INDEX_OUT_OF_RANGE, start ) );
120 }
121
122 if ( ( end < 0 ) || ( end > listSize ) )
123 {
124 throw new IllegalArgumentException( I18n.err( I18n.ERR_13106_END_INDEX_OUT_OF_RANGE, end ) );
125 }
126
127
128
129 if ( ( listSize > 0 ) && ( start >= end ) )
130 {
131 throw new IllegalArgumentException( I18n.err( I18n.ERR_13107_START_INDEX_ABOVE_END_INDEX, start, end ) );
132 }
133
134 this.start = start;
135 this.end = end;
136 this.searchContext = searchContext;
137 index = start;
138 currentCursor = this.list.get( index );
139 }
140
141
142
143
144
145
146
147
148
149 public CursorList( List<EntryFilteringCursor> list, SearchOperationContext searchContext )
150 {
151 this( 0, list, list.size(), searchContext );
152 }
153
154
155
156
157
158 public boolean available()
159 {
160 if ( ( index >= 0 ) && ( index < end ) )
161 {
162 return list.get( index ).available();
163 }
164
165 return false;
166 }
167
168
169
170
171
172 public void before( Entry element ) throws LdapException, CursorException
173 {
174 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13108_LIST_MAY_BE_SORTED ) );
175 }
176
177
178
179
180
181 public void after( Entry element ) throws LdapException, CursorException
182 {
183 throw new UnsupportedOperationException( I18n.err( I18n.ERR_13108_LIST_MAY_BE_SORTED ) );
184 }
185
186
187
188
189
190 public void beforeFirst() throws LdapException, CursorException
191 {
192 index = 0;
193 currentCursor = list.get( index );
194 currentCursor.beforeFirst();
195 }
196
197
198
199
200
201 public void afterLast() throws LdapException, CursorException
202 {
203 index = end - 1;
204 currentCursor = list.get( index );
205 currentCursor.afterLast();
206 }
207
208
209
210
211
212 public boolean first() throws LdapException, CursorException
213 {
214 if ( listSize > 0 )
215 {
216 index = start;
217
218 return list.get( index ).first();
219 }
220
221 return false;
222 }
223
224
225
226
227
228 public boolean last() throws LdapException, CursorException
229 {
230 if ( listSize > 0 )
231 {
232 index = end - 1;
233 currentCursor = list.get( index );
234
235 return currentCursor.last();
236 }
237
238 return false;
239 }
240
241
242
243
244
245 public boolean isFirst()
246 {
247 return ( listSize > 0 ) && ( index == start ) && list.get( index ).isFirst();
248 }
249
250
251
252
253
254 public boolean isLast()
255 {
256 return ( listSize > 0 ) && ( index == end - 1 ) && list.get( index ).isLast();
257 }
258
259
260
261
262
263 public boolean isAfterLast()
264 {
265 return ( index == end );
266 }
267
268
269
270
271
272 public boolean isBeforeFirst()
273 {
274 return index == -1;
275 }
276
277
278
279
280
281 public boolean previous() throws LdapException, CursorException
282 {
283 while ( index > -1 )
284 {
285 currentCursor = list.get( index );
286
287 if ( currentCursor.previous() )
288 {
289 return true;
290 }
291 else
292 {
293 index--;
294 }
295 }
296
297 return false;
298 }
299
300
301
302
303
304 public boolean next() throws LdapException, CursorException
305 {
306 if ( listSize > 0 )
307 {
308 if ( index == -1 )
309 {
310 index = start;
311 }
312
313 while ( index < end )
314 {
315 currentCursor = list.get( index );
316
317 if ( currentCursor.next() )
318 {
319 return true;
320 }
321 else
322 {
323 index++;
324 }
325 }
326 }
327
328 return false;
329 }
330
331
332
333
334
335 public Entry get() throws CursorException
336 {
337 if ( ( index < start ) || ( index >= end ) )
338 {
339 throw new CursorException( I18n.err( I18n.ERR_13109_CURSOR_NOT_POSITIONED ) );
340 }
341
342 if ( currentCursor.available() )
343 {
344 return currentCursor.get();
345 }
346
347 throw new InvalidCursorPositionException();
348 }
349
350
351
352
353
354 public boolean addEntryFilter( EntryFilter filter )
355 {
356 for ( EntryFilteringCursor efc : list )
357 {
358 efc.addEntryFilter( filter );
359 }
360
361
362 return true;
363 }
364
365
366
367
368
369 public List<EntryFilter> getEntryFilters()
370 {
371 throw new UnsupportedOperationException( "CursorList doesn't support this operation" );
372 }
373
374
375
376
377
378 public SearchOperationContext getOperationContext()
379 {
380 return searchContext;
381 }
382
383
384 public boolean isAbandoned()
385 {
386 return searchContext.isAbandoned();
387 }
388
389
390 public void setAbandoned( boolean abandoned )
391 {
392 searchContext.setAbandoned( abandoned );
393
394 if ( abandoned )
395 {
396 LOG.info( "Cursor has been abandoned." );
397 }
398 }
399
400
401
402
403
404 public void close()
405 {
406 if ( IS_DEBUG )
407 {
408 LOG_CURSOR.debug( "Closing CursorList {}", this );
409 }
410
411 close( null );
412 }
413
414
415
416
417
418 public void close( Exception reason )
419 {
420 if ( IS_DEBUG )
421 {
422 LOG_CURSOR.debug( "Closing CursorList {}", this );
423 }
424
425 closed = true;
426
427 for ( EntryFilteringCursor cursor : list )
428 {
429 try
430 {
431 if ( reason != null )
432 {
433 cursor.close( reason );
434 }
435 else
436 {
437 cursor.close();
438 }
439 }
440 catch ( Exception e )
441 {
442 LOG.warn( "Failed to close the cursor" );
443 }
444 }
445 }
446
447
448
449
450
451 public boolean isClosed()
452 {
453 return closed;
454 }
455
456
457 public Iterator<Entry> iterator()
458 {
459 throw new UnsupportedOperationException();
460 }
461
462
463
464
465
466 public void setClosureMonitor( ClosureMonitor monitor )
467 {
468 for ( EntryFilteringCursor c : list )
469 {
470 c.setClosureMonitor( monitor );
471 }
472 }
473 }