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.api.filtering;
21
22
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
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.ClosureMonitor;
31 import org.apache.directory.api.ldap.model.cursor.Cursor;
32 import org.apache.directory.api.ldap.model.cursor.CursorException;
33 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
34 import org.apache.directory.api.ldap.model.entry.Entry;
35 import org.apache.directory.api.ldap.model.exception.LdapException;
36 import org.apache.directory.api.ldap.model.exception.OperationAbandonedException;
37 import org.apache.directory.api.ldap.model.schema.SchemaManager;
38 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
39 import org.apache.directory.server.core.api.entry.ServerEntryUtils;
40 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45
46
47
48
49
50
51
52
53 public class EntryFilteringCursorImpl extends AbstractCursor<Entry> implements EntryFilteringCursor
54 {
55
56 private static final Logger LOG = LoggerFactory.getLogger( EntryFilteringCursorImpl.class );
57
58
59 private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
60
61
62 private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
63
64
65 private final Cursor<Entry> wrapped;
66
67
68 private final SearchOperationContext operationContext;
69
70
71 private final SchemaManager schemaManager;
72
73
74 private final List<EntryFilter> filters;
75
76
77 private Entry prefetched;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 public EntryFilteringCursorImpl( Cursor<Entry> wrapped,
94 SearchOperationContext operationContext, SchemaManager schemaManager, EntryFilter filter )
95 {
96 this( wrapped, operationContext, schemaManager, Collections.singletonList( filter ) );
97 }
98
99
100
101
102
103
104
105
106
107
108 public EntryFilteringCursorImpl( Cursor<Entry> wrapped, SearchOperationContext operationContext,
109 SchemaManager schemaManager )
110 {
111 if ( IS_DEBUG )
112 {
113 LOG_CURSOR.debug( "Creating BaseEntryFilteringCursor {}", this );
114 }
115
116 this.wrapped = wrapped;
117 this.operationContext = operationContext;
118 this.filters = new ArrayList<>();
119 this.schemaManager = schemaManager;
120 }
121
122
123
124
125
126
127
128
129
130
131
132 public EntryFilteringCursorImpl( Cursor<Entry> wrapped,
133 SearchOperationContext operationContext,
134 SchemaManager schemaManager,
135 List<EntryFilter> filters )
136 {
137 if ( IS_DEBUG )
138 {
139 LOG_CURSOR.debug( "Creating BaseEntryFilteringCursor {}", this );
140 }
141
142 this.wrapped = wrapped;
143 this.operationContext = operationContext;
144 this.filters = new ArrayList<>();
145 this.filters.addAll( filters );
146 this.schemaManager = schemaManager;
147 }
148
149
150
151
152
153
154
155
156
157 public boolean isAbandoned()
158 {
159 return operationContext.isAbandoned();
160 }
161
162
163
164
165
166 public void setAbandoned( boolean abandoned )
167 {
168 operationContext.setAbandoned( abandoned );
169
170 if ( abandoned )
171 {
172 LOG.info( "Cursor has been abandoned." );
173 }
174 }
175
176
177
178
179
180 public boolean addEntryFilter( EntryFilter filter )
181 {
182 return filters.add( filter );
183 }
184
185
186
187
188
189 public boolean removeEntryFilter( EntryFilter filter )
190 {
191 return filters.remove( filter );
192 }
193
194
195
196
197
198 public List<EntryFilter> getEntryFilters()
199 {
200 return Collections.unmodifiableList( filters );
201 }
202
203
204
205
206
207 public SearchOperationContext getOperationContext()
208 {
209 return operationContext;
210 }
211
212
213
214
215
216
217
218
219 public void after( Entry element ) throws LdapException, CursorException
220 {
221 throw new UnsupportedOperationException();
222 }
223
224
225
226
227
228 public void afterLast() throws LdapException, CursorException
229 {
230 wrapped.afterLast();
231 prefetched = null;
232 }
233
234
235
236
237
238 public boolean available()
239 {
240 return prefetched != null;
241 }
242
243
244
245
246
247 public void before( Entry element ) throws LdapException, CursorException
248 {
249 throw new UnsupportedOperationException();
250 }
251
252
253
254
255
256 public void beforeFirst() throws LdapException, CursorException
257 {
258 wrapped.beforeFirst();
259 prefetched = null;
260 }
261
262
263
264
265
266 public void close() throws IOException
267 {
268 if ( IS_DEBUG )
269 {
270 LOG_CURSOR.debug( "Closing BaseEntryFilteringCursor {}", this );
271 }
272
273 wrapped.close();
274 prefetched = null;
275 }
276
277
278
279
280
281 public void close( Exception reason ) throws IOException
282 {
283 if ( IS_DEBUG )
284 {
285 LOG_CURSOR.debug( "Closing BaseEntryFilteringCursor {}", this );
286 }
287
288 wrapped.close( reason );
289 prefetched = null;
290 }
291
292
293
294
295
296 public final void setClosureMonitor( ClosureMonitor monitor )
297 {
298 wrapped.setClosureMonitor( monitor );
299 }
300
301
302
303
304
305 public boolean first() throws LdapException, CursorException
306 {
307 if ( operationContext.isAbandoned() )
308 {
309 LOG.info( "Cursor has been abandoned." );
310
311 try
312 {
313 close();
314 }
315 catch ( IOException ioe )
316 {
317 throw new LdapException( ioe.getMessage(), ioe );
318 }
319
320 throw new OperationAbandonedException();
321 }
322
323 beforeFirst();
324
325 return next();
326 }
327
328
329
330
331
332 public Entry get() throws InvalidCursorPositionException
333 {
334 if ( available() )
335 {
336 return prefetched;
337 }
338
339 throw new InvalidCursorPositionException();
340 }
341
342
343
344
345
346 public boolean isClosed()
347 {
348 return wrapped.isClosed();
349 }
350
351
352
353
354
355 public boolean last() throws LdapException, CursorException
356 {
357 if ( operationContext.isAbandoned() )
358 {
359 LOG.info( "Cursor has been abandoned." );
360
361 try
362 {
363 close();
364 }
365 catch ( IOException ioe )
366 {
367 throw new LdapException( ioe.getMessage(), ioe );
368 }
369
370 throw new OperationAbandonedException();
371 }
372
373 afterLast();
374
375 return previous();
376 }
377
378
379
380
381
382 public boolean next() throws LdapException, CursorException
383 {
384 if ( operationContext.isAbandoned() )
385 {
386 LOG.info( "Cursor has been abandoned." );
387
388 try
389 {
390 close();
391 }
392 catch ( IOException ioe )
393 {
394 throw new LdapException( ioe.getMessage(), ioe );
395 }
396
397 throw new OperationAbandonedException();
398 }
399
400 Entry tempResult = null;
401
402 outer: while ( wrapped.next() )
403 {
404 Entry tempEntry = wrapped.get();
405
406 if ( tempEntry == null )
407 {
408
409 continue;
410 }
411
412 if ( tempEntry instanceof ClonedServerEntry )
413 {
414 tempResult = tempEntry;
415 }
416 else
417 {
418 tempResult = new ClonedServerEntry( tempEntry );
419 }
420
421
422
423
424
425
426
427
428
429 if ( filters.isEmpty() )
430 {
431 prefetched = tempResult;
432 ServerEntryUtils.filterContents(
433 schemaManager,
434 operationContext, prefetched );
435
436 return true;
437 }
438
439 if ( ( filters.size() == 1 ) && filters.get( 0 ).accept( operationContext, tempResult ) )
440 {
441 prefetched = tempResult;
442 ServerEntryUtils.filterContents(
443 schemaManager,
444 operationContext, prefetched );
445
446 return true;
447 }
448
449
450 for ( EntryFilter filter : filters )
451 {
452
453 if ( !filter.accept( operationContext, tempResult ) )
454 {
455 continue outer;
456 }
457 }
458
459
460
461
462 prefetched = tempResult;
463
464 return true;
465 }
466
467 prefetched = null;
468
469 return false;
470 }
471
472
473
474
475
476 public boolean previous() throws LdapException, CursorException
477 {
478 if ( operationContext.isAbandoned() )
479 {
480 LOG.info( "Cursor has been abandoned." );
481
482 try
483 {
484 close();
485 }
486 catch ( IOException ioe )
487 {
488 throw new LdapException( ioe.getMessage(), ioe );
489 }
490
491 throw new OperationAbandonedException();
492 }
493
494 Entry tempResult = null;
495
496 outer: while ( wrapped.previous() )
497 {
498 Entry entry = wrapped.get();
499
500 if ( entry == null )
501 {
502 continue;
503 }
504
505 tempResult = new ClonedServerEntry( entry );
506
507
508
509
510
511
512
513
514
515 if ( filters.isEmpty() )
516 {
517 prefetched = tempResult;
518 ServerEntryUtils.filterContents(
519 schemaManager,
520 operationContext, prefetched );
521
522 return true;
523 }
524
525 if ( ( filters.size() == 1 ) && filters.get( 0 ).accept( operationContext, tempResult ) )
526 {
527 prefetched = tempResult;
528 ServerEntryUtils.filterContents(
529 schemaManager,
530 operationContext, prefetched );
531
532 return true;
533 }
534
535
536
537 for ( EntryFilter filter : filters )
538 {
539
540 if ( !filter.accept( operationContext, tempResult ) )
541 {
542 continue outer;
543 }
544 }
545
546
547
548
549 prefetched = tempResult;
550 ServerEntryUtils.filterContents(
551 schemaManager,
552 operationContext, prefetched );
553
554 return true;
555 }
556
557 prefetched = null;
558
559 return false;
560 }
561
562
563
564
565
566 public String toString( String tabs )
567 {
568 StringBuilder sb = new StringBuilder();
569
570 if ( wrapped != null )
571 {
572 sb.append( tabs ).append( "BaseEntryFilteringCursor, wrapped : \n" );
573 sb.append( wrapped.toString( tabs + " " ) );
574 }
575 else
576 {
577 sb.append( tabs ).append( "BaseEntryFilteringCursor, no wrapped\n" );
578 }
579
580 if ( ( filters != null ) && !filters.isEmpty() )
581 {
582 sb.append( tabs ).append( "Filters : \n" );
583
584 for ( EntryFilter filter : filters )
585 {
586 sb.append( filter.toString( tabs + " " ) ).append( "\n" );
587 }
588 }
589 else
590 {
591 sb.append( tabs ).append( "No filter\n" );
592 }
593
594 if ( prefetched != null )
595 {
596 sb.append( tabs ).append( "Prefetched : \n" );
597 sb.append( prefetched.toString( tabs + " " ) );
598 }
599 else
600 {
601 sb.append( tabs ).append( "No prefetched" );
602 }
603
604 return sb.toString();
605 }
606
607
608
609
610
611 public String toString()
612 {
613 return toString( "" );
614 }
615 }